diff --git a/src/account.cpp b/src/account.cpp index cd378463e5feca78ed633fcda20f338645c39f5f..3fb100001f2e29dac8f983e2293e268ea79a2840 100644 --- a/src/account.cpp +++ b/src/account.cpp @@ -80,7 +80,7 @@ const char * const Account::ACCOUNT_ENABLE_KEY = "enable"; const char * const Account::ACCOUNT_AUTOANSWER_KEY = "autoAnswer"; const char * const Account::ACCOUNT_ACTIVE_CALL_LIMIT_KEY = "activeCallLimit"; const char * const Account::MAILBOX_KEY = "mailbox"; -const char * const Account::DEFAULT_USER_AGENT = PACKAGE_NAME "/" PACKAGE_VERSION; +const char * const Account::DEFAULT_USER_AGENT = PACKAGE_NAME; const char * const Account::USER_AGENT_KEY = "useragent"; const char * const Account::HAS_CUSTOM_USER_AGENT_KEY = "hasCustomUserAgent"; const char * const Account::PRESENCE_MODULE_ENABLED_KEY = "presenceModuleEnabled"; diff --git a/src/sip/sipaccount.cpp b/src/sip/sipaccount.cpp index 614d062caaa4b413ef372695553e492c96febb49..92f90dde60b366ddf8dd6fe940fc7e09db4ca831 100644 --- a/src/sip/sipaccount.cpp +++ b/src/sip/sipaccount.cpp @@ -72,6 +72,8 @@ #include <sstream> #include <cstdlib> #include <thread> +#include <chrono> +#include <ctime> #ifdef _WIN32 #include <lmcons.h> @@ -93,6 +95,14 @@ static const char *const VALID_TLS_PROTOS[] = {"Default", "TLSv1.2", "TLSv1.1", constexpr const char * const SIPAccount::ACCOUNT_TYPE; +struct ctx { + ctx(pjsip_auth_clt_sess* auth) : auth_sess(auth, &pjsip_auth_clt_deinit) {} + std::weak_ptr<SIPAccount> acc; + std::string to; + uint64_t id; + std::unique_ptr<pjsip_auth_clt_sess, decltype(&pjsip_auth_clt_deinit)> auth_sess; +}; + static void registration_cb(pjsip_regc_cbparam *param) { @@ -2069,39 +2079,126 @@ SIPAccount::sendTextMessage(const std::string& to, const std::map<std::string, s return; } - const pjsip_tpselector tp_sel = getTransportSelector(); - pjsip_tx_data_set_transport(tdata, &tp_sel); + /* Add Date Header. */ + pj_str_t date_str; + constexpr auto key = CONST_PJ_STR("Date"); + pjsip_hdr *hdr; + auto time = std::time(nullptr); + auto date = std::ctime(&time); + // the erase-remove idiom for a cstring, removes _all_ new lines with in date + *std::remove(date, date+strlen(date), '\n') = '\0'; - im::fillPJSIPMessageBody(*tdata, payloads); + // Add Header + hdr = reinterpret_cast<pjsip_hdr*>(pjsip_date_hdr_create(tdata->pool, &key, pj_cstr(&date_str, date))); + pjsip_msg_add_hdr(tdata->msg, hdr); - struct ctx { - std::weak_ptr<SIPAccount> acc; - std::string to; - uint64_t id; - }; - ctx* t = new ctx; + /* Add user agent header. */ + pjsip_hdr *hdr_list; + auto pJuseragent = CONST_PJ_STR(getUserAgentName()); + constexpr pj_str_t STR_USER_AGENT = CONST_PJ_STR("User-Agent"); + + // Add Header + hdr_list = reinterpret_cast<pjsip_hdr*>(pjsip_user_agent_hdr_create(tdata->pool, &STR_USER_AGENT, &pJuseragent)); + pjsip_msg_add_hdr(tdata->msg, hdr_list); + + // Set input token into callback + std::unique_ptr<ctx> t{ new ctx(new pjsip_auth_clt_sess) }; t->acc = shared(); t->to = to; t->id = id; - status = pjsip_endpt_send_request(link_->getEndpoint(), tdata, -1, t, [](void *token, pjsip_event *e) { - auto c = (ctx*) token; - try { - if (auto acc = c->acc.lock()) { - acc->messageEngine_.onMessageSent(c->to, c->id, e - && e->body.tsx_state.tsx - && e->body.tsx_state.tsx->status_code == PJSIP_SC_OK); - } - } catch (const std::exception& e) { - JAMI_ERR("Error calling message callback: %s", e.what()); - } - delete c; - }); + /* Initialize Auth header. */ + auto cred = getCredInfo(); + const_cast<pjsip_cred_info*>(cred)->realm = CONST_PJ_STR(hostname_); + status = pjsip_auth_clt_init(t->auth_sess.get(), link_->getEndpoint(), tdata->pool, 0); + + if (status != PJ_SUCCESS) { + JAMI_ERR("Unable to initialize auth session: %s", sip_utils::sip_strerror(status).c_str()); + messageEngine_.onMessageSent(to, id, false); + return; + } + + status = pjsip_auth_clt_set_credentials(t->auth_sess.get(), getCredentialCount(), cred); + + if (status != PJ_SUCCESS) { + JAMI_ERR("Unable to set auth session data: %s", sip_utils::sip_strerror(status).c_str()); + messageEngine_.onMessageSent(to, id, false); + return; + } + + const pjsip_tpselector tp_sel = getTransportSelector(); + status = pjsip_tx_data_set_transport(tdata, &tp_sel); + + if (status != PJ_SUCCESS) { + JAMI_ERR("Unable to set transport: %s", sip_utils::sip_strerror(status).c_str()); + messageEngine_.onMessageSent(to, id, false); + return; + } + + im::fillPJSIPMessageBody(*tdata, payloads); + + // Send message request with callback onComplete + auto token = t.release(); + status = pjsip_endpt_send_request(link_->getEndpoint(), tdata, -1, token, &onComplete); if (status != PJ_SUCCESS) { JAMI_ERR("Unable to send request: %s", sip_utils::sip_strerror(status).c_str()); + messageEngine_.onMessageSent(to, id, false); + delete token; + return; + } +} + +void +SIPAccount::onComplete(void *token, pjsip_event *event) +{ + std::unique_ptr<ctx> c{ (ctx*)token }; + int code; + pj_status_t status; + pj_assert(event->type == PJSIP_EVENT_TSX_STATE); + code = event->body.tsx_state.tsx->status_code; + + auto acc = c->acc.lock(); + if (not acc) return; + + //Check if Authorization Header if needed (request rejected by server) + if (code == PJSIP_SC_UNAUTHORIZED || code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) { + + JAMI_INFO("Authorization needed for SMS message - Resending"); + pjsip_tx_data *new_request; + + // Add Authorization Header into msg + status = pjsip_auth_clt_reinit_req( c->auth_sess.get(), event->body.tsx_state.src.rdata, event->body.tsx_state.tsx->last_tx, &new_request); + + if (status == PJ_SUCCESS) { + + // Increment Cseq number by one manually + pjsip_cseq_hdr *cseq_hdr; + cseq_hdr = (pjsip_cseq_hdr*)pjsip_msg_find_hdr(new_request->msg, PJSIP_H_CSEQ, NULL); + cseq_hdr->cseq += 1; + + // Resend request + auto data = c.release(); + status = pjsip_endpt_send_request(acc->link_->getEndpoint(), new_request, -1, data, &onComplete); + + if (status != PJ_SUCCESS) { + JAMI_ERR("Unable to send request: %s", sip_utils::sip_strerror(status).c_str()); + acc->messageEngine_.onMessageSent(c->to, c->id, false); + delete data; + } + return; + } + else { + JAMI_ERR("Unable to add Authorization Header into msg"); + acc->messageEngine_.onMessageSent(c->to, c->id, false); + return; + } } + acc->messageEngine_.onMessageSent(c->to, c->id, event + && event->body.tsx_state.tsx + && (event->body.tsx_state.tsx->status_code == PJSIP_SC_OK + || event->body.tsx_state.tsx->status_code == PJSIP_SC_ACCEPTED)); } std::string diff --git a/src/sip/sipaccount.h b/src/sip/sipaccount.h index 82e89670233b220b6635e6307ee19fa0fdc656d6..d798599e8ffb8e45e3d0ce6b3a3d9c5086898fb5 100644 --- a/src/sip/sipaccount.h +++ b/src/sip/sipaccount.h @@ -685,6 +685,11 @@ class SIPAccount : public SIPAccountBase { */ pj_uint16_t tlsListenerPort_ {sip_utils::DEFAULT_SIP_TLS_PORT}; + /** + * Send Request Callback + */ + static void onComplete(void *token, pjsip_event *event); + bool tlsEnable_ {false}; std::string tlsMethod_; std::string tlsCiphers_;