From 78f4b39ab16e4b0a1406ad04b70941b1c1007cf9 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 26 Sep 2017 15:39:11 +0200 Subject: [PATCH] Finish cleaning of c-chat-message, still work to do in ChatMessage --- coreapi/private.h | 1 - include/linphone/api/c-chat-message.h | 6 +- src/c-wrapper/api/c-chat-message.cpp | 1130 ++++--------------------- src/chat/chat-message-p.h | 9 +- src/chat/chat-message.cpp | 938 +++++++++++++++++++- src/chat/chat-message.h | 54 +- src/chat/chat-room.cpp | 2 - tester/message_tester.c | 2 +- 8 files changed, 1139 insertions(+), 1003 deletions(-) diff --git a/coreapi/private.h b/coreapi/private.h index 0cd36ff8e..b3a9d0ce7 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1099,7 +1099,6 @@ void linphone_chat_message_set_file_transfer_information(LinphoneChatMessage *ms LinphoneChatMessageDir linphone_chat_message_get_direction(const LinphoneChatMessage *msg); SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg); void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, SalOp *op); -void linphone_chat_message_set_chat_room(LinphoneChatMessage *msg, LinphoneChatRoom *room); void linphone_chat_message_destroy(LinphoneChatMessage* msg); void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state); void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured); diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index 74f2753d1..7b82dcccd 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -105,7 +105,7 @@ LINPHONE_PUBLIC void linphone_chat_message_set_from_address(LinphoneChatMessage* * @param[in] message #LinphoneChatMessage obj * @return #LinphoneAddress */ -LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from_address(const LinphoneChatMessage* msg); +LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from_address(LinphoneChatMessage* msg); /** * Set destination of the message @@ -119,7 +119,7 @@ LINPHONE_PUBLIC void linphone_chat_message_set_to_address(LinphoneChatMessage* m * @param[in] message #LinphoneChatMessage obj * @return #LinphoneAddress */ -LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to_address(const LinphoneChatMessage* msg); +LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to_address(LinphoneChatMessage* msg); /** * Get the content type of a chat message. @@ -301,7 +301,7 @@ LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_peer_address(Li *@param message #LinphoneChatMessage obj *@return #LinphoneAddress */ -LINPHONE_PUBLIC LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage* message); +LINPHONE_PUBLIC const LinphoneAddress *linphone_chat_message_get_local_address(LinphoneChatMessage* message); /** * Add custom headers to the message. diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 3b4b78881..9fe96f8b4 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -23,11 +23,13 @@ #include "ortp/b64.h" #include "c-wrapper/c-wrapper.h" +#include "address/address.h" +#include "content/content.h" +#include "content/content-type.h" #include "chat/chat-message-p.h" #include "chat/chat-message.h" #include "chat/chat-room-p.h" #include "chat/real-time-text-chat-room-p.h" -#include "content/content-type.h" // ============================================================================= @@ -39,30 +41,9 @@ static void _linphone_chat_message_destructor (LinphoneChatMessage *msg); L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(ChatMessage, _linphone_chat_message_constructor, _linphone_chat_message_destructor, LinphoneChatMessageCbs *cbs; - LinphoneChatRoom* chat_room; + LinphoneAddress *from; // cache for shared_ptr
+ LinphoneAddress *to; // cache for shared_ptr
LinphoneErrorInfo *ei; - LinphoneChatMessageDir dir; - char* message; - void* message_userdata; - char* appdata; - char* external_body_url; - LinphoneAddress *from; - LinphoneAddress *to; - time_t time; - SalCustomHeader *sal_custom_headers; - LinphoneChatMessageState state; - bool_t is_read; - unsigned int storage_id; - char *message_id; - SalOp *op; - LinphoneContent *file_transfer_information; //< used to store file transfer information when the message is of file transfer type - char *content_type; //< is used to specified the type of message to be sent, used only for file transfer message - bool_t to_be_stored; - belle_http_request_t *http_request; //< keep a reference to the http_request in case of file transfer in order to be able to cancel the transfer - belle_http_request_listener_t *http_listener; // our listener, only owned by us - char *file_transfer_filepath; - unsigned long bg_task_id; - bool_t is_secured; LinphoneChatMessageStateChangedCb message_state_changed_cb; void* message_state_changed_user_data; ) @@ -74,6 +55,10 @@ static void _linphone_chat_message_constructor (LinphoneChatMessage *msg) { static void _linphone_chat_message_destructor (LinphoneChatMessage *msg) { linphone_chat_message_cbs_unref(msg->cbs); msg->cbs = nullptr; + if (msg->from) + linphone_address_unref(msg->from); + if (msg->to) + linphone_address_unref(msg->to); } // ============================================================================= @@ -149,14 +134,6 @@ void linphone_chat_message_set_outgoing(LinphoneChatMessage *msg) { L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setDirection(LinphonePrivate::ChatMessage::Direction::Outgoing); } -const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getContentType().c_str(); -} - -const char *linphone_chat_message_get_text(const LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getText().c_str(); -} - unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage *msg) { return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getStorageId(); } @@ -193,33 +170,136 @@ void linphone_chat_message_set_appdata(LinphoneChatMessage *msg, const char *dat L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setAppdata(data); } -// ============================================================================= - void linphone_chat_message_set_from_address(LinphoneChatMessage *msg, const LinphoneAddress *from) { - if (msg->from) - linphone_address_unref(msg->from); - msg->from = linphone_address_clone(from); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFromAddress(make_shared(linphone_address_as_string(from))); } -const LinphoneAddress *linphone_chat_message_get_from_address(const LinphoneChatMessage *msg) { +const LinphoneAddress *linphone_chat_message_get_from_address(LinphoneChatMessage *msg) { + if (msg->from) + linphone_address_unref(msg->from); + msg->from = linphone_address_new(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFromAddress()->asString().c_str()); return msg->from; } void linphone_chat_message_set_to_address(LinphoneChatMessage *msg, const LinphoneAddress *to) { - if (msg->to) - linphone_address_unref(msg->to); - msg->to = linphone_address_clone(to); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setToAddress(make_shared(linphone_address_as_string(to))); } -const LinphoneAddress *linphone_chat_message_get_to_address(const LinphoneChatMessage *msg) { +const LinphoneAddress *linphone_chat_message_get_to_address(LinphoneChatMessage *msg) { if (msg->to) - return msg->to; - if (msg->dir == LinphoneChatMessageOutgoing) { - return linphone_chat_room_get_peer_address(msg->chat_room); - } - return NULL; + linphone_address_unref(msg->to); + msg->to = linphone_address_new(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getToAddress()->asString().c_str()); + return msg->to; } +const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFileTransferFilepath().c_str(); +} + +void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFileTransferFilepath(filepath); +} + +bool_t linphone_chat_message_get_to_be_stored(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isToBeStored(); +} + +void linphone_chat_message_set_to_be_stored(LinphoneChatMessage *msg, bool_t to_be_stored) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setIsToBeStored(to_be_stored); +} + +belle_http_request_t * linphone_chat_message_get_http_request(LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getHttpRequest(); +} + +void linphone_chat_message_set_http_request(LinphoneChatMessage *msg, belle_http_request_t *request) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setHttpRequest(request); +} + +SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getSalOp(); +} + +void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, SalOp *op) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setSalOp(op); +} + +SalCustomHeader * linphone_chat_message_get_sal_custom_headers(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getSalCustomHeaders(); +} + +void linphone_chat_message_set_sal_custom_headers(LinphoneChatMessage *msg, SalCustomHeader *header) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setSalCustomHeaders(header); +} + +void linphone_chat_message_add_custom_header(LinphoneChatMessage *msg, const char *header_name, + const char *header_value) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->addSalCustomHeader(header_name, header_value); +} + +void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const char *header_name) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->removeSalCustomHeader(header_name); +} + +const char *linphone_chat_message_get_custom_header(LinphoneChatMessage *msg, const char *header_name) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getSalCustomHeaderValue(header_name).c_str(); +} + +// ============================================================================= +// Methods +// ============================================================================= + +int linphone_chat_room_upload_file(LinphoneChatMessage *msg) { + return ((LinphoneStatus)L_GET_CPP_PTR_FROM_C_OBJECT(msg)->uploadFile()); +} + +LinphoneStatus linphone_chat_message_download_file(LinphoneChatMessage *msg) { + return ((LinphoneStatus)L_GET_CPP_PTR_FROM_C_OBJECT(msg)->downloadFile()); +} + +void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->cancelFileTransfer(); +} + +void linphone_chat_message_resend(LinphoneChatMessage *msg) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->reSend(); +} + +void linphone_chat_message_resend_2(LinphoneChatMessage *msg) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->reSend(); +} + +void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->updateState((LinphonePrivate::ChatMessage::State) new_state); +} +void linphone_chat_message_send_imdn(LinphoneChatMessage *msg, ImdnType imdn_type, LinphoneReason reason) { + //TODO + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->sendImdn(); +} + +void linphone_chat_message_deactivate(LinphoneChatMessage *msg){ + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->cancelFileTransfer(); + // TODO ? + //msg->chat_room = NULL; +} + +void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *msg, LinphoneReason reason) { + //TODO + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->sendDeliveryNotification(); +} + +void linphone_chat_message_send_display_notification(LinphoneChatMessage *msg) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->sendDisplayNotification(); +} + +LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t character) { + return ((LinphoneStatus)L_GET_CPP_PTR_FROM_C_OBJECT(msg)->putCharacter(character)); +} + +// ============================================================================= +// Old listener +// ============================================================================= + void linphone_chat_message_set_message_state_changed_cb(LinphoneChatMessage* msg, LinphoneChatMessageStateChangedCb cb) { msg->message_state_changed_cb = cb; } @@ -232,307 +312,69 @@ void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChat return msg->message_state_changed_user_data; } +// ============================================================================= +// Structure has changed, hard to keep the behavior +// ============================================================================= + +const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getContentType().c_str(); +} + void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type) { - if (msg->content_type) { - ms_free(msg->content_type); - } - msg->content_type = content_type ? ms_strdup(content_type) : NULL; + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setContentType(content_type); +} + +const char *linphone_chat_message_get_text(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getText().c_str(); } int linphone_chat_message_set_text(LinphoneChatMessage *msg, const char* text) { - if (msg->message) - ms_free(msg->message); - if (text) - msg->message = ms_strdup(text); - else - msg->message = NULL; - + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setText(text); return 0; } LinphoneContent *linphone_chat_message_get_file_transfer_information(LinphoneChatMessage *msg) { - return msg->file_transfer_information; -} - -SalCustomHeader * linphone_chat_message_get_sal_custom_headers(const LinphoneChatMessage *msg) { - return msg->sal_custom_headers; -} - -void linphone_chat_message_set_sal_custom_headers(LinphoneChatMessage *msg, SalCustomHeader *header) { - msg->sal_custom_headers = header; -} - -belle_http_request_t * linphone_chat_message_get_http_request(LinphoneChatMessage *msg) { - return msg->http_request; -} - -void linphone_chat_message_set_http_request(LinphoneChatMessage *msg, belle_http_request_t *request) { - msg->http_request = request; + //return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFileTransferInformation(); + //TODO + return NULL; } void linphone_chat_message_set_file_transfer_information(LinphoneChatMessage *msg, LinphoneContent *content) { - msg->file_transfer_information = content; + //TODO + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFileTransferInformation(nullptr); } -SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg) { - return msg->op; +// ============================================================================= +// Nothing to do, they call other C API methods +// ============================================================================= + +const LinphoneAddress *linphone_chat_message_get_peer_address(LinphoneChatMessage *msg) { + return linphone_chat_room_get_peer_address(linphone_chat_message_get_chat_room(msg)); } -void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, SalOp *op) { - msg->op = op; -} - -void linphone_chat_message_set_chat_room(LinphoneChatMessage *msg, LinphoneChatRoom *room) { - msg->chat_room = room; -} - -const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg) { - return msg->file_transfer_filepath; +const LinphoneAddress *linphone_chat_message_get_local_address(LinphoneChatMessage *msg) { + if (L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isOutgoing()) { + return linphone_chat_message_get_from_address(msg); + } + return linphone_chat_message_get_to_address(msg); } const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg) { if (!msg->ei) ((LinphoneChatMessage*)msg)->ei = linphone_error_info_new(); /*let's do it mutable*/ - linphone_error_info_from_sal_op(msg->ei, msg->op); + linphone_error_info_from_sal_op(msg->ei, linphone_chat_message_get_sal_op(msg)); return msg->ei; } LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage *msg) { return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg)); -}const LinphoneAddress *linphone_chat_message_get_peer_address(LinphoneChatMessage *msg) { - return linphone_chat_room_get_peer_address(msg->chat_room); } bool_t linphone_chat_message_is_file_transfer(const LinphoneChatMessage *msg) { - return LinphonePrivate::ContentType::isFileTransfer(msg->content_type); + return LinphonePrivate::ContentType::isFileTransfer(linphone_chat_message_get_content_type(msg)); } bool_t linphone_chat_message_is_text(const LinphoneChatMessage *msg) { - return LinphonePrivate::ContentType::isText(msg->content_type); -} - -bool_t linphone_chat_message_get_to_be_stored(const LinphoneChatMessage *msg) { - return msg->to_be_stored; -} - -void linphone_chat_message_set_to_be_stored(LinphoneChatMessage *msg, bool_t to_be_stored) { - msg->to_be_stored = to_be_stored; -} - -LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage *msg) { - return msg->dir == LinphoneChatMessageOutgoing ? msg->from : msg->to; -} - -void linphone_chat_message_add_custom_header(LinphoneChatMessage *msg, const char *header_name, - const char *header_value) { - msg->sal_custom_headers = sal_custom_header_append(msg->sal_custom_headers, header_name, header_value); -} - -const char *linphone_chat_message_get_custom_header(LinphoneChatMessage *msg, const char *header_name) { - return sal_custom_header_find(msg->sal_custom_headers, header_name); -} - -void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const char *header_name) { - msg->sal_custom_headers = sal_custom_header_remove(msg->sal_custom_headers, header_name); -} - -// ============================================================================= -// ============================================================================= - -void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state) { - linphone_chat_message_set_state(msg, new_state); - linphone_chat_message_store_state(msg); - - if (msg->state == LinphoneChatMessageStateDelivered || msg->state == LinphoneChatMessageStateNotDelivered) { - L_GET_PRIVATE_FROM_C_OBJECT(msg->chat_room)->moveTransientMessageToWeakMessages(msg); - } -} - -void _linphone_chat_message_resend(LinphoneChatMessage *msg, bool_t ref_msg) { - LinphoneChatMessageState state = linphone_chat_message_get_state(msg); - LinphoneChatRoom *cr; - - if (state != LinphoneChatMessageStateNotDelivered) { - ms_warning("Cannot resend chat message in state %s", linphone_chat_message_state_to_string(state)); - return; - } - - cr = linphone_chat_message_get_chat_room(msg); - if (ref_msg) linphone_chat_message_ref(msg); - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(msg); -} - -void linphone_chat_message_resend(LinphoneChatMessage *msg) { - _linphone_chat_message_resend(msg, FALSE); -} - -void linphone_chat_message_resend_2(LinphoneChatMessage *msg) { - _linphone_chat_message_resend(msg, TRUE); -} - -static char *linphone_chat_message_create_imdn_xml(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason) { - xmlBufferPtr buf; - xmlTextWriterPtr writer; - int err; - char *content = NULL; - char *datetime = NULL; - const char *message_id; - - /* Check that the chat message has a message id */ - message_id = linphone_chat_message_get_message_id(cm); - if (message_id == NULL) return NULL; - - buf = xmlBufferCreate(); - if (buf == NULL) { - ms_error("Error creating the XML buffer"); - return content; - } - writer = xmlNewTextWriterMemory(buf, 0); - if (writer == NULL) { - ms_error("Error creating the XML writer"); - return content; - } - - datetime = linphone_timestamp_to_rfc3339_string(linphone_chat_message_get_time(cm)); - err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); - if (err >= 0) { - err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"imdn", - (const xmlChar *)"urn:ietf:params:xml:ns:imdn"); - } - if ((err >= 0) && (reason != LinphoneReasonNone)) { - err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", NULL, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd"); - } - if (err >= 0) { - err = xmlTextWriterWriteElement(writer, (const xmlChar *)"message-id", (const xmlChar *)message_id); - } - if (err >= 0) { - err = xmlTextWriterWriteElement(writer, (const xmlChar *)"datetime", (const xmlChar *)datetime); - } - if (err >= 0) { - if (imdn_type == ImdnTypeDelivery) { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivery-notification"); - } else { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"display-notification"); - } - } - if (err >= 0) { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"status"); - } - if (err >= 0) { - if (reason == LinphoneReasonNone) { - if (imdn_type == ImdnTypeDelivery) { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivered"); - } else { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"displayed"); - } - } else { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"error"); - } - } - if (err >= 0) { - /* Close the "delivered", "displayed" or "error" element. */ - err = xmlTextWriterEndElement(writer); - } - if ((err >= 0) && (reason != LinphoneReasonNone)) { - err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"linphoneimdn", (const xmlChar *)"reason", NULL); - if (err >= 0) { - char codestr[16]; - snprintf(codestr, 16, "%d", linphone_reason_to_error_code(reason)); - err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"code", (const xmlChar *)codestr); - } - if (err >= 0) { - err = xmlTextWriterWriteString(writer, (const xmlChar *)linphone_reason_to_string(reason)); - } - if (err >= 0) { - err = xmlTextWriterEndElement(writer); - } - } - if (err >= 0) { - /* Close the "status" element. */ - err = xmlTextWriterEndElement(writer); - } - if (err >= 0) { - /* Close the "delivery-notification" or "display-notification" element. */ - err = xmlTextWriterEndElement(writer); - } - if (err >= 0) { - /* Close the "imdn" element. */ - err = xmlTextWriterEndElement(writer); - } - if (err >= 0) { - err = xmlTextWriterEndDocument(writer); - } - if (err > 0) { - /* xmlTextWriterEndDocument returns the size of the content. */ - content = ms_strdup((char *)buf->content); - } - xmlFreeTextWriter(writer); - xmlBufferFree(buf); - ms_free(datetime); - return content; -} - -void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason) { - char *content = linphone_chat_message_create_imdn_xml(cm, imdn_type, reason); - if (content) { - L_GET_PRIVATE_FROM_C_OBJECT(linphone_chat_message_get_chat_room(cm))->sendImdn(content, reason); - ms_free(content); - } -} - -void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *cm, LinphoneReason reason) { - LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); - LinphoneCore *lc = linphone_chat_room_get_core(cr); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if (linphone_im_notif_policy_get_send_imdn_delivered(policy) == TRUE) { - linphone_chat_message_send_imdn(cm, ImdnTypeDelivery, reason); - } -} - -void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm) { - LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); - LinphoneCore *lc = linphone_chat_room_get_core(cr); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if (linphone_im_notif_policy_get_send_imdn_displayed(policy) == TRUE) { - linphone_chat_message_send_imdn(cm, ImdnTypeDisplay, LinphoneReasonNone); - } -}LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t character) { - LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); - if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) { - shared_ptr rttcr = - static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); - LinphoneCall *call = rttcr->getCall(); - LinphoneCore *lc = rttcr->getCore(); - const uint32_t new_line = 0x2028; - const uint32_t crlf = 0x0D0A; - const uint32_t lf = 0x0A; - - if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText)) { - return -1; - } - - if (character == new_line || character == crlf || character == lf) { - if (lc && lp_config_get_int(lc->config, "misc", "store_rtt_messages", 1) == 1) { - ms_debug("New line sent, forge a message with content %s", msg->message); - msg->time = ms_time(0); - msg->state = LinphoneChatMessageStateDisplayed; - msg->dir = LinphoneChatMessageOutgoing; - if (msg->from) linphone_address_unref(msg->from); - msg->from = linphone_address_new(linphone_core_get_identity(lc)); - msg->storage_id = linphone_chat_message_store(msg); - ms_free(msg->message); - msg->message = NULL; - } - } else { - char *value = LinphonePrivate::Utils::utf8ToChar(character); - msg->message = ms_strcat_printf(msg->message, value); - ms_debug("Sent RTT character: %s (%lu), pending text is %s", value, (unsigned long)character, msg->message); - delete value; - } - - text_stream_putchar32(reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeText)), character); - return 0; - } - return -1; + return LinphonePrivate::ContentType::isText(linphone_chat_message_get_content_type(msg)); } const char *linphone_chat_message_state_to_string(const LinphoneChatMessageState state) { @@ -557,618 +399,6 @@ const char *linphone_chat_message_state_to_string(const LinphoneChatMessageState return NULL; } -LinphoneChatMessage *linphone_chat_message_clone(const LinphoneChatMessage *msg) { - LinphoneChatMessage *new_message = linphone_chat_room_create_message(msg->chat_room, msg->message); - if (msg->external_body_url) - new_message->external_body_url = ms_strdup(msg->external_body_url); - if (msg->appdata) - new_message->appdata = ms_strdup(msg->appdata); - new_message->message_state_changed_cb = msg->message_state_changed_cb; - new_message->message_state_changed_user_data = msg->message_state_changed_user_data; - new_message->message_userdata = msg->message_userdata; - new_message->time = msg->time; - new_message->state = msg->state; - new_message->storage_id = msg->storage_id; - if (msg->from) - new_message->from = linphone_address_clone(msg->from); - if (msg->file_transfer_filepath) - new_message->file_transfer_filepath = ms_strdup(msg->file_transfer_filepath); - if (msg->file_transfer_information) - new_message->file_transfer_information = linphone_content_copy(msg->file_transfer_information); - return new_message; -} - -void linphone_chat_message_deactivate(LinphoneChatMessage *msg){ - if (msg->file_transfer_information != NULL) { - _linphone_chat_message_cancel_file_transfer(msg, FALSE); - } - /*mark the chat msg as orphan (it has no chat room anymore)*/ - msg->chat_room = NULL; -} - -void linphone_chat_message_release(LinphoneChatMessage *msg) { - linphone_chat_message_deactivate(msg); - linphone_chat_message_unref(msg); -} - -static bool_t file_transfer_in_progress_and_valid(LinphoneChatMessage* msg) { - return (linphone_chat_message_get_chat_room(msg) && - linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)) && - linphone_chat_message_get_http_request(msg) && - !belle_http_request_is_cancelled(linphone_chat_message_get_http_request(msg))); -} - -static void _release_http_request(LinphoneChatMessage* msg) { - if (linphone_chat_message_get_http_request(msg)) { - belle_sip_object_unref(msg->http_request); - msg->http_request = NULL; - if (msg->http_listener){ - belle_sip_object_unref(msg->http_listener); - msg->http_listener = NULL; - // unhold the reference that the listener was holding on the message - linphone_chat_message_unref(msg); - } - } -} - -static void linphone_chat_message_process_io_error_upload(void *data, const belle_sip_io_error_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("I/O Error during file upload of msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - linphone_chat_room_remove_transient_message(msg->chat_room, msg); - linphone_chat_message_unref(msg); -} - -static void linphone_chat_message_process_auth_requested_upload(void *data, belle_sip_auth_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("Error during file upload: auth requested for msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - linphone_chat_room_remove_transient_message(msg->chat_room, msg); - linphone_chat_message_unref(msg); -} - -static void linphone_chat_message_process_io_error_download(void *data, const belle_sip_io_error_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("I/O Error during file download msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError); - _release_http_request(msg); -} - -static void linphone_chat_message_process_auth_requested_download(void *data, belle_sip_auth_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("Error during file download : auth requested for msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError); - _release_http_request(msg); -} - -static void linphone_chat_message_file_transfer_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *m, - void *data, size_t offset, size_t total) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - if (!file_transfer_in_progress_and_valid(msg)) { - ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); - _release_http_request(msg); - return; - } - if (linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->cbs)) { - linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->cbs)( - msg, msg->file_transfer_information, offset, total); - } else { - /* Legacy: call back given by application level */ - linphone_core_notify_file_transfer_progress_indication(linphone_chat_room_get_core(msg->chat_room), msg, msg->file_transfer_information, - offset, total); - } -} - -static int on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, - void *data, size_t offset, uint8_t *buffer, size_t *size) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = NULL; - LinphoneImEncryptionEngine *imee = NULL; - int retval = -1; - - if (!file_transfer_in_progress_and_valid(msg)) { - if (msg->http_request) { - ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); - _release_http_request(msg); - } - return BELLE_SIP_STOP; - } - - lc = linphone_chat_room_get_core(msg->chat_room); - /* if we've not reach the end of file yet, ask for more data */ - /* in case of file body handler, won't be called */ - if (msg->file_transfer_filepath == NULL && offset < linphone_content_get_size(msg->file_transfer_information)) { - /* get data from call back */ - LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = linphone_chat_message_cbs_get_file_transfer_send(msg->cbs); - if (file_transfer_send_cb) { - LinphoneBuffer *lb = file_transfer_send_cb(msg, msg->file_transfer_information, offset, *size); - if (lb == NULL) { - *size = 0; - } else { - *size = linphone_buffer_get_size(lb); - memcpy(buffer, linphone_buffer_get_content(lb), *size); - linphone_buffer_unref(lb); - } - } else { - /* Legacy */ - linphone_core_notify_file_transfer_send(lc, msg, msg->file_transfer_information, (char *)buffer, size); - } - } - - imee = linphone_core_get_im_encryption_engine(lc); - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); - if (cb_process_uploading_file) { - size_t max_size = *size; - uint8_t *encrypted_buffer = (uint8_t *)ms_malloc0(max_size); - retval = cb_process_uploading_file(imee, msg, offset, (const uint8_t *)buffer, size, encrypted_buffer); - if (retval == 0) { - if (*size > max_size) { - ms_error("IM encryption engine process upload file callback returned a size bigger than the size of the buffer, so it will be truncated !"); - *size = max_size; - } - memcpy(buffer, encrypted_buffer, *size); - } - ms_free(encrypted_buffer); - } - } - - return retval <= 0 ? BELLE_SIP_CONTINUE : BELLE_SIP_STOP; -} - -static void on_send_end(belle_sip_user_body_handler_t *bh, void *data) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); - - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); - if (cb_process_uploading_file) { - cb_process_uploading_file(imee, msg, 0, NULL, NULL, NULL); - } - } -} - -static void file_upload_end_background_task(LinphoneChatMessage *obj){ - if (obj->bg_task_id){ - ms_message("channel [%p]: ending file upload background task with id=[%lx].",obj,obj->bg_task_id); - sal_end_background_task(obj->bg_task_id); - obj->bg_task_id=0; - } -} - -static void file_upload_background_task_ended(LinphoneChatMessage *obj){ - ms_warning("channel [%p]: file upload background task has to be ended now, but work isn't finished.",obj); - file_upload_end_background_task(obj); -} - -static void file_upload_begin_background_task(LinphoneChatMessage *obj){ - if (obj->bg_task_id==0){ - obj->bg_task_id=sal_begin_background_task("file transfer upload",(void (*)(void*))file_upload_background_task_ended, obj); - if (obj->bg_task_id) ms_message("channel [%p]: starting file upload background task with id=[%lx].",obj,obj->bg_task_id); - } -} - -static void linphone_chat_message_process_response_from_post_file(void *data, const belle_http_response_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - - if (msg->http_request && !file_transfer_in_progress_and_valid(msg)) { - ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); - _release_http_request(msg); - return; - } - - /* check the answer code */ - if (event->response) { - int code = belle_http_response_get_status_code(event->response); - if (code == 204) { /* this is the reply to the first post to the server - an empty msg */ - /* start uploading the file */ - belle_sip_multipart_body_handler_t *bh; - char *first_part_header; - belle_sip_body_handler_t *first_part_bh; - - bool_t is_file_encryption_enabled = FALSE; - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(linphone_chat_room_get_core(msg->chat_room)); - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb = - linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(imee_cbs); - if (is_encryption_enabled_for_file_transfer_cb) { - is_file_encryption_enabled = is_encryption_enabled_for_file_transfer_cb(imee, msg->chat_room); - } - } - /* shall we encrypt the file */ - if (is_file_encryption_enabled) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb = - linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs); - if (generate_file_transfer_key_cb) { - generate_file_transfer_key_cb(imee, msg->chat_room, msg); - } - /* temporary storage for the Content-disposition header value : use a generic filename to not leak it - * Actual filename stored in msg->file_transfer_information->name will be set in encrypted msg - * sended to the */ - first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"filename.txt\""); - } else { - /* temporary storage for the Content-disposition header value */ - first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", - linphone_content_get_name(msg->file_transfer_information)); - } - - /* create a user body handler to take care of the file and add the content disposition and content-type - * headers */ - first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new( - linphone_content_get_size(msg->file_transfer_information), - linphone_chat_message_file_transfer_on_progress, NULL, NULL, - on_send_body, on_send_end, msg); - if (msg->file_transfer_filepath != NULL) { - belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; - first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(msg->file_transfer_filepath, - NULL, msg); // No need to add again the callback for progression, otherwise it will be called twice - linphone_content_set_size(msg->file_transfer_information, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); - belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler); - } else if (linphone_content_get_buffer(msg->file_transfer_information) != NULL) { - first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer( - linphone_content_get_buffer(msg->file_transfer_information), - linphone_content_get_size(msg->file_transfer_information), linphone_chat_message_file_transfer_on_progress, msg); - } - - belle_sip_body_handler_add_header(first_part_bh, - belle_sip_header_create("Content-disposition", first_part_header)); - belle_sip_free(first_part_header); - belle_sip_body_handler_add_header(first_part_bh, - (belle_sip_header_t *)belle_sip_header_content_type_create( - linphone_content_get_type(msg->file_transfer_information), - linphone_content_get_subtype(msg->file_transfer_information))); - - /* insert it in a multipart body handler which will manage the boundaries of multipart msg */ - bh = belle_sip_multipart_body_handler_new(linphone_chat_message_file_transfer_on_progress, msg, first_part_bh, NULL); - - linphone_chat_message_ref(msg); - _release_http_request(msg); - file_upload_begin_background_task(msg); - linphone_chat_room_upload_file(msg); - belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(msg->http_request), BELLE_SIP_BODY_HANDLER(bh)); - linphone_chat_message_unref(msg); - } else if (code == 200) { /* file has been uploaded correctly, get server reply and send it */ - const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); - if (body && strlen(body) > 0) { - /* if we have an encryption key for the file, we must insert it into the msg and restore the correct - * filename */ - const char *content_key = linphone_content_get_key(msg->file_transfer_information); - size_t content_key_size = linphone_content_get_key_size(msg->file_transfer_information); - if (content_key != NULL) { - /* parse the msg body */ - xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body); - - xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); - if (cur != NULL) { - cur = cur->xmlChildrenNode; - while (cur != NULL) { - if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check - it has a type="file" attribute */ - xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); - if (!xmlStrcmp(typeAttribute, - (const xmlChar *)"file")) { /* this is the node we are looking for : add a - file-key children node */ - xmlNodePtr fileInfoNodeChildren = - cur - ->xmlChildrenNode; /* need to parse the children node to update the file-name - one */ - /* convert key to base64 */ - size_t b64Size = b64::b64_encode(NULL, content_key_size, NULL, 0); - char *keyb64 = (char *)ms_malloc0(b64Size + 1); - int xmlStringLength; - - b64Size = b64::b64_encode(content_key, content_key_size, keyb64, b64Size); - keyb64[b64Size] = '\0'; /* libxml need a null terminated string */ - - /* add the node containing the key to the file-info node */ - xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64); - xmlFree(typeAttribute); - ms_free(keyb64); - - /* look for the file-name node and update its content */ - while (fileInfoNodeChildren != NULL) { - if (!xmlStrcmp( - fileInfoNodeChildren->name, - (const xmlChar *)"file-name")) { /* we found a the file-name node, update - its content with the real filename */ - /* update node content */ - xmlNodeSetContent(fileInfoNodeChildren, - (const xmlChar *)(linphone_content_get_name( - msg->file_transfer_information))); - break; - } - fileInfoNodeChildren = fileInfoNodeChildren->next; - } - - /* dump the xml into msg->message */ - xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&msg->message, &xmlStringLength, - "UTF-8", 0); - - break; - } - xmlFree(typeAttribute); - } - cur = cur->next; - } - } - xmlFreeDoc(xmlMessageBody); - } else { /* no encryption key, transfer in plain, just copy the msg sent by server */ - msg->message = ms_strdup(body); - } - linphone_chat_message_set_content_type(msg, "application/vnd.gsma.rcs-ft-http+xml"); - linphone_chat_message_ref(msg); - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); - _release_http_request(msg); - L_GET_CPP_PTR_FROM_C_OBJECT(msg->chat_room)->sendMessage(msg); - file_upload_end_background_task(msg); - linphone_chat_message_unref(msg); - } else { - ms_warning("Received empty response from server, file transfer failed"); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - file_upload_end_background_task(msg); - linphone_chat_message_unref(msg); - } - } else { - ms_warning("Unhandled HTTP code response %d for file transfer", code); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - file_upload_end_background_task(msg); - linphone_chat_message_unref(msg); - } - } -} - -static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = NULL; - LinphoneImEncryptionEngine *imee = NULL; - int retval = -1; - uint8_t *decrypted_buffer = NULL; - - if (!msg->chat_room) { - linphone_chat_message_cancel_file_transfer(msg); - return; - } - lc = linphone_chat_room_get_core(msg->chat_room); - - if (lc == NULL){ - return; /*might happen during linphone_core_destroy()*/ - } - - if (!msg->http_request || belle_http_request_is_cancelled(msg->http_request)) { - ms_warning("Cancelled request for msg [%p], ignoring %s", msg, __FUNCTION__); - return; - } - - /* first call may be with a zero size, ignore it */ - if (size == 0) { - return; - } - - decrypted_buffer = (uint8_t *)ms_malloc0(size); - imee = linphone_core_get_im_encryption_engine(lc); - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); - if (cb_process_downloading_file) { - retval = cb_process_downloading_file(imee, msg, offset, (const uint8_t *)buffer, size, decrypted_buffer); - if (retval == 0) { - memcpy(buffer, decrypted_buffer, size); - } - } - } - ms_free(decrypted_buffer); - - if (retval <= 0) { - if (msg->file_transfer_filepath == NULL) { - if (linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)) { - LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size); - linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)(msg, msg->file_transfer_information, lb); - linphone_buffer_unref(lb); - } else { - /* Legacy: call back given by application level */ - linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, (const char *)buffer, size); - } - } - } else { - ms_warning("File transfer decrypt failed with code %d", (int)retval); - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError); - } - - return; -} - -static void on_recv_end(belle_sip_user_body_handler_t *bh, void *data) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); - int retval = -1; - - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); - if (cb_process_downloading_file) { - retval = cb_process_downloading_file(imee, msg, 0, NULL, 0, NULL); - } - } - - if (retval <= 0) { - if (msg->file_transfer_filepath == NULL) { - if (linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)) { - LinphoneBuffer *lb = linphone_buffer_new(); - linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)(msg, msg->file_transfer_information, lb); - linphone_buffer_unref(lb); - } else { - /* Legacy: call back given by application level */ - linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, NULL, 0); - } - } - } - - if (retval <= 0 && linphone_chat_message_get_state(msg) != LinphoneChatMessageStateFileTransferError) { - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); - } -} - -static LinphoneContent *linphone_chat_create_file_transfer_information_from_headers(const belle_sip_message_t *m) { - LinphoneContent *content = linphone_content_new(); - - belle_sip_header_content_length_t *content_length_hdr = - BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); - belle_sip_header_content_type_t *content_type_hdr = - BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); - const char *type = NULL, *subtype = NULL; - - linphone_content_set_name(content, ""); - - if (content_type_hdr) { - type = belle_sip_header_content_type_get_type(content_type_hdr); - subtype = belle_sip_header_content_type_get_subtype(content_type_hdr); - ms_message("Extracted content type %s / %s from header", type ? type : "", subtype ? subtype : ""); - if (type) - linphone_content_set_type(content, type); - if (subtype) - linphone_content_set_subtype(content, subtype); - } - - if (content_length_hdr) { - linphone_content_set_size(content, belle_sip_header_content_length_get_content_length(content_length_hdr)); - ms_message("Extracted content length %i from header", (int)linphone_content_get_size(content)); - } - - return content; -} - -static void linphone_chat_process_response_headers_from_get_file(void *data, const belle_http_response_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - if (event->response) { - /*we are receiving a response, set a specific body handler to acquire the response. - * if not done, belle-sip will create a memory body handler, the default*/ - belle_sip_message_t *response = BELLE_SIP_MESSAGE(event->response); - belle_sip_body_handler_t *body_handler = NULL; - size_t body_size = 0; - - if (msg->file_transfer_information == NULL) { - ms_warning("No file transfer information for msg %p: creating...", msg); - msg->file_transfer_information = linphone_chat_create_file_transfer_information_from_headers(response); - } - - if (msg->file_transfer_information) { - body_size = linphone_content_get_size(msg->file_transfer_information); - } - - - body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, linphone_chat_message_file_transfer_on_progress, NULL, on_recv_body, NULL, on_recv_end, msg); - if (msg->file_transfer_filepath != NULL) { - belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; - body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new( - msg->file_transfer_filepath, linphone_chat_message_file_transfer_on_progress, msg); - if (belle_sip_body_handler_get_size((belle_sip_body_handler_t *)body_handler) == 0) { - /* If the size of the body has not been initialized from the file stat, use the one from the - * file_transfer_information. */ - belle_sip_body_handler_set_size((belle_sip_body_handler_t *)body_handler, body_size); - } - belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)body_handler, bh); - } - belle_sip_message_set_body_handler((belle_sip_message_t *)event->response, body_handler); - } -} - -static void linphone_chat_process_response_from_get_file(void *data, const belle_http_response_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - /* check the answer code */ - if (event->response) { - int code = belle_http_response_get_status_code(event->response); - if (code >= 400 && code < 500) { - ms_warning("File transfer failed with code %d", code); - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError); - } else if (code != 200) { - ms_warning("Unhandled HTTP code response %d for file transfer", code); - } - _release_http_request(msg); - } -} - -int _linphone_chat_room_start_http_transfer(LinphoneChatMessage *msg, const char* url, const char* action, const belle_http_request_listener_callbacks_t *cbs) { - belle_generic_uri_t *uri = NULL; - const char* ua = linphone_core_get_user_agent(linphone_chat_room_get_core(msg->chat_room)); - - if (url == NULL) { - ms_warning("Cannot process file transfer msg: no file remote URI configured."); - goto error; - } - uri = belle_generic_uri_parse(url); - if (uri == NULL || belle_generic_uri_get_host(uri)==NULL) { - ms_warning("Cannot process file transfer msg: incorrect file remote URI configured '%s'.", url); - goto error; - } - - msg->http_request = belle_http_request_create(action, uri, belle_sip_header_create("User-Agent", ua), NULL); - - if (msg->http_request == NULL) { - ms_warning("Could not create http request for uri %s", url); - goto error; - } - /* keep a reference to the http request to be able to cancel it during upload */ - belle_sip_object_ref(msg->http_request); - - /* give msg to listener to be able to start the actual file upload when server answer a 204 No content */ - msg->http_listener = belle_http_request_listener_create_from_callbacks(cbs, linphone_chat_message_ref(msg)); - belle_http_provider_send_request(linphone_chat_room_get_core(msg->chat_room)->http_provider, msg->http_request, msg->http_listener); - return 0; -error: - if (uri) { - belle_sip_object_unref(uri); - } - return -1; -} - -int linphone_chat_room_upload_file(LinphoneChatMessage *msg) { - belle_http_request_listener_callbacks_t cbs = {0}; - int err; - - if (msg->http_request){ - ms_error("linphone_chat_room_upload_file(): there is already an upload in progress."); - return -1; - } - - cbs.process_response = linphone_chat_message_process_response_from_post_file; - cbs.process_io_error = linphone_chat_message_process_io_error_upload; - cbs.process_auth_requested = linphone_chat_message_process_auth_requested_upload; - err = _linphone_chat_room_start_http_transfer(msg, linphone_core_get_file_transfer_server(linphone_chat_room_get_core(msg->chat_room)), "POST", &cbs); - if (err == -1){ - linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered); - } - return err; -} - -LinphoneStatus linphone_chat_message_download_file(LinphoneChatMessage *msg) { - belle_http_request_listener_callbacks_t cbs = {0}; - int err; - - if (msg->http_request){ - ms_error("linphone_chat_message_download_file(): there is already a download in progress"); - return -1; - } - cbs.process_response_headers = linphone_chat_process_response_headers_from_get_file; - cbs.process_response = linphone_chat_process_response_from_get_file; - cbs.process_io_error = linphone_chat_message_process_io_error_download; - cbs.process_auth_requested = linphone_chat_message_process_auth_requested_download; - err = _linphone_chat_room_start_http_transfer(msg, msg->external_body_url, "GET", &cbs); - if (err == -1) return -1; - /* start the download, status is In Progress */ - linphone_chat_message_set_state(msg, LinphoneChatMessageStateInProgress); - return 0; -} - void linphone_chat_message_start_file_download(LinphoneChatMessage *msg, LinphoneChatMessageStateChangedCb status_cb, void *ud) { msg->message_state_changed_cb = status_cb; @@ -1176,39 +406,7 @@ void linphone_chat_message_start_file_download(LinphoneChatMessage *msg, linphone_chat_message_download_file(msg); } -void _linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg, bool_t unref) { - if (msg->http_request) { - if (msg->state == LinphoneChatMessageStateInProgress) { - linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered); - } - if (!belle_http_request_is_cancelled(msg->http_request)) { - if (msg->chat_room) { - ms_message("Canceling file transfer %s - msg [%p] chat room[%p]" - , (msg->external_body_url == NULL) ? linphone_core_get_file_transfer_server(linphone_chat_room_get_core(msg->chat_room)) : msg->external_body_url - , msg - , msg->chat_room); - belle_http_provider_cancel_request(linphone_chat_room_get_core(msg->chat_room)->http_provider, msg->http_request); - if ((msg->dir == LinphoneChatMessageOutgoing) && unref) { - // must release it - linphone_chat_message_unref(msg); - } - } else { - ms_message("Warning: http request still running for ORPHAN msg [%p]: this is a memory leak", msg); - } - } - _release_http_request(msg); - } else { - ms_message("No existing file transfer - nothing to cancel"); - } -} - -void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg) { - _linphone_chat_message_cancel_file_transfer(msg, TRUE); -} - -void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath) { - if (msg->file_transfer_filepath != NULL) { - ms_free(msg->file_transfer_filepath); - } - msg->file_transfer_filepath = ms_strdup(filepath); -} +void linphone_chat_message_release(LinphoneChatMessage *msg) { + linphone_chat_message_deactivate(msg); + linphone_chat_message_unref(msg); +} \ No newline at end of file diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 0145f1187..2b756812f 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -41,18 +41,23 @@ private: ChatMessage::Direction direction = ChatMessage::Incoming; ChatMessage::State state = ChatMessage::Idle; unsigned int storageId; - // LinphoneAddress *from; - // LinphoneAddress *to; + std::shared_ptr
from; + std::shared_ptr
to; time_t time = 0; std::string id; std::string appData; + std::string fileTransferFilePath; bool isSecured = false; bool isReadOnly = false; + bool isToBeStored = false; std::list > contents; std::shared_ptr internalContent; std::unordered_map customHeaders; std::shared_ptr eventsDb; std::shared_ptr errorInfo; + belle_http_request_t *httpRequest; + SalOp *salOp; + SalCustomHeader *salCustomHeaders; L_DECLARE_PUBLIC(ChatMessage); }; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index c73be1e5f..2c5f07e50 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -19,7 +19,6 @@ #include "db/events-db.h" #include "object/object-p.h" -#include "linphone/types.h" #include "linphone/core.h" #include "linphone/lpconfig.h" #include "c-wrapper/c-wrapper.h" @@ -151,14 +150,67 @@ void ChatMessage::setId (string id) { } bool ChatMessage::isRead() const { - //L_D(const ChatMessage); return false; - /*shared_ptr policy =d->chatRoom->core->getImNotifPolicy(); + /* TODO + L_D(const ChatMessage); + shared_ptr policy =d->chatRoom->core->getImNotifPolicy(); if (policy->getRecvImdnDisplayed() && d->state == Displayed) return true; if (policy->getRecvImdnDelivered() && (d->state == DeliveredToUser || d->state == Displayed)) return true; return d->state == Delivered || d->state == Displayed || d->state == DeliveredToUser;*/ } +string ChatMessage::getAppdata () const { + L_D(const ChatMessage); + return d->appData; +} + +void ChatMessage::setAppdata (const string &appData) { + L_D(ChatMessage); + d->appData = appData; + // TODO: store app data in db ! + // linphone_chat_message_store_appdata(msg); +} + +shared_ptr
ChatMessage::getFromAddress () const { + L_D(const ChatMessage); + return d->from; +} + +void ChatMessage::setFromAddress(shared_ptr
from) { + L_D(ChatMessage); + d->from = from; +} + +shared_ptr
ChatMessage::getToAddress () const { + L_D(const ChatMessage); + return d->to; +} + +void ChatMessage::setToAddress(shared_ptr
to) { + L_D(ChatMessage); + d->to = to; +} + +string ChatMessage::getFileTransferFilepath() const { + L_D(const ChatMessage); + return d->fileTransferFilePath; +} + +void ChatMessage::setFileTransferFilepath(const string &path) { + L_D(ChatMessage); + d->fileTransferFilePath = path; +} + +bool ChatMessage::isToBeStored() const { + L_D(const ChatMessage); + return d->isToBeStored; +} + +void ChatMessage::setIsToBeStored(bool store) { + L_D(ChatMessage); + d->isToBeStored = store; +} + // ----------------------------------------------------------------------------- string ChatMessage::getContentType() const { @@ -172,6 +224,10 @@ string ChatMessage::getContentType() const { return ""; } +void ChatMessage::setContentType(string contentType) { + //TODO +} + string ChatMessage::getText() const { L_D(const ChatMessage); if (d->internalContent) { @@ -183,6 +239,19 @@ string ChatMessage::getText() const { return ""; } +void ChatMessage::setText(string text) { + //TODO +} + +shared_ptr ChatMessage::getFileTransferInformation() const { + //TODO + return nullptr; +} + +void ChatMessage::setFileTransferInformation(shared_ptr content) { + //TODO +} + unsigned int ChatMessage::getStorageId() const { L_D(const ChatMessage); return d->storageId; @@ -193,45 +262,868 @@ void ChatMessage::setStorageId(unsigned int id) { d->storageId = id; } -string ChatMessage::getAppdata () const { +belle_http_request_t *ChatMessage::getHttpRequest() const { L_D(const ChatMessage); - return d->appData; + return d->httpRequest; } -void ChatMessage::setAppdata (const string &appData) { +void ChatMessage::setHttpRequest(belle_http_request_t *request) { L_D(ChatMessage); - d->appData = appData; - // TODO: store app data in db ! - // linphone_chat_message_store_appdata(msg); + d->httpRequest = request; } -// ----------------------------------------------------------------------------- - -shared_ptr ChatMessage::getFromAddress () const { - // TODO. - return nullptr; +SalOp *ChatMessage::getSalOp() const { + L_D(const ChatMessage); + return d->salOp; } -shared_ptr ChatMessage::getToAddress () const { - // TODO. - return nullptr; +void ChatMessage::setSalOp(SalOp *op) { + L_D(ChatMessage); + d->salOp = op; } -shared_ptr ChatMessage::getLocalAddress () const { - // TODO. - return nullptr; +SalCustomHeader *ChatMessage::getSalCustomHeaders() const { + L_D(const ChatMessage); + return d->salCustomHeaders; } -shared_ptr ChatMessage::getRemoteAddress () const { - // TODO. - return nullptr; +void ChatMessage::setSalCustomHeaders(SalCustomHeader *headers) { + L_D(ChatMessage); + d->salCustomHeaders = headers; +} + +void ChatMessage::addSalCustomHeader(string name, string value) { + L_D(ChatMessage); + d->salCustomHeaders = sal_custom_header_append(d->salCustomHeaders, name.c_str(), value.c_str()); +} + +void ChatMessage::removeSalCustomHeader(string name) { + L_D(ChatMessage); + d->salCustomHeaders = sal_custom_header_remove(d->salCustomHeaders, name.c_str()); +} + +string ChatMessage::getSalCustomHeaderValue(string name) { + L_D(ChatMessage); + return sal_custom_header_find(d->salCustomHeaders, name.c_str()); } shared_ptr ChatMessage::getErrorInfo () const { L_D(const ChatMessage); + //TODO return d->errorInfo; } +// ----------------------------------------------------------------------------- + +void ChatMessage::updateState(State state) { + //TODO + /*linphone_chat_message_set_state(msg, new_state); + linphone_chat_message_store_state(msg); + + if (msg->state == LinphoneChatMessageStateDelivered || msg->state == LinphoneChatMessageStateNotDelivered) { + L_GET_PRIVATE_FROM_C_OBJECT(msg->chat_room)->moveTransientMessageToWeakMessages(msg); + }*/ +} + +void ChatMessage::reSend() { + //TODO + /*LinphoneChatMessageState state = linphone_chat_message_get_state(msg); + LinphoneChatRoom *cr; + + if (state != LinphoneChatMessageStateNotDelivered) { + ms_warning("Cannot resend chat message in state %s", linphone_chat_message_state_to_string(state)); + return; + } + + cr = linphone_chat_message_get_chat_room(msg); + if (ref_msg) linphone_chat_message_ref(msg); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(msg);*/ +} + +/*static void linphone_chat_message_process_io_error_upload(void *data, const belle_sip_io_error_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + ms_error("I/O Error during file upload of msg [%p]", msg); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); + _release_http_request(msg); + linphone_chat_room_remove_transient_message(msg->chat_room, msg); + linphone_chat_message_unref(msg); +} + +static void linphone_chat_message_process_auth_requested_upload(void *data, belle_sip_auth_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + ms_error("Error during file upload: auth requested for msg [%p]", msg); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); + _release_http_request(msg); + linphone_chat_room_remove_transient_message(msg->chat_room, msg); + linphone_chat_message_unref(msg); +} + +static void linphone_chat_message_process_io_error_download(void *data, const belle_sip_io_error_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + ms_error("I/O Error during file download msg [%p]", msg); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError); + _release_http_request(msg); +} + +static void linphone_chat_process_response_from_get_file(void *data, const belle_http_response_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + // check the answer code + if (event->response) { + int code = belle_http_response_get_status_code(event->response); + if (code >= 400 && code < 500) { + ms_warning("File transfer failed with code %d", code); + linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError); + } else if (code != 200) { + ms_warning("Unhandled HTTP code response %d for file transfer", code); + } + _release_http_request(msg); + } +}*/ + +/*static char *linphone_chat_message_create_imdn_xml(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason) { + xmlBufferPtr buf; + xmlTextWriterPtr writer; + int err; + char *content = NULL; + char *datetime = NULL; + const char *message_id; + + // Check that the chat message has a message id + message_id = linphone_chat_message_get_message_id(cm); + if (message_id == NULL) return NULL; + + buf = xmlBufferCreate(); + if (buf == NULL) { + ms_error("Error creating the XML buffer"); + return content; + } + writer = xmlNewTextWriterMemory(buf, 0); + if (writer == NULL) { + ms_error("Error creating the XML writer"); + return content; + } + + datetime = linphone_timestamp_to_rfc3339_string(linphone_chat_message_get_time(cm)); + err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); + if (err >= 0) { + err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"imdn", + (const xmlChar *)"urn:ietf:params:xml:ns:imdn"); + } + if ((err >= 0) && (reason != LinphoneReasonNone)) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", NULL, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd"); + } + if (err >= 0) { + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"message-id", (const xmlChar *)message_id); + } + if (err >= 0) { + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"datetime", (const xmlChar *)datetime); + } + if (err >= 0) { + if (imdn_type == ImdnTypeDelivery) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivery-notification"); + } else { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"display-notification"); + } + } + if (err >= 0) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"status"); + } + if (err >= 0) { + if (reason == LinphoneReasonNone) { + if (imdn_type == ImdnTypeDelivery) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivered"); + } else { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"displayed"); + } + } else { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"error"); + } + } + if (err >= 0) { + // Close the "delivered", "displayed" or "error" element. + err = xmlTextWriterEndElement(writer); + } + if ((err >= 0) && (reason != LinphoneReasonNone)) { + err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"linphoneimdn", (const xmlChar *)"reason", NULL); + if (err >= 0) { + char codestr[16]; + snprintf(codestr, 16, "%d", linphone_reason_to_error_code(reason)); + err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"code", (const xmlChar *)codestr); + } + if (err >= 0) { + err = xmlTextWriterWriteString(writer, (const xmlChar *)linphone_reason_to_string(reason)); + } + if (err >= 0) { + err = xmlTextWriterEndElement(writer); + } + } + if (err >= 0) { + // Close the "status" element. + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + // Close the "delivery-notification" or "display-notification" element. + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + // Close the "imdn" element. + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + err = xmlTextWriterEndDocument(writer); + } + if (err > 0) { + // xmlTextWriterEndDocument returns the size of the content. + content = ms_strdup((char *)buf->content); + } + xmlFreeTextWriter(writer); + xmlBufferFree(buf); + ms_free(datetime); + return content; +}*/ + +void ChatMessage::sendImdn() { + //TODO + /*char *content = linphone_chat_message_create_imdn_xml(cm, imdn_type, reason); + if (content) { + L_GET_PRIVATE_FROM_C_OBJECT(linphone_chat_message_get_chat_room(cm))->sendImdn(content, reason); + ms_free(content); + }*/ +} + +void ChatMessage::sendDeliveryNotification() { + //TODO + /*LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); + LinphoneCore *lc = linphone_chat_room_get_core(cr); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); + if (linphone_im_notif_policy_get_send_imdn_delivered(policy) == TRUE) { + linphone_chat_message_send_imdn(cm, ImdnTypeDelivery, reason); + }*/ +} + +void ChatMessage::sendDisplayNotification() { + //TODO + /*LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); + LinphoneCore *lc = linphone_chat_room_get_core(cr); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); + if (linphone_im_notif_policy_get_send_imdn_displayed(policy) == TRUE) { + linphone_chat_message_send_imdn(cm, ImdnTypeDisplay, LinphoneReasonNone); + }*/ +} + +/* +static LinphoneContent *linphone_chat_create_file_transfer_information_from_headers(const belle_sip_message_t *m) { + LinphoneContent *content = linphone_content_new(); + + belle_sip_header_content_length_t *content_length_hdr = + BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); + belle_sip_header_content_type_t *content_type_hdr = + BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); + const char *type = NULL, *subtype = NULL; + + linphone_content_set_name(content, ""); + + if (content_type_hdr) { + type = belle_sip_header_content_type_get_type(content_type_hdr); + subtype = belle_sip_header_content_type_get_subtype(content_type_hdr); + ms_message("Extracted content type %s / %s from header", type ? type : "", subtype ? subtype : ""); + if (type) + linphone_content_set_type(content, type); + if (subtype) + linphone_content_set_subtype(content, subtype); + } + + if (content_length_hdr) { + linphone_content_set_size(content, belle_sip_header_content_length_get_content_length(content_length_hdr)); + ms_message("Extracted content length %i from header", (int)linphone_content_get_size(content)); + } + + return content; +} + +static void linphone_chat_process_response_headers_from_get_file(void *data, const belle_http_response_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + if (event->response) { + //we are receiving a response, set a specific body handler to acquire the response. + // if not done, belle-sip will create a memory body handler, the default + belle_sip_message_t *response = BELLE_SIP_MESSAGE(event->response); + belle_sip_body_handler_t *body_handler = NULL; + size_t body_size = 0; + + if (msg->file_transfer_information == NULL) { + ms_warning("No file transfer information for msg %p: creating...", msg); + msg->file_transfer_information = linphone_chat_create_file_transfer_information_from_headers(response); + } + + if (msg->file_transfer_information) { + body_size = linphone_content_get_size(msg->file_transfer_information); + } + + + body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, linphone_chat_message_file_transfer_on_progress, NULL, on_recv_body, NULL, on_recv_end, msg); + if (msg->file_transfer_filepath != NULL) { + belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; + body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new( + msg->file_transfer_filepath, linphone_chat_message_file_transfer_on_progress, msg); + if (belle_sip_body_handler_get_size((belle_sip_body_handler_t *)body_handler) == 0) { + // If the size of the body has not been initialized from the file stat, use the one from the + // file_transfer_information. + belle_sip_body_handler_set_size((belle_sip_body_handler_t *)body_handler, body_size); + } + belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)body_handler, bh); + } + belle_sip_message_set_body_handler((belle_sip_message_t *)event->response, body_handler); + } + }*/ + +/*static bool_t file_transfer_in_progress_and_valid(LinphoneChatMessage* msg) { + return (linphone_chat_message_get_chat_room(msg) && + linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)) && + linphone_chat_message_get_http_request(msg) && + !belle_http_request_is_cancelled(linphone_chat_message_get_http_request(msg))); +} + +static void _release_http_request(LinphoneChatMessage* msg) { + if (linphone_chat_message_get_http_request(msg)) { + belle_sip_object_unref(msg->http_request); + msg->http_request = NULL; + if (msg->http_listener){ + belle_sip_object_unref(msg->http_listener); + msg->http_listener = NULL; + // unhold the reference that the listener was holding on the message + linphone_chat_message_unref(msg); + } + } +} + +static void linphone_chat_message_process_auth_requested_download(void *data, belle_sip_auth_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + ms_error("Error during file download : auth requested for msg [%p]", msg); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError); + _release_http_request(msg); +} + +static void linphone_chat_message_file_transfer_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *m, + void *data, size_t offset, size_t total) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + if (!file_transfer_in_progress_and_valid(msg)) { + ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); + _release_http_request(msg); + return; + } + if (linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->cbs)) { + linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->cbs)( + msg, msg->file_transfer_information, offset, total); + } else { + // Legacy: call back given by application level + linphone_core_notify_file_transfer_progress_indication(linphone_chat_room_get_core(msg->chat_room), msg, msg->file_transfer_information, + offset, total); + } +} + +static int on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, + void *data, size_t offset, uint8_t *buffer, size_t *size) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + LinphoneCore *lc = NULL; + LinphoneImEncryptionEngine *imee = NULL; + int retval = -1; + + if (!file_transfer_in_progress_and_valid(msg)) { + if (msg->http_request) { + ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); + _release_http_request(msg); + } + return BELLE_SIP_STOP; + } + + lc = linphone_chat_room_get_core(msg->chat_room); + // if we've not reach the end of file yet, ask for more data + // in case of file body handler, won't be called + if (msg->file_transfer_filepath == NULL && offset < linphone_content_get_size(msg->file_transfer_information)) { + // get data from call back + LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = linphone_chat_message_cbs_get_file_transfer_send(msg->cbs); + if (file_transfer_send_cb) { + LinphoneBuffer *lb = file_transfer_send_cb(msg, msg->file_transfer_information, offset, *size); + if (lb == NULL) { + *size = 0; + } else { + *size = linphone_buffer_get_size(lb); + memcpy(buffer, linphone_buffer_get_content(lb), *size); + linphone_buffer_unref(lb); + } + } else { + // Legacy + linphone_core_notify_file_transfer_send(lc, msg, msg->file_transfer_information, (char *)buffer, size); + } + } + + imee = linphone_core_get_im_encryption_engine(lc); + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); + if (cb_process_uploading_file) { + size_t max_size = *size; + uint8_t *encrypted_buffer = (uint8_t *)ms_malloc0(max_size); + retval = cb_process_uploading_file(imee, msg, offset, (const uint8_t *)buffer, size, encrypted_buffer); + if (retval == 0) { + if (*size > max_size) { + ms_error("IM encryption engine process upload file callback returned a size bigger than the size of the buffer, so it will be truncated !"); + *size = max_size; + } + memcpy(buffer, encrypted_buffer, *size); + } + ms_free(encrypted_buffer); + } + } + + return retval <= 0 ? BELLE_SIP_CONTINUE : BELLE_SIP_STOP; +} + +static void on_send_end(belle_sip_user_body_handler_t *bh, void *data) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); + + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); + if (cb_process_uploading_file) { + cb_process_uploading_file(imee, msg, 0, NULL, NULL, NULL); + } + } +} + +static void file_upload_end_background_task(LinphoneChatMessage *obj){ + if (obj->bg_task_id){ + ms_message("channel [%p]: ending file upload background task with id=[%lx].",obj,obj->bg_task_id); + sal_end_background_task(obj->bg_task_id); + obj->bg_task_id=0; + } +} + +static void file_upload_background_task_ended(LinphoneChatMessage *obj){ + ms_warning("channel [%p]: file upload background task has to be ended now, but work isn't finished.",obj); + file_upload_end_background_task(obj); +} + +static void file_upload_begin_background_task(LinphoneChatMessage *obj){ + if (obj->bg_task_id==0){ + obj->bg_task_id=sal_begin_background_task("file transfer upload",(void (*)(void*))file_upload_background_task_ended, obj); + if (obj->bg_task_id) ms_message("channel [%p]: starting file upload background task with id=[%lx].",obj,obj->bg_task_id); + } +} + +static void linphone_chat_message_process_response_from_post_file(void *data, const belle_http_response_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + + if (msg->http_request && !file_transfer_in_progress_and_valid(msg)) { + ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); + _release_http_request(msg); + return; + } + + // check the answer code + if (event->response) { + int code = belle_http_response_get_status_code(event->response); + if (code == 204) { // this is the reply to the first post to the server - an empty msg + // start uploading the file + belle_sip_multipart_body_handler_t *bh; + char *first_part_header; + belle_sip_body_handler_t *first_part_bh; + + bool_t is_file_encryption_enabled = FALSE; + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(linphone_chat_room_get_core(msg->chat_room)); + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb = + linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(imee_cbs); + if (is_encryption_enabled_for_file_transfer_cb) { + is_file_encryption_enabled = is_encryption_enabled_for_file_transfer_cb(imee, msg->chat_room); + } + } + // shall we encrypt the file + if (is_file_encryption_enabled) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb = + linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs); + if (generate_file_transfer_key_cb) { + generate_file_transfer_key_cb(imee, msg->chat_room, msg); + } + // temporary storage for the Content-disposition header value : use a generic filename to not leak it + // Actual filename stored in msg->file_transfer_information->name will be set in encrypted msg + // sended to the + first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"filename.txt\""); + } else { + // temporary storage for the Content-disposition header value + first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", + linphone_content_get_name(msg->file_transfer_information)); + } + + // create a user body handler to take care of the file and add the content disposition and content-type headers + first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new( + linphone_content_get_size(msg->file_transfer_information), + linphone_chat_message_file_transfer_on_progress, NULL, NULL, + on_send_body, on_send_end, msg); + if (msg->file_transfer_filepath != NULL) { + belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; + first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(msg->file_transfer_filepath, + NULL, msg); // No need to add again the callback for progression, otherwise it will be called twice + linphone_content_set_size(msg->file_transfer_information, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); + belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler); + } else if (linphone_content_get_buffer(msg->file_transfer_information) != NULL) { + first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer( + linphone_content_get_buffer(msg->file_transfer_information), + linphone_content_get_size(msg->file_transfer_information), linphone_chat_message_file_transfer_on_progress, msg); + } + + belle_sip_body_handler_add_header(first_part_bh, + belle_sip_header_create("Content-disposition", first_part_header)); + belle_sip_free(first_part_header); + belle_sip_body_handler_add_header(first_part_bh, + (belle_sip_header_t *)belle_sip_header_content_type_create( + linphone_content_get_type(msg->file_transfer_information), + linphone_content_get_subtype(msg->file_transfer_information))); + + // insert it in a multipart body handler which will manage the boundaries of multipart msg + bh = belle_sip_multipart_body_handler_new(linphone_chat_message_file_transfer_on_progress, msg, first_part_bh, NULL); + + linphone_chat_message_ref(msg); + _release_http_request(msg); + file_upload_begin_background_task(msg); + linphone_chat_room_upload_file(msg); + belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(msg->http_request), BELLE_SIP_BODY_HANDLER(bh)); + linphone_chat_message_unref(msg); + } else if (code == 200) { // file has been uploaded correctly, get server reply and send it + const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); + if (body && strlen(body) > 0) { + // if we have an encryption key for the file, we must insert it into the msg and restore the correct filename + const char *content_key = linphone_content_get_key(msg->file_transfer_information); + size_t content_key_size = linphone_content_get_key_size(msg->file_transfer_information); + if (content_key != NULL) { + // parse the msg body + xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body); + + xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); + if (cur != NULL) { + cur = cur->xmlChildrenNode; + while (cur != NULL) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { // we found a file info node, check + // it has a type="file" attribute + xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); + if (!xmlStrcmp(typeAttribute, + (const xmlChar *)"file")) { // this is the node we are looking for : add a + // file-key children node + xmlNodePtr fileInfoNodeChildren = + cur + ->xmlChildrenNode; // need to parse the children node to update the file-name one + // convert key to base64 + size_t b64Size = b64::b64_encode(NULL, content_key_size, NULL, 0); + char *keyb64 = (char *)ms_malloc0(b64Size + 1); + int xmlStringLength; + + b64Size = b64::b64_encode(content_key, content_key_size, keyb64, b64Size); + keyb64[b64Size] = '\0'; // libxml need a null terminated string + + // add the node containing the key to the file-info node + xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64); + xmlFree(typeAttribute); + ms_free(keyb64); + + // look for the file-name node and update its content + while (fileInfoNodeChildren != NULL) { + if (!xmlStrcmp( + fileInfoNodeChildren->name, + (const xmlChar *)"file-name")) { // we found a the file-name node, update + // its content with the real filename + // update node content + xmlNodeSetContent(fileInfoNodeChildren, + (const xmlChar *)(linphone_content_get_name( + msg->file_transfer_information))); + break; + } + fileInfoNodeChildren = fileInfoNodeChildren->next; + } + + // dump the xml into msg->message + xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&msg->message, &xmlStringLength, + "UTF-8", 0); + + break; + } + xmlFree(typeAttribute); + } + cur = cur->next; + } + } + xmlFreeDoc(xmlMessageBody); + } else { // no encryption key, transfer in plain, just copy the msg sent by server + msg->message = ms_strdup(body); + } + linphone_chat_message_set_content_type(msg, "application/vnd.gsma.rcs-ft-http+xml"); + linphone_chat_message_ref(msg); + linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); + _release_http_request(msg); + L_GET_CPP_PTR_FROM_C_OBJECT(msg->chat_room)->sendMessage(msg); + file_upload_end_background_task(msg); + linphone_chat_message_unref(msg); + } else { + ms_warning("Received empty response from server, file transfer failed"); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); + _release_http_request(msg); + file_upload_end_background_task(msg); + linphone_chat_message_unref(msg); + } + } else { + ms_warning("Unhandled HTTP code response %d for file transfer", code); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); + _release_http_request(msg); + file_upload_end_background_task(msg); + linphone_chat_message_unref(msg); + } + } +} + +static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + LinphoneCore *lc = NULL; + LinphoneImEncryptionEngine *imee = NULL; + int retval = -1; + uint8_t *decrypted_buffer = NULL; + + if (!msg->chat_room) { + linphone_chat_message_cancel_file_transfer(msg); + return; + } + lc = linphone_chat_room_get_core(msg->chat_room); + + if (lc == NULL){ + return; // might happen during linphone_core_destroy() + } + + if (!msg->http_request || belle_http_request_is_cancelled(msg->http_request)) { + ms_warning("Cancelled request for msg [%p], ignoring %s", msg, __FUNCTION__); + return; + } + + // first call may be with a zero size, ignore it + if (size == 0) { + return; + } + + decrypted_buffer = (uint8_t *)ms_malloc0(size); + imee = linphone_core_get_im_encryption_engine(lc); + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); + if (cb_process_downloading_file) { + retval = cb_process_downloading_file(imee, msg, offset, (const uint8_t *)buffer, size, decrypted_buffer); + if (retval == 0) { + memcpy(buffer, decrypted_buffer, size); + } + } + } + ms_free(decrypted_buffer); + + if (retval <= 0) { + if (msg->file_transfer_filepath == NULL) { + if (linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)) { + LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size); + linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)(msg, msg->file_transfer_information, lb); + linphone_buffer_unref(lb); + } else { + // Legacy: call back given by application level + linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, (const char *)buffer, size); + } + } + } else { + ms_warning("File transfer decrypt failed with code %d", (int)retval); + linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError); + } + + return; +} + +static void on_recv_end(belle_sip_user_body_handler_t *bh, void *data) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); + int retval = -1; + + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); + if (cb_process_downloading_file) { + retval = cb_process_downloading_file(imee, msg, 0, NULL, 0, NULL); + } + } + + if (retval <= 0) { + if (msg->file_transfer_filepath == NULL) { + if (linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)) { + LinphoneBuffer *lb = linphone_buffer_new(); + linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)(msg, msg->file_transfer_information, lb); + linphone_buffer_unref(lb); + } else { + // Legacy: call back given by application level + linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, NULL, 0); + } + } + } + + if (retval <= 0 && linphone_chat_message_get_state(msg) != LinphoneChatMessageStateFileTransferError) { + linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); + } +}*/ + +/* + +static int _linphone_chat_room_start_http_transfer(LinphoneChatMessage *msg, const char* url, const char* action, const belle_http_request_listener_callbacks_t *cbs) { + belle_generic_uri_t *uri = NULL; + const char* ua = linphone_core_get_user_agent(linphone_chat_room_get_core(msg->chat_room)); + + if (url == NULL) { + ms_warning("Cannot process file transfer msg: no file remote URI configured."); + goto error; + } + uri = belle_generic_uri_parse(url); + if (uri == NULL || belle_generic_uri_get_host(uri)==NULL) { + ms_warning("Cannot process file transfer msg: incorrect file remote URI configured '%s'.", url); + goto error; + } + + msg->http_request = belle_http_request_create(action, uri, belle_sip_header_create("User-Agent", ua), NULL); + + if (msg->http_request == NULL) { + ms_warning("Could not create http request for uri %s", url); + goto error; + } + // keep a reference to the http request to be able to cancel it during upload + belle_sip_object_ref(msg->http_request); + + // give msg to listener to be able to start the actual file upload when server answer a 204 No content + msg->http_listener = belle_http_request_listener_create_from_callbacks(cbs, linphone_chat_message_ref(msg)); + belle_http_provider_send_request(linphone_chat_room_get_core(msg->chat_room)->http_provider, msg->http_request, msg->http_listener); + return 0; + error: + if (uri) { + belle_sip_object_unref(uri); + } + return -1; + } +*/ + +int ChatMessage::uploadFile() { + return -1; + //TODO + /*belle_http_request_listener_callbacks_t cbs = {0}; + int err; + + if (msg->http_request){ + ms_error("linphone_chat_room_upload_file(): there is already an upload in progress."); + return -1; + } + + cbs.process_response = linphone_chat_message_process_response_from_post_file; + cbs.process_io_error = linphone_chat_message_process_io_error_upload; + cbs.process_auth_requested = linphone_chat_message_process_auth_requested_upload; + err = _linphone_chat_room_start_http_transfer(msg, linphone_core_get_file_transfer_server(linphone_chat_room_get_core(msg->chat_room)), "POST", &cbs); + if (err == -1){ + linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered); + } + return err;*/ +} + +int ChatMessage::downloadFile() { + return -1; + //TODO + /*belle_http_request_listener_callbacks_t cbs = {0}; + int err; + + if (msg->http_request){ + ms_error("linphone_chat_message_download_file(): there is already a download in progress"); + return -1; + } + cbs.process_response_headers = linphone_chat_process_response_headers_from_get_file; + cbs.process_response = linphone_chat_process_response_from_get_file; + cbs.process_io_error = linphone_chat_message_process_io_error_download; + cbs.process_auth_requested = linphone_chat_message_process_auth_requested_download; + err = _linphone_chat_room_start_http_transfer(msg, msg->external_body_url, "GET", &cbs); + if (err == -1) return -1; + // start the download, status is In Progress + linphone_chat_message_set_state(msg, LinphoneChatMessageStateInProgress); + return 0;*/ +} + +void ChatMessage::cancelFileTransfer() { + //TODO + /*if (msg->http_request) { + if (msg->state == LinphoneChatMessageStateInProgress) { + linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered); + } + if (!belle_http_request_is_cancelled(msg->http_request)) { + if (msg->chat_room) { + ms_message("Canceling file transfer %s - msg [%p] chat room[%p]" + , (msg->external_body_url == NULL) ? linphone_core_get_file_transfer_server(linphone_chat_room_get_core(msg->chat_room)) : msg->external_body_url + , msg + , msg->chat_room); + belle_http_provider_cancel_request(linphone_chat_room_get_core(msg->chat_room)->http_provider, msg->http_request); + if ((msg->dir == LinphoneChatMessageOutgoing) && unref) { + // must release it + linphone_chat_message_unref(msg); + } + } else { + ms_message("Warning: http request still running for ORPHAN msg [%p]: this is a memory leak", msg); + } + } + _release_http_request(msg); + } else { + ms_message("No existing file transfer - nothing to cancel"); + }*/ +} + +int ChatMessage::putCharacter(uint32_t character) { + //TODO + /*LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); + if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) { + std::shared_ptr rttcr = + std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); + LinphoneCall *call = rttcr->getCall(); + LinphoneCore *lc = rttcr->getCore(); + const uint32_t new_line = 0x2028; + const uint32_t crlf = 0x0D0A; + const uint32_t lf = 0x0A; + + if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText)) { + return -1; + } + + if (character == new_line || character == crlf || character == lf) { + if (lc && lp_config_get_int(lc->config, "misc", "store_rtt_messages", 1) == 1) { + ms_debug("New line sent, forge a message with content %s", msg->message); + msg->time = ms_time(0); + msg->state = LinphoneChatMessageStateDisplayed; + msg->dir = LinphoneChatMessageOutgoing; + if (msg->from) linphone_address_unref(msg->from); + msg->from = linphone_address_new(linphone_core_get_identity(lc)); + msg->storage_id = linphone_chat_message_store(msg); + ms_free(msg->message); + msg->message = NULL; + } + } else { + char *value = LinphonePrivate::Utils::utf8ToChar(character); + msg->message = ms_strcat_printf(msg->message, value); + ms_debug("Sent RTT character: %s (%lu), pending text is %s", value, (unsigned long)character, msg->message); + delete value; + } + + text_stream_putchar32(reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeText)), character); + return 0; + }*/ + return -1; +} + +// ----------------------------------------------------------------------------- + void ChatMessage::send () { L_D(ChatMessage); diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index c14a4998e..7faa8be72 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -22,6 +22,8 @@ #include #include +#include "imdn.h" +#include "linphone/api/c-types.h" #include "linphone/api/c-chat-message.h" #include "object/object.h" @@ -62,7 +64,24 @@ public: LinphoneChatMessage * getBackPtr(); std::shared_ptr getChatRoom () const; + void setChatRoom (std::shared_ptr cr); + // ----------------------------------------------------------------------------- + // Methods + // ----------------------------------------------------------------------------- + + void updateState(State state); + void reSend(); + void sendImdn(); + void sendDeliveryNotification(); + void sendDisplayNotification(); + int uploadFile(); + int downloadFile(); + void cancelFileTransfer(); + int putCharacter(uint32_t character); + + // ----------------------------------------------------------------------------- + // Getters & setters // ----------------------------------------------------------------------------- Direction getDirection () const; @@ -89,25 +108,50 @@ public: std::string getAppdata () const; void setAppdata (const std::string &appData); + std::shared_ptr
getFromAddress () const; + void setFromAddress(std::shared_ptr
from); + + std::shared_ptr
getToAddress () const; + void setToAddress(std::shared_ptr
to); + + std::string getFileTransferFilepath() const; + void setFileTransferFilepath(const std::string &path); + + bool isToBeStored() const; + void setIsToBeStored(bool store); + // ----------------------------------------------------------------------------- // Deprecated methods, only used for C wrapper // ----------------------------------------------------------------------------- std::string getContentType() const; + void setContentType(std::string contentType); std::string getText() const; + void setText(std::string text); + + std::shared_ptr getFileTransferInformation() const; + void setFileTransferInformation(std::shared_ptr content); unsigned int getStorageId() const; void setStorageId(unsigned int id); void setTime(time_t time); - // ----------------------------------------------------------------------------- + belle_http_request_t *getHttpRequest() const; + void setHttpRequest(belle_http_request_t *request); - std::shared_ptr getFromAddress () const; - std::shared_ptr getToAddress () const; - std::shared_ptr getLocalAddress () const; - std::shared_ptr getRemoteAddress () const; + SalOp *getSalOp() const; + void setSalOp(SalOp *op); + + SalCustomHeader *getSalCustomHeaders() const; + void setSalCustomHeaders(SalCustomHeader *headers); + + void addSalCustomHeader(std::string name, std::string value); + void removeSalCustomHeader(std::string name); + std::string getSalCustomHeaderValue(std::string name); + + // ----------------------------------------------------------------------------- std::shared_ptr getErrorInfo () const; diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 29102a8fb..b04b14841 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -593,7 +593,6 @@ void ChatRoom::compose () { LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { L_D(ChatRoom); LinphoneChatMessage *msg = createMessage(""); - linphone_chat_message_set_chat_room(msg, L_GET_C_BACK_PTR(this)); linphone_chat_message_set_text(msg, NULL); linphone_chat_message_set_file_transfer_information(msg, linphone_content_copy(initialContent)); linphone_chat_message_set_outgoing(msg); @@ -612,7 +611,6 @@ LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent LinphoneChatMessage *ChatRoom::createMessage (const string &message) { shared_ptr chatMessage = make_shared(static_pointer_cast(shared_from_this())); LinphoneChatMessage *msg = chatMessage->getBackPtr(); - linphone_chat_message_set_chat_room(msg, L_GET_C_BACK_PTR(this)); linphone_chat_message_set_state(msg, LinphoneChatMessageStateIdle); linphone_chat_message_set_text(msg, message.empty() ? nullptr : ms_strdup(message.c_str())); linphone_chat_message_set_content_type(msg, ms_strdup("text/plain")); diff --git a/tester/message_tester.c b/tester/message_tester.c index 444010ec3..3b661a342 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -741,7 +741,7 @@ static void file_transfer_2_messages_simultaneously(void) { linphone_chat_room_send_chat_message(pauline_room,msg); linphone_chat_room_send_chat_message(pauline_room,msg2); if (BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1, 60000))) { - msg = linphone_chat_message_clone(marie->stat.last_received_chat_message); + msg = linphone_chat_message_ref(marie->stat.last_received_chat_message); BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,2, 60000)); msg2 = marie->stat.last_received_chat_message; BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_core_get_chat_rooms(marie->lc)), 1, unsigned int, "%u");