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");