diff --git a/coreapi/sal/call_op.cpp b/coreapi/sal/call_op.cpp index 6c3b50ba6..c55139d5a 100644 --- a/coreapi/sal/call_op.cpp +++ b/coreapi/sal/call_op.cpp @@ -21,7 +21,7 @@ int SalCallOp::set_local_media_description(SalMediaDescription *desc) { vector buffer = marshal_media_description(sdp, error); if (error != BELLE_SIP_OK) return -1; - this->local_body.setContentType("application/sdp"); + this->local_body.setContentType(ContentType::Sdp); this->local_body.setBody(move(buffer)); if (this->local_media) sal_media_description_unref(this->local_media); @@ -47,7 +47,7 @@ int SalCallOp::set_local_body(const Content &body) { int SalCallOp::set_local_body(const Content &&body) { if (!body.isValid()) return -1; - if (body.getContentType() == "application/sdp") { + if (body.getContentType() == ContentType::Sdp) { SalMediaDescription *desc = NULL; if (body.getSize() > 0) { belle_sdp_session_description_t *sdp = belle_sdp_session_description_parse(body.getBodyAsString().c_str()); @@ -139,7 +139,7 @@ int SalCallOp::set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* if (error != BELLE_SIP_OK) return -1; Content body; - body.setContentType("application/sdp"); + body.setContentType(ContentType::Sdp); body.setBody(move(buff)); set_custom_body(msg, body); @@ -161,7 +161,7 @@ void SalCallOp::fill_invite(belle_sip_request_t* invite) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Session-expires", "600;refresher=uas")); belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Supported", "timer")); } - this->sdp_offering = (this->local_body.getContentType() == "application/sdp"); + this->sdp_offering = (this->local_body.getContentType() == ContentType::Sdp); set_custom_body(BELLE_SIP_MESSAGE(invite), this->local_body); } @@ -204,6 +204,7 @@ void SalCallOp::cancelling_invite(const SalErrorInfo *info) { Content SalCallOp::extract_body(belle_sip_message_t *message) { Content body; belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(message, belle_sip_header_content_type_t); + belle_sip_header_content_disposition_t *contentDisposition = belle_sip_message_get_header_by_type(message, belle_sip_header_content_disposition_t); belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(message, belle_sip_header_content_length_t); const char *type_str = content_type ? belle_sip_header_content_type_get_type(content_type) : NULL; const char *subtype_str = content_type ? belle_sip_header_content_type_get_subtype(content_type) : NULL; @@ -211,6 +212,8 @@ Content SalCallOp::extract_body(belle_sip_message_t *message) { const char *body_str = belle_sip_message_get_body(message); if (type_str && subtype_str) body.setContentType(ContentType(type_str, subtype_str)); + if (contentDisposition) + body.setContentDisposition(belle_sip_header_content_disposition_get_content_disposition(contentDisposition)); if (length > 0 && body_str) body.setBody(body_str, length); return body; } @@ -311,7 +314,7 @@ void SalCallOp::handle_body_from_response(belle_sip_response_t* response) { sal_media_description_unref(this->remote_media); this->remote_media=NULL; } - if (body.getContentType() == "application/sdp") { + if (body.getContentType() == ContentType::Sdp) { if (parse_sdp_body(body, &sdp, &reason) == 0) { if (sdp) { this->remote_media = sal_media_description_new(); @@ -543,7 +546,7 @@ SalReason SalCallOp::process_body_for_invite(belle_sip_request_t* invite) { Content body = extract_body(BELLE_SIP_MESSAGE(invite)); if (!body.isValid()) return SalReasonUnsupportedContent; - if (body.getContentType() == "application/sdp") { + if (body.getContentType() == ContentType::Sdp) { belle_sdp_session_description_t* sdp; if (parse_sdp_body(body, &sdp, &reason) == 0) { if (sdp) { @@ -574,7 +577,7 @@ SalReason SalCallOp::process_body_for_ack(belle_sip_request_t *ack) { SalReason reason = SalReasonNone; Content body = extract_body(BELLE_SIP_MESSAGE(ack)); if (!body.isValid()) return SalReasonUnsupportedContent; - if (body.getContentType() == "application/sdp") { + if (body.getContentType() == ContentType::Sdp) { belle_sdp_session_description_t *sdp; if (parse_sdp_body(body, &sdp, &reason) == 0) { if (sdp) { diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index d8393484a..92d6cec9a 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -318,11 +318,11 @@ void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChat // ============================================================================= const char * linphone_chat_message_get_content_type(LinphoneChatMessage *msg) { - return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getContentType()); + return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getContentType().asString()); } void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type) { - L_GET_PRIVATE_FROM_C_OBJECT(msg)->setContentType(L_C_TO_STRING(content_type)); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setContentType(ContentType(L_C_TO_STRING(content_type))); } const char *linphone_chat_message_get_text(LinphoneChatMessage *msg) { @@ -362,11 +362,11 @@ LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage *msg) { } bool_t linphone_chat_message_is_file_transfer(LinphoneChatMessage *msg) { - return LinphonePrivate::ContentType::isFileTransfer(linphone_chat_message_get_content_type(msg)); + return LinphonePrivate::ContentType(linphone_chat_message_get_content_type(msg)) == LinphonePrivate::ContentType::FileTransfer; } bool_t linphone_chat_message_is_text(LinphoneChatMessage *msg) { - return LinphonePrivate::ContentType::isText(linphone_chat_message_get_content_type(msg)); + return LinphonePrivate::ContentType(linphone_chat_message_get_content_type(msg)) == LinphonePrivate::ContentType::PlainText; } const char *linphone_chat_message_state_to_string(const LinphoneChatMessageState state) { diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index f931f421a..bd5b5cbe7 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -68,13 +68,13 @@ public: // Methods only used for C wrapper // ----------------------------------------------------------------------------- - const std::string& getContentType(); - void setContentType(const std::string& contentType); + const ContentType &getContentType(); + void setContentType(const ContentType &contentType); - const std::string& getText(); - void setText(const std::string& text); + const std::string &getText(); + void setText(const std::string &text); - LinphoneContent * getFileTransferInformation() const; + LinphoneContent *getFileTransferInformation() const; void setFileTransferInformation(LinphoneContent *content); // ----------------------------------------------------------------------------- @@ -128,7 +128,7 @@ private: SalCustomHeader *salCustomHeaders = NULL; unsigned long backgroundTaskId; // Cache for returned values, used for compatibility with previous C API - std::string cContentType = ""; + ContentType cContentType; std::string cText = ""; // Used for compatibility with previous C API LinphoneContent *cFileTransferInformation = NULL; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 822493530..dc543a760 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -139,19 +139,19 @@ string ChatMessagePrivate::getSalCustomHeaderValue(const string& name) { // ----------------------------------------------------------------------------- -const string& ChatMessagePrivate::getContentType() { - if (!internalContent.getContentType().asString().empty()) { - cContentType = internalContent.getContentType().asString(); +const ContentType& ChatMessagePrivate::getContentType() { + if (internalContent.getContentType().isValid()) { + cContentType = internalContent.getContentType(); } else { if (contents.size() > 0) { Content content = contents.front(); - cContentType = content.getContentType().asString(); + cContentType = content.getContentType(); } } return cContentType; } -void ChatMessagePrivate::setContentType(const string& contentType) { +void ChatMessagePrivate::setContentType(const ContentType &contentType) { internalContent.setContentType(contentType); } @@ -681,7 +681,7 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e } else { // no encryption key, transfer in plain, just copy the msg sent by server setText(body); } - setContentType("application/vnd.gsma.rcs-ft-http+xml"); + setContentType(ContentType::FileTransfer); q->updateState(ChatMessage::State::FileTransferDone); releaseHttpRequest(); send(); @@ -977,7 +977,7 @@ LinphoneReason ChatMessagePrivate::receive() { // Start of message modification // --------------------------------------- - if (ContentType::isCpim(getContentType())) { + if (getContentType() == ContentType::Cpim) { CpimChatMessageModifier ccmm; ccmm.decode(this); } @@ -1000,9 +1000,9 @@ LinphoneReason ChatMessagePrivate::receive() { // End of message modification // --------------------------------------- - if ((retval <= 0) && (linphone_core_is_content_type_supported(chatRoom->getCore(), getContentType().c_str()) == FALSE)) { + if ((retval <= 0) && (linphone_core_is_content_type_supported(chatRoom->getCore(), getContentType().asString().c_str()) == FALSE)) { retval = 415; - lError() << "Unsupported MESSAGE (content-type " << getContentType() << " not recognized)"; + lError() << "Unsupported MESSAGE (content-type " << getContentType().asString() << " not recognized)"; } if (retval > 0) { @@ -1011,10 +1011,10 @@ LinphoneReason ChatMessagePrivate::receive() { return reason; } - if (ContentType::isFileTransfer(getContentType())) { + if (getContentType() == ContentType::FileTransfer) { createFileTransferInformationsFromVndGsmaRcsFtHttpXml(); store = true; - } else if (ContentType::isText(getContentType())) { + } else if (getContentType() == ContentType::PlainText) { store = true; } @@ -1071,12 +1071,12 @@ void ChatMessagePrivate::send() { // --------------------------------------- string clearTextMessage; - string clearTextContentType; + ContentType clearTextContentType; if (!getText().empty()) { clearTextMessage = getText().c_str(); } - if (!getContentType().empty()) { + if (getContentType().isValid()) { clearTextContentType = getContentType(); } @@ -1110,8 +1110,8 @@ void ChatMessagePrivate::send() { ms_free(content_type); } else { auto msgOp = dynamic_cast(op); - if (!getContentType().empty()) { - msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), getContentType().c_str(), getText().c_str(), chatRoom->getPeerAddress().asStringUriOnly().c_str()); + if (getContentType().isValid()) { + msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), getContentType().asString().c_str(), getText().c_str(), chatRoom->getPeerAddress().asStringUriOnly().c_str()); } else { msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), getText().c_str()); } @@ -1121,7 +1121,7 @@ void ChatMessagePrivate::send() { /* We replace the encrypted message by the original one so it can be correctly stored and displayed by the application */ setText(clearTextMessage); } - if (!getContentType().empty() && getContentType() == clearTextContentType) { + if (getContentType().isValid() && (getContentType() == clearTextContentType)) { /* We replace the encrypted content type by the original one */ setContentType(clearTextContentType); } diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 5e3e12100..4c47f02a4 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -137,7 +137,7 @@ void ChatRoomPrivate::sendImdn (const string &payload, LinphoneReason reason) { } if (retval <= 0) { - op->send_message(identity, peerAddress.asString().c_str(), msg->getPrivate()->getContentType().c_str(), msg->getPrivate()->getText().c_str(), nullptr); + op->send_message(identity, peerAddress.asString().c_str(), msg->getPrivate()->getContentType().asString().c_str(), msg->getPrivate()->getText().c_str(), nullptr); } linphone_address_unref(peer); @@ -227,7 +227,7 @@ void ChatRoomPrivate::sendIsComposingNotification () { } if (retval <= 0) { - op->send_message(identity, peerAddress.asString().c_str(), msg->getPrivate()->getContentType().c_str(), msg->getPrivate()->getText().c_str(), nullptr); + op->send_message(identity, peerAddress.asString().c_str(), msg->getPrivate()->getContentType().asString().c_str(), msg->getPrivate()->getText().c_str(), nullptr); } op->unref(); } @@ -424,13 +424,13 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa goto end; } - if (ContentType::isImIsComposing(msg->getPrivate()->getContentType())) { + if (msg->getPrivate()->getContentType() == ContentType::ImIsComposing) { isComposingReceived(msg->getPrivate()->getText()); increaseMsgCount = FALSE; if (lp_config_get_int(core->config, "sip", "deliver_imdn", 0) != 1) { goto end; } - } else if (ContentType::isImdn(msg->getPrivate()->getContentType())) { + } else if (msg->getPrivate()->getContentType() == ContentType::Imdn) { imdnReceived(msg->getPrivate()->getText()); increaseMsgCount = FALSE; if (lp_config_get_int(core->config, "sip", "deliver_imdn", 0) != 1) { @@ -461,7 +461,7 @@ end: void ChatRoomPrivate::chatMessageReceived (shared_ptr msg) { L_Q(); - if (!ContentType::isImdn(msg->getPrivate()->getContentType()) && !ContentType::isImIsComposing(msg->getPrivate()->getContentType())) { + if ((msg->getPrivate()->getContentType() != ContentType::Imdn) && (msg->getPrivate()->getContentType() != ContentType::ImIsComposing)) { notifyChatMessageReceived(msg); remoteIsComposing = false; linphone_core_notify_is_composing_received(core, L_GET_C_BACK_PTR(q)); @@ -733,7 +733,7 @@ void ChatRoom::sendMessage (shared_ptr msg) { msg->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); /* Check if we shall upload a file to a server */ - if (msg->getPrivate()->getFileTransferInformation() && msg->getPrivate()->getContentType().empty()) { + if (msg->getPrivate()->getFileTransferInformation() && !msg->getPrivate()->getContentType().isValid()) { /* Open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */ if (msg->uploadFile() == 0) { /* Add to transient list only if message is going out */ diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index 14fe313ab..189f2e4a2 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -81,8 +81,7 @@ int CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { content = messagePrivate->contents.front(); } - ContentType contentType = content.getContentType(); - if (ContentType::isCpim(contentType.asString())) { + if (content.getContentType() == ContentType::Cpim) { const vector body = content.getBody(); string contentBody(body.begin(), body.end()); shared_ptr message = Cpim::Message::createFromString(contentBody); @@ -97,7 +96,7 @@ int CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { return 500; } } else { - lError() << "[CPIM] Message is not CPIM but " << contentType.asString(); + lError() << "[CPIM] Message is not CPIM but " << content.getContentType().asString(); return -1; } return 0; diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index b0609c72b..e2972e478 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +#include "linphone/utils/utils.h" + #include "object/clonable-object-p.h" #include "content-type.h" @@ -34,6 +36,16 @@ public: // ----------------------------------------------------------------------------- +const ContentType ContentType::Cpim("message/cpim"); +const ContentType ContentType::FileTransfer("application/vnd.gsma.rcs-ft-http+xml"); +const ContentType ContentType::Imdn("message/imdn+xml"); +const ContentType ContentType::ImIsComposing("application/im-iscomposing+xml"); +const ContentType ContentType::PlainText("text/plain"); +const ContentType ContentType::ResourceLists("application/resource-lists+xml"); +const ContentType ContentType::Sdp("application/sdp"); + +// ----------------------------------------------------------------------------- + ContentType::ContentType (const string &contentType) : ClonableObject(*new ContentTypePrivate) { L_D(); @@ -71,16 +83,8 @@ bool ContentType::operator== (const ContentType &contentType) const { return getType() == contentType.getType() && getSubType() == contentType.getSubType(); } -bool ContentType::operator== (const string &contentType) const { - return *this == ContentType(contentType); -} - bool ContentType::operator!= (const ContentType &contentType) const { - return !(*this == contentType); -} - -bool ContentType::operator!= (const std::string &contentType) const { - return !(*this == contentType); + return !operator==(contentType); } const string &ContentType::getType () const { @@ -91,7 +95,7 @@ const string &ContentType::getType () const { bool ContentType::setType (const string &type) { L_D(); if (type.find('/') == string::npos) { - d->type = type; + d->type = Utils::stringToLower(type); return true; } return false; @@ -105,7 +109,7 @@ const string &ContentType::getSubType () const { bool ContentType::setSubType (const string &subType) { L_D(); if (subType.find('/') == string::npos) { - d->subType = subType; + d->subType = Utils::stringToLower(subType); return true; } return false; @@ -121,40 +125,4 @@ string ContentType::asString () const { return isValid() ? d->type + "/" + d->subType : ""; } -bool ContentType::isFileTransfer () const { - return isFileTransfer(asString()); -} - -bool ContentType::isImIsComposing () const { - return isFileTransfer(asString()); -} - -bool ContentType::isImdn () const { - return isImdn(asString()); -} - -bool ContentType::isText () const { - return isText(asString()); -} - -bool ContentType::isFileTransfer (const string &contentType) { - return contentType == "application/vnd.gsma.rcs-ft-http+xml"; -} - -bool ContentType::isImIsComposing (const string &contentType) { - return contentType == "application/im-iscomposing+xml"; -} - -bool ContentType::isImdn (const string &contentType) { - return contentType == "message/imdn+xml"; -} - -bool ContentType::isText (const string &contentType) { - return contentType == "text/plain"; -} - -bool ContentType::isCpim(const string &contentType) { - return contentType == "Message/CPIM"; -} - LINPHONE_END_NAMESPACE diff --git a/src/content/content-type.h b/src/content/content-type.h index 746166c66..9f05fef68 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -36,9 +36,12 @@ public: ContentType &operator= (const ContentType &src); bool operator== (const ContentType &contentType) const; - bool operator== (const std::string &contentType) const; bool operator!= (const ContentType &contentType) const; - bool operator!= (const std::string &contentType) const; + + // Delete these operators to prevent putting complicated content-type strings + // in the code. Instead define static const ContentType objects below. + bool operator== (const std::string &contentType) const = delete; + bool operator!= (const std::string &contentType) const = delete; bool isValid () const; @@ -50,16 +53,13 @@ public: std::string asString () const; - bool isFileTransfer () const; - bool isImIsComposing () const; - bool isImdn () const; - bool isText () const; - - static bool isFileTransfer (const std::string &contentType); - static bool isImIsComposing (const std::string &contentType); - static bool isImdn (const std::string &contentType); - static bool isText (const std::string &contentType); - static bool isCpim (const std::string &contentType); + static const ContentType Cpim; + static const ContentType FileTransfer; + static const ContentType Imdn; + static const ContentType ImIsComposing; + static const ContentType PlainText; + static const ContentType ResourceLists; + static const ContentType Sdp; private: L_DECLARE_PRIVATE(ContentType); diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index 8c0ac3f10..ce778ee6e 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -395,7 +395,7 @@ static void cpim_chat_message_modifier(void) { marieRoom->sendMessage(marieMessage); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageReceived,1)); - BC_ASSERT_TRUE(ContentType::isCpim(marieMessage->getInternalContent().getContentType().asString())); + BC_ASSERT_TRUE(marieMessage->getInternalContent().getContentType() == ContentType::Cpim); BC_ASSERT_PTR_NOT_NULL(pauline->stat.last_received_chat_message); if (pauline->stat.last_received_chat_message != NULL) {