Source

Target

Commits (1)
Showing with 175 additions and 81 deletions
......@@ -123,6 +123,8 @@ public:
return isAutoDownloadAttachedFilesHappened;
}
void handleAutoDownload();
belle_http_request_t *getHttpRequest () const;
void setHttpRequest (belle_http_request_t *request);
......
......@@ -543,24 +543,21 @@ void ChatMessagePrivate::notifyReceiving () {
L_Q();
LinphoneChatRoom *chatRoom = static_pointer_cast<ChatRoom>(q->getChatRoom())->getPrivate()->getCChatRoom();
if ((getContentType() != ContentType::Imdn) && (getContentType() != ContentType::ImIsComposing)) {
_linphone_chat_room_notify_chat_message_should_be_stored(chatRoom, L_GET_C_BACK_PTR(q->getSharedFromThis()));
if (toBeStored)
storeInDb();
} else {
if (getContentType() == ContentType::Imdn || getContentType() == ContentType::ImIsComposing) {
// For compatibility, when CPIM is not used
positiveDeliveryNotificationRequired = false;
negativeDeliveryNotificationRequired = false;
displayNotificationRequired = false;
}
shared_ptr<ConferenceChatMessageEvent> event = make_shared<ConferenceChatMessageEvent>(
::time(nullptr), q->getSharedFromThis()
);
_linphone_chat_room_notify_chat_message_received(chatRoom, L_GET_C_BACK_PTR(event));
// Legacy.
AbstractChatRoomPrivate *dChatRoom = q->getChatRoom()->getPrivate();
dChatRoom->notifyChatMessageReceived(q->getSharedFromThis());
static_cast<ChatRoomPrivate *>(dChatRoom)->sendDeliveryNotification(q->getSharedFromThis());
}
......@@ -651,34 +648,6 @@ LinphoneReason ChatMessagePrivate::receive () {
currentRecvStep |= ChatMessagePrivate::Step::FileDownload;
}
if ((currentRecvStep & ChatMessagePrivate::Step::AutoFileDownload) == ChatMessagePrivate::Step::AutoFileDownload) {
lInfo() << "Auto file download step already done, skipping";
} else {
for (Content *c : contents) {
if (c->isFileTransfer()) {
int max_size = linphone_core_get_max_size_for_auto_download_incoming_files(q->getCore()->getCCore());
if (max_size >= 0) {
FileTransferContent *ftc = static_cast<FileTransferContent *>(c);
if (max_size == 0 || ftc->getFileSize() <= (size_t)max_size) {
string downloadPath = q->getCore()->getDownloadPath();
if (!downloadPath.empty()) {
string filepath = downloadPath + ftc->getFileName();
lInfo() << "Downloading file to " << filepath;
ftc->setFilePath(filepath);
setAutoFileTransferDownloadHappened(true);
q->downloadFile(ftc);
return LinphoneReasonNone;
} else {
lError() << "Downloading path is empty, aborting auto download !";
}
}
}
}
}
currentRecvStep |= ChatMessagePrivate::Step::AutoFileDownload;
q->getChatRoom()->getPrivate()->removeTransientChatMessage(q->getSharedFromThis());
}
if (contents.empty()) {
// All previous modifiers only altered the internal content, let's fill the content list
contents.push_back(new Content(internalContent));
......@@ -694,14 +663,27 @@ LinphoneReason ChatMessagePrivate::receive () {
// Remove internal content as it is not needed anymore and will confuse some old methods like getText()
internalContent.setBody("");
internalContent.setContentType(ContentType(""));
// Also remove current step so we go through all modifiers if message is re-sent
// Also remove current step so we go through all modifiers if message is re-received (in case of recursive call from a modifier)
currentRecvStep = ChatMessagePrivate::Step::None;
setState(ChatMessage::State::Delivered);
if (errorCode <= 0 && !isAutoFileTransferDownloadHappened()) {
// if auto download happened and message contains only file transfer,
// the following will state that the content type of the file is unsupported
// Check if this is a duplicate message.
if (chatRoom->findChatMessage(imdnId, direction)) {
lInfo() << "Duplicated SIP MESSAGE, ignored.";
return core->getCCore()->chat_deny_code;
}
if (getContentType() != ContentType::Imdn && getContentType() != ContentType::ImIsComposing) {
_linphone_chat_room_notify_chat_message_should_be_stored(static_pointer_cast<ChatRoom>(q->getChatRoom())->getPrivate()->getCChatRoom(), L_GET_C_BACK_PTR(q->getSharedFromThis()));
if (toBeStored) {
storeInDb();
}
} else {
toBeStored = false;
}
if (errorCode <= 0) {
bool foundSupportContentType = false;
for (Content *c : contents) {
ContentType ct(c->getContentType());
......@@ -710,8 +692,9 @@ LinphoneReason ChatMessagePrivate::receive () {
if (linphone_core_is_content_type_supported(core->getCCore(), contenttype.c_str())) {
foundSupportContentType = true;
break;
} else
lError() << "Unsupported content-type: " << contenttype;
} else {
lError() << "Unsupported content-type: " << contenttype;
}
}
if (!foundSupportContentType) {
......@@ -719,19 +702,11 @@ LinphoneReason ChatMessagePrivate::receive () {
lError() << "No content-type in the contents list is supported...";
}
}
// If auto download failed, reset this flag so the user can normally download the file later
setAutoFileTransferDownloadHappened(false);
// Check if this is in fact an outgoing message (case where this is a message sent by us from an other device).
if (
(chatRoom->getCapabilities() & ChatRoom::Capabilities::Conference) &&
Address(chatRoom->getLocalAddress()).weakEqual(fromAddress)
)
if (chatRoom->getCapabilities() & ChatRoom::Capabilities::Conference && Address(chatRoom->getLocalAddress()).weakEqual(fromAddress)) {
setDirection(ChatMessage::Direction::Outgoing);
// Check if this is a duplicate message.
if (chatRoom->findChatMessage(imdnId, direction))
return core->getCCore()->chat_deny_code;
}
if (errorCode > 0) {
reason = linphone_error_code_to_reason(errorCode);
......@@ -742,14 +717,47 @@ LinphoneReason ChatMessagePrivate::receive () {
return reason;
}
if ((getContentType() == ContentType::ImIsComposing) || (getContentType() == ContentType::Imdn))
toBeStored = false;
chatRoom->getPrivate()->onChatMessageReceived(q->getSharedFromThis());
handleAutoDownload();
return reason;
}
void ChatMessagePrivate::handleAutoDownload() {
L_Q();
if ((currentRecvStep & ChatMessagePrivate::Step::AutoFileDownload) == ChatMessagePrivate::Step::AutoFileDownload) {
lInfo() << "Auto file download step already done, skipping";
} else {
for (Content *c : contents) {
if (c->isFileTransfer()) {
int max_size = linphone_core_get_max_size_for_auto_download_incoming_files(q->getCore()->getCCore());
if (max_size >= 0) {
FileTransferContent *ftc = static_cast<FileTransferContent *>(c);
if (max_size == 0 || ftc->getFileSize() <= (size_t)max_size) {
string downloadPath = q->getCore()->getDownloadPath();
if (!downloadPath.empty()) {
string filepath = downloadPath + ftc->getFileName();
lInfo() << "Downloading file to " << filepath;
ftc->setFilePath(filepath);
setAutoFileTransferDownloadHappened(true);
q->downloadFile(ftc);
return;
} else {
lError() << "Downloading path is empty, aborting auto download !";
}
}
}
}
}
currentRecvStep |= ChatMessagePrivate::Step::AutoFileDownload;
}
q->getChatRoom()->getPrivate()->removeTransientChatMessage(q->getSharedFromThis());
setAutoFileTransferDownloadHappened(false);
q->getChatRoom()->getPrivate()->onChatMessageReceived(q->getSharedFromThis());
return;
}
void ChatMessagePrivate::restoreFileTransferContentAsFileContent() {
// Restore FileContents and remove FileTransferContents
list<Content*>::iterator it = contents.begin();
......@@ -776,6 +784,7 @@ void ChatMessagePrivate::send () {
SalOp *op = salOp;
LinphoneCall *lcall = nullptr;
int errorCode = 0;
bool isResend = state == ChatMessage::State::NotDelivered;
// Remove the sent flag so the message will be sent by the OP in case of resend
currentSendStep &= (unsigned char)~ChatMessagePrivate::Step::Sent;
......@@ -783,8 +792,9 @@ void ChatMessagePrivate::send () {
q->getChatRoom()->getPrivate()->addTransientChatMessage(q->getSharedFromThis());
//imdnId.clear(); //moved into ChatRoomPrivate::sendChatMessage
if (toBeStored && currentSendStep == (ChatMessagePrivate::Step::Started | ChatMessagePrivate::Step::None))
if (toBeStored && currentSendStep == (ChatMessagePrivate::Step::Started | ChatMessagePrivate::Step::None)) {
storeInDb();
}
if ((currentSendStep & ChatMessagePrivate::Step::FileUpload) == ChatMessagePrivate::Step::FileUpload) {
lInfo() << "File upload step already done, skipping";
......@@ -962,6 +972,11 @@ void ChatMessagePrivate::send () {
setIsReadOnly(true);
setState(ChatMessage::State::InProgress);
}
// Do not notify message sent callback when it's a resend
if (!isResend) {
q->getChatRoom()->getPrivate()->onChatMessageSent(q->getSharedFromThis());
}
}
void ChatMessagePrivate::storeInDb () {
......
......@@ -41,6 +41,7 @@ public:
virtual void setState (AbstractChatRoom::State newState) = 0;
virtual void sendChatMessage (const std::shared_ptr<ChatMessage> &chatMessage) = 0;
virtual void onChatMessageSent (const std::shared_ptr<ChatMessage> &chatMessage) = 0;
virtual void addEvent (const std::shared_ptr<EventLog> &eventLog) = 0;
......
......@@ -53,6 +53,7 @@ public:
void setState (ChatRoom::State newState) override;
void sendChatMessage (const std::shared_ptr<ChatMessage> &chatMessage) override;
void onChatMessageSent (const std::shared_ptr<ChatMessage> &chatMessage) override;
void sendIsComposingNotification ();
void addEvent (const std::shared_ptr<EventLog> &eventLog) override;
......
......@@ -52,33 +52,34 @@ void ChatRoomPrivate::sendChatMessage (const shared_ptr<ChatMessage> &chatMessag
L_Q();
ChatMessagePrivate *dChatMessage = chatMessage->getPrivate();
bool isResend = chatMessage->getState() == ChatMessage::State::NotDelivered;
dChatMessage->setTime(ms_time(0));
if (!q->canHandleCpim()) {
//if not using cpim, ImdnMessageId = SIP Message call id, so should be computed each time, specially in case of resend.
dChatMessage->setImdnMessageId("");
}
dChatMessage->send();
}
void ChatRoomPrivate::onChatMessageSent(const shared_ptr<ChatMessage> &chatMessage) {
L_Q();
ChatMessagePrivate *dChatMessage = chatMessage->getPrivate();
LinphoneChatRoom *cr = getCChatRoom();
// TODO: server currently don't stock message, remove condition in the future.
if (!linphone_core_conference_server_enabled(q->getCore()->getCCore())) {
shared_ptr<ConferenceChatMessageEvent> event = static_pointer_cast<ConferenceChatMessageEvent>(
q->getCore()->getPrivate()->mainDb->getEventFromKey(dChatMessage->dbKey)
);
if (!event)
if (!event) {
event = make_shared<ConferenceChatMessageEvent>(time(nullptr), chatMessage);
if (!isResend) {
// Do not notify message sent callback when it's a resend
_linphone_chat_room_notify_chat_message_sent(cr, L_GET_C_BACK_PTR(event));
linphone_core_notify_message_sent(q->getCore()->getCCore(), cr, L_GET_C_BACK_PTR(chatMessage));
}
_linphone_chat_room_notify_chat_message_sent(cr, L_GET_C_BACK_PTR(event));
linphone_core_notify_message_sent(q->getCore()->getCCore(), cr, L_GET_C_BACK_PTR(chatMessage));
}
if (isComposing)
isComposing = false;
if (isComposing) isComposing = false;
isComposingHandler->stopIdleTimer();
isComposingHandler->stopRefreshTimer();
}
......
......@@ -45,6 +45,10 @@ public:
chatRoom->getPrivate()->sendChatMessage(chatMessage);
}
inline void onChatMessageSent (const std::shared_ptr<ChatMessage> &chatMessage) override {
chatRoom->getPrivate()->onChatMessageSent(chatMessage);
}
inline void addEvent (const std::shared_ptr<EventLog> &eventLog) override {
chatRoom->getPrivate()->addEvent(eventLog);
}
......
......@@ -36,6 +36,7 @@ public:
void realtimeTextReceived (uint32_t character, const std::shared_ptr<Call> &call);
void sendChatMessage (const std::shared_ptr<ChatMessage> &chatMessage) override;
void onChatMessageSent (const std::shared_ptr<ChatMessage> &chatMessage) override;
void setCall (const std::shared_ptr<Call> &value) { call = value; }
std::weak_ptr<Call> call;
......
......@@ -66,11 +66,10 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, cons
pendingMessage->getPrivate()->setState(ChatMessage::State::Delivered);
pendingMessage->getPrivate()->setTime(::ms_time(0));
if (lp_config_get_int(linphone_core_get_config(cCore), "misc", "store_rtt_messages", 1) == 1)
pendingMessage->setToBeStored(true);
else
pendingMessage->setToBeStored(false);
if (lp_config_get_int(linphone_core_get_config(cCore), "misc", "store_rtt_messages", 1) == 1) {
pendingMessage->getPrivate()->storeInDb();
}
onChatMessageReceived(pendingMessage);
pendingMessage = nullptr;
receivedRttCharacters.clear();
......@@ -90,17 +89,20 @@ void RealTimeTextChatRoomPrivate::sendChatMessage (const shared_ptr<ChatMessage>
if (call && call->getCurrentParams()->realtimeTextEnabled()) {
uint32_t newLine = 0x2028;
chatMessage->putCharacter(newLine);
}
}
ChatMessagePrivate *dChatMessage = chatMessage->getPrivate();
shared_ptr<ConferenceChatMessageEvent> event = static_pointer_cast<ConferenceChatMessageEvent>(
q->getCore()->getPrivate()->mainDb->getEventFromKey(dChatMessage->dbKey)
);
if (!event)
event = make_shared<ConferenceChatMessageEvent>(time(nullptr), chatMessage);
void RealTimeTextChatRoomPrivate::onChatMessageSent(const shared_ptr<ChatMessage> &chatMessage) {
L_Q();
LinphoneChatRoom *cr = getCChatRoom();
_linphone_chat_room_notify_chat_message_sent(cr, L_GET_C_BACK_PTR(event));
}
ChatMessagePrivate *dChatMessage = chatMessage->getPrivate();
shared_ptr<ConferenceChatMessageEvent> event = static_pointer_cast<ConferenceChatMessageEvent>(
q->getCore()->getPrivate()->mainDb->getEventFromKey(dChatMessage->dbKey)
);
if (!event)
event = make_shared<ConferenceChatMessageEvent>(time(nullptr), chatMessage);
LinphoneChatRoom *cr = getCChatRoom();
_linphone_chat_room_notify_chat_message_sent(cr, L_GET_C_BACK_PTR(event));
}
// =============================================================================
......
......@@ -845,7 +845,7 @@ void FileTransferChatMessageModifier::onRecvEnd (belle_sip_user_body_handler_t *
if (message->getPrivate()->isAutoFileTransferDownloadHappened()) {
releaseHttpRequest();
message->getPrivate()->receive();
message->getPrivate()->handleAutoDownload();
} else {
message->getPrivate()->setState(ChatMessage::State::FileTransferDone);
releaseHttpRequest();
......@@ -954,7 +954,7 @@ void FileTransferChatMessageModifier::onDownloadFailed() {
if (message->getPrivate()->isAutoFileTransferDownloadHappened()) {
message->getPrivate()->doNotRetryAutoDownload();
releaseHttpRequest();
message->getPrivate()->receive();
message->getPrivate()->handleAutoDownload();
} else {
message->getPrivate()->setState(ChatMessage::State::FileTransferError);
releaseHttpRequest();
......
......@@ -823,6 +823,72 @@ static void transfer_message_download_cancelled(void) {
linphone_core_manager_destroy(pauline);
}
static void transfer_message_auto_download_aborted(void) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc");
/* Globally configure an http file transfer server. */
linphone_core_set_file_transfer_server(pauline->lc, file_transfer_url);
/* Enable auto download on marie's Core */
linphone_core_set_max_size_for_auto_download_incoming_files(marie->lc, 0);
/* create a chatroom on pauline's side */
LinphoneChatRoom* chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
LinphoneChatMessage* msg = create_message_from_sintel_trailer(chat_room);
linphone_chat_message_send(msg);
/* wait for marie to receive pauline's msg */
BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneMessageSent, 1, 5000));
linphone_chat_message_unref(msg);
BC_ASSERT_FALSE(wait_for_until(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceivedWithFile, 1, 1000));
linphone_core_manager_restart(marie, TRUE);
BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneFileTransferDownloadSuccessful, 0, int, "%d");
BC_ASSERT_NOT_EQUAL(marie->stat.number_of_LinphoneMessageNotDelivered, 1, int, "%d");
LinphoneChatRoom *marie_cr = linphone_core_get_chat_room(marie->lc, pauline->identity);
LinphoneChatMessage *marie_msg = linphone_chat_room_get_last_message_in_history(marie_cr);
BC_ASSERT_PTR_NOT_NULL(marie_msg);
if (marie_msg) {
const bctbx_list_t *contents = linphone_chat_message_get_contents(marie_msg);
BC_ASSERT_PTR_NOT_NULL(contents);
BC_ASSERT_EQUAL(bctbx_list_size(contents), 1, int, "%d");
LinphoneContent *content = (LinphoneContent *)bctbx_list_get_data(contents);
BC_ASSERT_STRING_EQUAL(linphone_content_get_type(content), "application");
BC_ASSERT_STRING_EQUAL(linphone_content_get_subtype(content), "vnd.gsma.rcs-ft-http+xml");
LinphoneChatMessageState state = linphone_chat_message_get_state(marie_msg);
BC_ASSERT_EQUAL(state, LinphoneChatMessageStateDelivered, int, "%d");
// Auto download isn't resumed automatically, and since the manager restarted the stats are reset
BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageFileTransferInProgress, 0, int, "%d");
char *send_filepath = bc_tester_res("sounds/sintel_trailer_opus_h264.mkv");
char *receive_filepath = bc_tester_file("receive_file.dump");
/* Remove any previously downloaded file */
remove(receive_filepath);
LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(marie_msg);
linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_received);
linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication);
linphone_chat_message_download_file(marie_msg);
BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageFileTransferInProgress, 1, int, "%d");
if (BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneFileTransferDownloadSuccessful, 1, 55000))) {
compare_files(send_filepath, receive_filepath);
}
linphone_chat_message_unref(marie_msg);
bc_free(send_filepath);
bc_free(receive_filepath);
}
linphone_core_manager_destroy(pauline);
linphone_core_manager_destroy(marie);
}
static void file_transfer_2_messages_simultaneously(void) {
if (transport_supported(LinphoneTransportTls)) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
......@@ -2949,6 +3015,7 @@ test_t message_tests[] = {
TEST_NO_TAG("Transfer message with download io error", transfer_message_with_download_io_error),
TEST_NO_TAG("Transfer message upload cancelled", transfer_message_upload_cancelled),
TEST_NO_TAG("Transfer message download cancelled", transfer_message_download_cancelled),
TEST_NO_TAG("Transfer message auto download aborted", transfer_message_auto_download_aborted),
TEST_NO_TAG("Transfer 2 messages simultaneously", file_transfer_2_messages_simultaneously),
TEST_NO_TAG("Transfer using external body URL", file_transfer_using_external_body_url),
TEST_NO_TAG("Transfer using external body URL 2", file_transfer_using_external_body_url_2),
......