diff --git a/src/dring/account_const.h b/src/dring/account_const.h index a2c6ca215fda6976082bb03a198d2701986c8a5c..ab2aded9d2f1c9546b8025f86111176fcf9aac82 100644 --- a/src/dring/account_const.h +++ b/src/dring/account_const.h @@ -86,6 +86,12 @@ constexpr static const char STATE_DESC [] = "Transport.statusDesc } //namespace DRing::VolatileProperties::Transport +namespace InstantMessaging { + +constexpr static const char OFF_CALL [] = "IM.offCall"; + +} + } //namespace DRing::Account::VolatileProperties namespace ConfProperties { diff --git a/src/sip/sipaccount.cpp b/src/sip/sipaccount.cpp index 7f519de04aee60f7f8d0840119542726d91030f4..cb7a2b175691c5b6c025adae9f628aa112e219e6 100644 --- a/src/sip/sipaccount.cpp +++ b/src/sip/sipaccount.cpp @@ -667,6 +667,7 @@ SIPAccount::getVolatileAccountDetails() const auto a = SIPAccountBase::getVolatileAccountDetails(); a.emplace(Conf::CONFIG_ACCOUNT_REGISTRATION_STATE_CODE, ring::to_string(registrationStateDetailed_.first)); a.emplace(Conf::CONFIG_ACCOUNT_REGISTRATION_STATE_DESC, registrationStateDetailed_.second); + a.emplace(DRing::Account::VolatileProperties::InstantMessaging::OFF_CALL, TRUE_STR); if (presence_) { a.emplace(Conf::CONFIG_PRESENCE_STATUS, presence_->isOnline() ? TRUE_STR : FALSE_STR); @@ -2113,4 +2114,79 @@ void SIPAccount::updateDialogViaSentBy(pjsip_dialog *dlg) pjsip_dlg_set_via_sent_by(dlg, &via_addr_, via_tp_); } +/** + * Create Accept header for MESSAGE. + */ +static pjsip_accept_hdr* im_create_accept(pj_pool_t *pool) +{ + /* Create Accept header. */ + pjsip_accept_hdr *accept; + + accept = pjsip_accept_hdr_create(pool); + accept->values[0] = CONST_PJ_STR("text/plain"); + accept->values[1] = CONST_PJ_STR("application/im-iscomposing+xml"); + accept->count = 2; + + return accept; +} + +void +SIPAccount::sendTextMessage(const std::string& to, const std::string& msg) +{ + if (to.empty() or msg.empty()) + return; + + std::string toUri; + if (to.find("sip:") != std::string::npos or + to.find("sips:") != std::string::npos) + toUri = to; + else + toUri = getToUri(to); + + const pjsip_method msg_method = { PJSIP_OTHER_METHOD, CONST_PJ_STR("MESSAGE") }; + std::string from(getFromUri()); + pj_str_t pjFrom = pj_str((char*) from.c_str()); + pj_str_t pjTo = pj_str((char*) toUri.c_str()); + + /* Create request. */ + pjsip_tx_data *tdata; + pj_status_t status = pjsip_endpt_create_request(link_->getEndpoint(), &msg_method, + &pjTo, &pjFrom, &pjTo, NULL, NULL, -1, NULL, &tdata); + if (status != PJ_SUCCESS) { + char err_msg[128]; + err_msg[0] = '\0'; + pj_str_t descr = pj_strerror(status, err_msg, sizeof(err_msg)); + RING_ERR("Unable to create request: %.*s", descr.slen, descr.ptr); + return; + } + + const pjsip_tpselector tp_sel = getTransportSelector(); + pjsip_tx_data_set_transport(tdata, &tp_sel); + + /* Add accept header. */ + pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)im_create_accept(tdata->pool)); + + /* Set default media type if none is specified */ + static const constexpr pj_str_t type = CONST_PJ_STR("text"); + static const constexpr pj_str_t subtype = CONST_PJ_STR("plain"); + + pj_str_t message = pj_str((char*) msg.c_str()); + + tdata->msg->body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &message); + if (tdata->msg->body == NULL) { + RING_ERR("Unable to create msg body"); + pjsip_tx_data_dec_ref(tdata); + return; + } + + status = pjsip_endpt_send_request(link_->getEndpoint(), tdata, -1, nullptr, nullptr); + if (status != PJ_SUCCESS) { + char err_msg[128]; + err_msg[0] = '\0'; + pj_str_t descr = pj_strerror(status, err_msg, sizeof(err_msg)); + RING_ERR("Unable to send request: %.*s", descr.slen, descr.ptr); + return; + } +} + } // namespace ring diff --git a/src/sip/sipaccount.h b/src/sip/sipaccount.h index f01fe69dd3cac61e5e2e3c6bcb7da78e36ac4cf3..38009b8a38b6c059ed22e5a1da859359ed82a9c1 100644 --- a/src/sip/sipaccount.h +++ b/src/sip/sipaccount.h @@ -513,6 +513,8 @@ class SIPAccount : public SIPAccountBase { void onRegister(pjsip_regc_cbparam *param); + virtual void sendTextMessage(const std::string& /* to */, const std::string& /* message */); + private: void doRegister1_(); void doRegister2_(); diff --git a/src/sip/sipaccountbase.cpp b/src/sip/sipaccountbase.cpp index 5a4d1fe97af612499168c94bbd18a311cc6fe281..09c122d102d12a75ac9af870d53d3cba9e4e2aa4 100644 --- a/src/sip/sipaccountbase.cpp +++ b/src/sip/sipaccountbase.cpp @@ -328,4 +328,11 @@ SIPAccountBase::getIceOptions() const noexcept return opts; } +void +SIPAccountBase::onTextMessage(const std::string& from, const std::string& msg) +{ + RING_WARN("Text message received ! %s -> %s", from.c_str(), msg.c_str()); + emitSignal<DRing::ConfigurationSignal::IncomingAccountMessage>(accountID_, from, msg); +} + } // namespace ring diff --git a/src/sip/sipaccountbase.h b/src/sip/sipaccountbase.h index 7d9f9f80a25b023e1fbbc0338c9c92cc147a26fa..6728a3c9c1faa581b6cfb377b0a81cf9c7cfc51c 100644 --- a/src/sip/sipaccountbase.h +++ b/src/sip/sipaccountbase.h @@ -244,6 +244,8 @@ public: const IceTransportOptions getIceOptions() const noexcept override; + void onTextMessage(const std::string& from, const std::string& msg); + protected: virtual void serialize(YAML::Emitter &out); virtual void serializeTls(YAML::Emitter &out); diff --git a/src/sip/sipvoiplink.cpp b/src/sip/sipvoiplink.cpp index b409ecdeea76cd18ee8d0a0e3f0f12f2819ad0f8..57070c5b6a58eef2b2aacf83629812b15b29aa46 100644 --- a/src/sip/sipvoiplink.cpp +++ b/src/sip/sipvoiplink.cpp @@ -63,8 +63,6 @@ #include "client/videomanager.h" #endif -#include "client/ring_signal.h" - #include "pres_sub_server.h" #include "array_size.h" @@ -223,6 +221,10 @@ transaction_request_cb(pjsip_rx_data *rdata) std::string viaHostname(sip_via.host.ptr, sip_via.host.slen); const std::string remote_user(sip_from_uri->user.ptr, sip_from_uri->user.slen); const std::string remote_hostname(sip_from_uri->host.ptr, sip_from_uri->host.slen); + char tmp[PJSIP_MAX_URL_SIZE]; + size_t length = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, sip_from_uri, tmp, PJSIP_MAX_URL_SIZE); + std::string peerNumber(tmp, length); + sip_utils::stripSipUriPrefix(peerNumber); auto link = getSIPVoIPLink(); if (not link) { @@ -252,6 +254,13 @@ transaction_request_cb(pjsip_rx_data *rdata) if (ret == 1 and voicemail != 0) Manager::instance().startVoiceMessageNotification(account_id, voicemail); } + } else if (request.find("MESSAGE") != std::string::npos) { + if (body) { + pjsip_endpt_respond( endpt_, NULL, rdata, PJSIP_SC_OK, NULL, NULL, NULL, NULL); + std::string text {(char*)body->data, (char*)body->data+body->len}; + account->onTextMessage(peerNumber, text); + return PJ_FALSE; + } } try_respond_stateless(endpt_, rdata, PJSIP_SC_OK, NULL, NULL, NULL); @@ -291,10 +300,6 @@ transaction_request_cb(pjsip_rx_data *rdata) return PJ_FALSE; } - char tmp[PJSIP_MAX_URL_SIZE]; - size_t length = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, sip_from_uri, tmp, PJSIP_MAX_URL_SIZE); - std::string peerNumber(tmp, length); - sip_utils::stripSipUriPrefix(peerNumber); if (not remote_user.empty() and not remote_hostname.empty()) peerNumber = remote_user + "@" + remote_hostname; @@ -581,6 +586,9 @@ SIPVoIPLink::SIPVoIPLink() static const pj_str_t accepted = CONST_PJ_STR("application/sdp"); pjsip_endpt_add_capability(endpt_, &mod_ua_, PJSIP_H_ACCEPT, nullptr, 1, &accepted); + static const pj_str_t iscomposing = CONST_PJ_STR("application/im-iscomposing+xml"); + pjsip_endpt_add_capability(endpt_, &mod_ua_, PJSIP_H_ACCEPT, nullptr, 1, &iscomposing); + TRY(pjsip_replaces_init_module(endpt_)); #undef TRY