From 0ba8441c1d1f799af6b473be714f73d4431caa29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Blin?= <sebastien.blin@savoirfairelinux.com> Date: Tue, 13 Apr 2021 17:00:47 -0400 Subject: [PATCH] swarm: fix build Change-Id: I7e93ecac1639a07b9dd71607b9e7e57493165816 --- src/api/contactmodel.h | 2 +- src/api/conversation.h | 3 +- src/api/datatransfermodel.h | 34 +- src/api/interaction.h | 55 +-- src/authority/storagehelper.cpp | 3 +- src/callbackshandler.cpp | 80 ++++- src/callbackshandler.h | 34 +- src/contactmodel.cpp | 6 +- src/conversationmodel.cpp | 396 +++++++++++++--------- src/datatransfermodel.cpp | 120 ++++--- src/messageslist.cpp | 32 +- src/newaccountmodel.cpp | 2 +- src/qtwrapper/configurationmanager_wrap.h | 93 +++-- src/web-chatview/chatview.js | 53 +-- 14 files changed, 548 insertions(+), 365 deletions(-) diff --git a/src/api/contactmodel.h b/src/api/contactmodel.h index e7cec154..83f43cf9 100644 --- a/src/api/contactmodel.h +++ b/src/api/contactmodel.h @@ -157,7 +157,7 @@ Q_SIGNALS: * @param dringId Daemon's ID for incoming transfer * @param transferInfo DataTransferInfo structure from daemon */ - void newAccountTransfer(DataTransferId dringId, datatransfer::Info info) const; + void newAccountTransfer(const QString& fileId, datatransfer::Info info) const; /** * Connect this signal to know when a contact is banned or unbanned * @param contactUri diff --git a/src/api/conversation.h b/src/api/conversation.h index fe828bf5..dace0784 100644 --- a/src/api/conversation.h +++ b/src/api/conversation.h @@ -72,7 +72,8 @@ struct Info std::map<QString, QString> lastDisplayedMessageUid; unsigned int unreadMessages = 0; - QString getCallId() { return confId.isEmpty() ? callId : confId; } + QString getCallId() const { return confId.isEmpty() ? callId : confId; } + bool isNotASwarm() const { return mode == Mode::NON_SWARM; } Mode mode = Mode::NON_SWARM; bool needsSyncing = false; diff --git a/src/api/datatransfermodel.h b/src/api/datatransfermodel.h index 1e6fadf0..19083559 100644 --- a/src/api/datatransfermodel.h +++ b/src/api/datatransfermodel.h @@ -57,32 +57,32 @@ public: const QString& file_path, const QString& display_name); - void transferInfo(const QString& accountId, - const QString& conversationId, - DataTransferId ringId, - datatransfer::Info& lrc_info); + void transferInfo(const QString& accountId, const QString& fileId, datatransfer::Info& lrc_info); - void bytesProgress(const QString& accountId, - const QString& conversationId, - const QString& interactionId, - int64_t& total, - int64_t& progress); + void fileTransferInfo(const QString& accountId, + const QString& conversationId, + const QString& fileId, + QString& path, + qlonglong& total, + qlonglong& progress); QString accept(const QString& accountId, - const QString& conversationId, - const QString& interactionId, + const QString& fileId, const QString& file_path, std::size_t offset); - void cancel(const QString& accountId, - const QString& conversationId, - const QString& interactionId); + void download(const QString& accountId, + const QString& convId, + const QString& fileId, + const QString& path); - void registerTransferId(DataTransferId dringId, const QString& interactionId); + void cancel(const QString& accountId, const QString& conversationId, const QString& fileId); - QString getInteractionIdFromDringId(DataTransferId dringId); + void registerTransferId(const QString& fileId, const QString& interactionId); - DataTransferId getDringIdFromInteractionId(const QString& interactionId); + QString getInteractionIdFromFileId(const QString& fileId); + + QString getFileIdFromInteractionId(const QString& fileId); /** * Creates APPDATA/received and return the path diff --git a/src/api/interaction.h b/src/api/interaction.h index d78fa9a6..34c17b0e 100644 --- a/src/api/interaction.h +++ b/src/api/interaction.h @@ -172,27 +172,25 @@ to_status(const QString& status) return Status::INVALID; } -enum class ContactAction { - ADD, - JOIN, - LEAVE, - BANNED -}; +enum class ContactAction { ADD, JOIN, LEAVE, BANNED, INVALID }; Q_ENUM_NS(ContactAction) static inline const QString to_string(const ContactAction& action) { switch (action) { - case ContactAction::ADD: - return "ADD"; - case ContactAction::JOIN: - return "JOIN"; - case ContactAction::LEAVE: - return "LEAVE"; - case ContactAction::BANNED: - return "BANNED"; + case ContactAction::ADD: + return "ADD"; + case ContactAction::JOIN: + return "JOIN"; + case ContactAction::LEAVE: + return "LEAVE"; + case ContactAction::BANNED: + return "BANNED"; + case ContactAction::INVALID: + return {}; } + return {}; } static inline ContactAction @@ -204,26 +202,29 @@ to_action(const QString& action) return ContactAction::JOIN; else if (action == "remove") return ContactAction::LEAVE; - else if (action == "baned") + else if (action == "banned") return ContactAction::BANNED; + return ContactAction::INVALID; } static inline QString getContactInteractionString(const QString& authorUri, const ContactAction& action) { switch (action) { - case ContactAction::ADD: - if (authorUri.isEmpty()) { - return QObject::tr("Contact added"); - } - return QObject::tr("Invitation received"); - case ContactAction::JOIN: - return QObject::tr("Invitation accepted"); - case ContactAction::LEAVE: - return QObject::tr("Contact left conversation"); - case ContactAction::BANNED: - return {}; + case ContactAction::ADD: + if (authorUri.isEmpty()) { + return QObject::tr("Contact added"); + } + return QObject::tr("Invitation received"); + case ContactAction::JOIN: + return QObject::tr("Invitation accepted"); + case ContactAction::LEAVE: + return QObject::tr("Contact left conversation"); + case ContactAction::BANNED: + case ContactAction::INVALID: + return {}; } + return {}; } /** @@ -245,6 +246,7 @@ struct Info Type type = Type::INVALID; Status status = Status::INVALID; bool isRead = false; + MapStringString commit; Info() {} @@ -288,6 +290,7 @@ struct Info if (type == Type::CALL) { duration = message["duration"].toInt() / 1000; } + commit = message; } }; diff --git a/src/authority/storagehelper.cpp b/src/authority/storagehelper.cpp index 8c453397..fcdcc0ad 100644 --- a/src/authority/storagehelper.cpp +++ b/src/authority/storagehelper.cpp @@ -509,6 +509,7 @@ addOrUpdateMessage(Database& db, return id; } } + QString addDataTransferToConversation(Database& db, const QString& conversationId, @@ -528,7 +529,7 @@ addDataTransferToConversation(Database& db, {":conversation", convId}, {":timestamp", toQString(std::time(nullptr))}, {":body", infoFromDaemon.path}, - {":type", infoFromDaemon.isOutgoing ? "DATA_TRANSFER" : "DATA_TRANSFER"}, + {":type", "DATA_TRANSFER"}, {":status", "TRANSFER_CREATED"}, {":is_read", "0"}, {":daemon_id", infoFromDaemon.uid}}); diff --git a/src/callbackshandler.cpp b/src/callbackshandler.cpp index 0101b60d..0f912104 100644 --- a/src/callbackshandler.cpp +++ b/src/callbackshandler.cpp @@ -22,6 +22,7 @@ #include "api/account.h" #include "api/lrc.h" #include "api/newaccountmodel.h" +#include "api/datatransfer.h" #include "api/datatransfermodel.h" #include "api/behaviorcontroller.h" @@ -34,6 +35,8 @@ // DRing #include <datatransfer_interface.h> +#include <QFileInfo> + #ifdef ENABLE_LIBWRAP // For the debugMessageReceived connection that queues const std::string refs // when not using dbus @@ -44,6 +47,38 @@ namespace lrc { using namespace api; +static inline datatransfer::Status +convertDataTransferEvent(DRing::DataTransferEventCode event) +{ + switch (event) { + case DRing::DataTransferEventCode::invalid: + return datatransfer::Status::INVALID; + case DRing::DataTransferEventCode::created: + return datatransfer::Status::on_connection; + case DRing::DataTransferEventCode::unsupported: + return datatransfer::Status::unsupported; + case DRing::DataTransferEventCode::wait_peer_acceptance: + return datatransfer::Status::on_connection; + case DRing::DataTransferEventCode::wait_host_acceptance: + return datatransfer::Status::on_connection; + case DRing::DataTransferEventCode::ongoing: + return datatransfer::Status::on_progress; + case DRing::DataTransferEventCode::finished: + return datatransfer::Status::success; + case DRing::DataTransferEventCode::closed_by_host: + return datatransfer::Status::stop_by_host; + case DRing::DataTransferEventCode::closed_by_peer: + return datatransfer::Status::stop_by_peer; + case DRing::DataTransferEventCode::invalid_pathname: + return datatransfer::Status::invalid_pathname; + case DRing::DataTransferEventCode::unjoinable_peer: + return datatransfer::Status::unjoinable_peer; + case DRing::DataTransferEventCode::timeout_expired: + return datatransfer::Status::timeout_expired; + } + throw std::runtime_error("BUG: broken convertDataTransferEvent() switch"); +} + CallbacksHandler::CallbacksHandler(const Lrc& parent) : QObject() , parent(parent) @@ -521,15 +556,34 @@ CallbacksHandler::slotAccountMessageStatusChanged(const QString& accountId, void CallbacksHandler::slotDataTransferEvent(const QString& accountId, const QString& conversationId, - DataTransferId dringId, + const QString&, + const QString& fileId, uint codeStatus) { auto event = DRing::DataTransferEventCode(codeStatus); api::datatransfer::Info info; - parent.getAccountModel() - .getAccountInfo(accountId) - .dataTransferModel->transferInfo(accountId, conversationId, dringId, info); + if (conversationId.isEmpty()) { + parent.getAccountModel().getAccountInfo(accountId).dataTransferModel->transferInfo(accountId, + fileId, + info); + } else { + info.uid = fileId; + info.status = convertDataTransferEvent(event); + info.conversationId = conversationId; + info.accountId = accountId; + qlonglong totalSize, progress; + QString path; + parent.getAccountModel().getAccountInfo(accountId).dataTransferModel->fileTransferInfo( + accountId, conversationId, fileId, path, totalSize, progress); + auto fi = QFileInfo(path); + if (fi.isSymLink()) { + path = fi.symLinkTarget(); + } + info.path = path; + info.totalSize = totalSize; + info.progress = progress; + } // WARNING: info.status could be INVALID in case of async signaling // So listeners must only take account of dringId in such case. @@ -537,33 +591,33 @@ CallbacksHandler::slotDataTransferEvent(const QString& accountId, switch (event) { case DRing::DataTransferEventCode::created: - emit transferStatusCreated(static_cast<DataTransferId>(dringId), info); + emit transferStatusCreated(fileId, info); break; case DRing::DataTransferEventCode::closed_by_host: case DRing::DataTransferEventCode::closed_by_peer: - emit transferStatusCanceled(static_cast<DataTransferId>(dringId), info); + emit transferStatusCanceled(fileId, info); break; case DRing::DataTransferEventCode::wait_peer_acceptance: - emit transferStatusAwaitingPeer(static_cast<DataTransferId>(dringId), info); + emit transferStatusAwaitingPeer(fileId, info); break; case DRing::DataTransferEventCode::wait_host_acceptance: - emit transferStatusAwaitingHost(static_cast<DataTransferId>(dringId), info); + emit transferStatusAwaitingHost(fileId, info); break; case DRing::DataTransferEventCode::ongoing: - emit transferStatusOngoing(static_cast<DataTransferId>(dringId), info); + emit transferStatusOngoing(fileId, info); break; case DRing::DataTransferEventCode::finished: - emit transferStatusFinished(static_cast<DataTransferId>(dringId), info); + emit transferStatusFinished(fileId, info); break; case DRing::DataTransferEventCode::invalid_pathname: case DRing::DataTransferEventCode::unsupported: - emit transferStatusError(static_cast<DataTransferId>(dringId), info); + emit transferStatusError(fileId, info); break; case DRing::DataTransferEventCode::timeout_expired: - emit transferStatusTimeoutExpired(static_cast<DataTransferId>(dringId), info); + emit transferStatusTimeoutExpired(fileId, info); break; case DRing::DataTransferEventCode::unjoinable_peer: - emit transferStatusUnjoinable(static_cast<DataTransferId>(dringId), info); + emit transferStatusUnjoinable(fileId, info); break; case DRing::DataTransferEventCode::invalid: break; diff --git a/src/callbackshandler.h b/src/callbackshandler.h index 0cc689ee..ddfd9f2b 100644 --- a/src/callbackshandler.h +++ b/src/callbackshandler.h @@ -204,15 +204,15 @@ Q_SIGNALS: const QString& messageId, int status); - void transferStatusCreated(DataTransferId dringId, api::datatransfer::Info info); - void transferStatusCanceled(DataTransferId dringId, api::datatransfer::Info info); - void transferStatusAwaitingPeer(DataTransferId dringId, api::datatransfer::Info info); - void transferStatusAwaitingHost(DataTransferId dringId, api::datatransfer::Info info); - void transferStatusOngoing(DataTransferId dringId, api::datatransfer::Info info); - void transferStatusFinished(DataTransferId dringId, api::datatransfer::Info info); - void transferStatusError(DataTransferId dringId, api::datatransfer::Info info); - void transferStatusTimeoutExpired(DataTransferId dringId, api::datatransfer::Info info); - void transferStatusUnjoinable(DataTransferId dringId, api::datatransfer::Info info); + void transferStatusCreated(const QString& fileId, api::datatransfer::Info info); + void transferStatusCanceled(const QString& fileId, api::datatransfer::Info info); + void transferStatusAwaitingPeer(const QString& fileId, api::datatransfer::Info info); + void transferStatusAwaitingHost(const QString& fileId, api::datatransfer::Info info); + void transferStatusOngoing(const QString& fileId, api::datatransfer::Info info); + void transferStatusFinished(const QString& fileId, api::datatransfer::Info info); + void transferStatusError(const QString& fileId, api::datatransfer::Info info); + void transferStatusTimeoutExpired(const QString& fileId, api::datatransfer::Info info); + void transferStatusUnjoinable(const QString& fileId, api::datatransfer::Info info); /** * Connect this signal to get when a device name changed or a device is added @@ -508,12 +508,16 @@ private Q_SLOTS: * @param status, new status for this message */ void slotAccountMessageStatusChanged(const QString& accountId, - const QString& conversationId, - const QString& peer, - const QString& messageId, - int status); - - void slotDataTransferEvent(const QString& accountId, const QString& conversationId, DataTransferId id, uint code); + const QString& conversationId, + const QString& peer, + const QString& messageId, + int status); + + void slotDataTransferEvent(const QString& accountId, + const QString& conversationId, + const QString& interactionId, + const QString& fileId, + uint code); /** * Emit knownDevicesChanged diff --git a/src/contactmodel.cpp b/src/contactmodel.cpp index 341dfb6f..743b50a5 100644 --- a/src/contactmodel.cpp +++ b/src/contactmodel.cpp @@ -194,7 +194,7 @@ public Q_SLOTS: * @param dringId Daemon's ID for incoming transfer * @param transferInfo DataTransferInfo structure from daemon */ - void slotNewAccountTransfer(DataTransferId dringId, datatransfer::Info info); + void slotNewAccountTransfer(const QString& fileId, datatransfer::Info info); /** * Listen from daemon to know when a VCard is received @@ -1125,7 +1125,7 @@ ContactModelPimpl::sipUriReceivedFilter(const QString& uri) } void -ContactModelPimpl::slotNewAccountTransfer(DataTransferId dringId, datatransfer::Info info) +ContactModelPimpl::slotNewAccountTransfer(const QString& fileId, datatransfer::Info info) { if (info.accountId != linked.owner.id) return; @@ -1149,7 +1149,7 @@ ContactModelPimpl::slotNewAccountTransfer(DataTransferId dringId, datatransfer:: emit behaviorController.newTrustRequest(linked.owner.id, info.peerUri); } - emit linked.newAccountTransfer(dringId, info); + emit linked.newAccountTransfer(fileId, info); } void diff --git a/src/conversationmodel.cpp b/src/conversationmodel.cpp index 40c80c85..c00a039e 100644 --- a/src/conversationmodel.cpp +++ b/src/conversationmodel.cpp @@ -199,11 +199,11 @@ public: int conversationIdx, const QString& interactionId); - bool usefulDataFromDataTransfer(DataTransferId dringId, + bool usefulDataFromDataTransfer(const QString& fileId, const datatransfer::Info& info, QString& interactionId, QString& conversationId); - void awaitingHost(DataTransferId dringId, datatransfer::Info info); + void awaitingHost(const QString& fileId, datatransfer::Info info); bool hasOneOneSwarmWith(const QString& participant); @@ -214,6 +214,10 @@ public: * @param final name of the file */ void acceptTransfer(const QString& convUid, const QString& interactionId, const QString& path); + void handleIncomingFile(const QString& convId, + const QString& interactionId, + const QString& displayName, + int totalSize); void addConversationRequest(const MapStringString& convRequest); void addContactRequest(const QString& contactUri); const VectorString peersForConversation(const conversation::Info& conversation) @@ -332,16 +336,16 @@ public Q_SLOTS: const QString& contactUri, bool isComposing); - void slotTransferStatusCreated(DataTransferId dringId, api::datatransfer::Info info); - void slotTransferStatusCanceled(DataTransferId dringId, api::datatransfer::Info info); - void slotTransferStatusAwaitingPeer(DataTransferId dringId, api::datatransfer::Info info); - void slotTransferStatusAwaitingHost(DataTransferId dringId, api::datatransfer::Info info); - void slotTransferStatusOngoing(DataTransferId dringId, api::datatransfer::Info info); - void slotTransferStatusFinished(DataTransferId dringId, api::datatransfer::Info info); - void slotTransferStatusError(DataTransferId dringId, api::datatransfer::Info info); - void slotTransferStatusTimeoutExpired(DataTransferId dringId, api::datatransfer::Info info); - void slotTransferStatusUnjoinable(DataTransferId dringId, api::datatransfer::Info info); - bool updateTransferStatus(DataTransferId dringId, + void slotTransferStatusCreated(const QString& fileId, api::datatransfer::Info info); + void slotTransferStatusCanceled(const QString& fileId, api::datatransfer::Info info); + void slotTransferStatusAwaitingPeer(const QString& fileId, api::datatransfer::Info info); + void slotTransferStatusAwaitingHost(const QString& fileId, api::datatransfer::Info info); + void slotTransferStatusOngoing(const QString& fileId, api::datatransfer::Info info); + void slotTransferStatusFinished(const QString& fileId, api::datatransfer::Info info); + void slotTransferStatusError(const QString& fileId, api::datatransfer::Info info); + void slotTransferStatusTimeoutExpired(const QString& fileId, api::datatransfer::Info info); + void slotTransferStatusUnjoinable(const QString& fileId, api::datatransfer::Info info); + bool updateTransferStatus(const QString& fileId, datatransfer::Info info, interaction::Status newStatus, bool& updated); @@ -587,12 +591,13 @@ ConversationModel::getFilteredConversations(const FilterType& filter, return (owner.profileInfo.type == profile::Type::SIP && !entry.isRequest); case FilterType::REQUEST: return entry.isRequest; + case FilterType::INVALID: default: break; } } catch (...) { - return false; } + return false; }) .validate(); } @@ -616,6 +621,9 @@ ConversationModel::getConversationForPeerUri(const QString& uri) if (!pimpl_->isCoreDialog(conv)) { return false; } + if (conv.mode == conversation::Mode::ONE_TO_ONE) { + return pimpl_->peersForConversation(conv).indexOf(uri) != -1; + } return uri == pimpl_->peersForConversation(conv).front(); }, true)); @@ -1482,6 +1490,9 @@ ConversationModel::acceptConversationRequest(const QString& conversationId) } break; } + case conversation::Mode::ADMIN_INVITES_ONLY: + case conversation::Mode::INVITES_ONLY: + case conversation::Mode::PUBLIC: default: break; } @@ -1904,10 +1915,9 @@ ConversationModelPimpl::peersForConversation(const conversation::Info& conversat default: break; } - for (const auto& participant : conversation.participants) { + for (const auto& participant : conversation.participants) if (participant != linked.owner.profileInfo.uri) result.push_back(participant); - } return result; } @@ -1930,8 +1940,9 @@ ConversationModelPimpl::isCoreDialog(const conversation::Info& conversation) con return true; } default: - return false; + break; } + return false; } bool @@ -2083,7 +2094,7 @@ ConversationModelPimpl::sendContactRequest(const QString& contactUri) linked.owner.contactModel->addContact(contact); } void -ConversationModelPimpl::slotConversationLoaded(uint32_t requestId, +ConversationModelPimpl::slotConversationLoaded(uint32_t, const QString& accountId, const QString& conversationId, const VectorMapStringString& messages) @@ -2108,8 +2119,25 @@ ConversationModelPimpl::slotConversationLoaded(uint32_t requestId, auto msgId = message["id"]; auto msg = interaction::Info(message, linked.owner.profileInfo.uri); if (msg.type == interaction::Type::DATA_TRANSFER) { - auto daemponID = message["tid"]; - storage::updateDataTransferInteractionForDaemonId(db, daemponID, msg); + auto fileId = message["fileId"]; + QString path; + qlonglong bytesProgress, totalSize; + linked.owner.dataTransferModel->fileTransferInfo(accountId, + conversationId, + fileId, + path, + totalSize, + bytesProgress); + QFileInfo fi(path); + if (fi.isSymLink()) { + msg.body = fi.symLinkTarget(); + } else { + msg.body = path; + } + msg.status = bytesProgress == 0 ? interaction::Status::TRANSFER_AWAITING_HOST + : bytesProgress == totalSize ? interaction::Status::TRANSFER_FINISHED + : interaction::Status::TRANSFER_ONGOING; + linked.owner.dataTransferModel->registerTransferId(fileId, msgId); } else if (msg.type == interaction::Type::CALL) { msg.body = storage::getCallInteractionString(msg.authorUri, msg.duration); } @@ -2154,27 +2182,30 @@ ConversationModelPimpl::slotMessageReceived(const QString& accountId, auto msgId = message["id"]; auto msg = interaction::Info(message, linked.owner.profileInfo.uri); api::datatransfer::Info info; - DataTransferId transferIdInt; + QString fileId; + if (msg.type == interaction::Type::DATA_TRANSFER) { // save data transfer interaction to db and assosiate daemon id with interaction id, // conversation id and db id - QString transferId = message["tid"]; - transferIdInt = std::stoull(message["tid"].toStdString()); - linked.owner.dataTransferModel->transferInfo(accountId, - conversationId, - transferIdInt, - info); - // create db entry for valid data transfer - if (info.status != datatransfer::Status::INVALID) { - msg.body = info.path; - msg.status = (info.status == datatransfer::Status::on_connection - && !interaction::isOutgoing(msg)) - ? interaction::Status::TRANSFER_AWAITING_HOST - : interaction::Status::TRANSFER_CREATED; + QString fileId = message["fileId"]; + QString path; + qlonglong bytesProgress, totalSize; + linked.owner.dataTransferModel->fileTransferInfo(accountId, + conversationId, + fileId, + path, + totalSize, + bytesProgress); + QFileInfo fi(path); + if (fi.isSymLink()) { + msg.body = fi.symLinkTarget(); + } else { + msg.body = path; } - auto interactionId = storage::addDataTransferToConversation(db, conversationId, info); - transfIdToDbIntId[transferId] = interactionId; - linked.owner.dataTransferModel->registerTransferId(transferIdInt, msgId); + msg.status = bytesProgress == 0 ? interaction::Status::TRANSFER_AWAITING_HOST + : bytesProgress == totalSize ? interaction::Status::TRANSFER_FINISHED + : interaction::Status::TRANSFER_ONGOING; + linked.owner.dataTransferModel->registerTransferId(fileId, msgId); } else if (msg.type == interaction::Type::CALL) { msg.body = storage::getCallInteractionString(msg.authorUri, msg.duration); } else if (msg.type == interaction::Type::TEXT @@ -2197,7 +2228,10 @@ ConversationModelPimpl::slotMessageReceived(const QString& accountId, emit linked.newInteraction(conversationId, msgId, msg); emit linked.modelChanged(); if (msg.status == interaction::Status::TRANSFER_AWAITING_HOST) { - awaitingHost(transferIdInt, info); + handleIncomingFile(conversationId, + msgId, + message["displayName"], + message["totalSize"].toInt()); } Q_EMIT linked.dataChanged(indexOf(conversationId)); } catch (const std::exception& e) { @@ -2231,7 +2265,7 @@ ConversationModelPimpl::insertSwarmInteraction(const QString& interactionId, void ConversationModelPimpl::slotConversationRequestReceived(const QString& accountId, - const QString& conversationId, + const QString&, const MapStringString& metadatas) { if (accountId != linked.owner.id) { @@ -2267,20 +2301,23 @@ ConversationModelPimpl::slotConversationReady(const QString& accountId, auto& conversation = getConversationForPeerUri(member["uri"]).get(); // remove non swarm conversation if (conversation.mode == conversation::Mode::NON_SWARM) { + Q_EMIT linked.beginRemoveRows(indexOf(conversation.uid)); conversations.erase(conversations.begin() + indexOf(conversation.uid)); storage::removeContact(db, member["uri"]); + Q_EMIT linked.endRemoveRows(); invalidateModel(); emit linked.conversationRemoved(conversation.uid); + emit linked.modelChanged(); } } catch (...) { } } } - Q_EMIT linked.beginInsertRows(conversations.size()); bool conversationExists = indexOf(conversationId) >= 0; if (!conversationExists) { + Q_EMIT linked.beginInsertRows(conversations.size()); addSwarmConversation(conversationId); } auto& conversation = getConversationForUid(conversationId).get(); @@ -2293,10 +2330,16 @@ ConversationModelPimpl::slotConversationReady(const QString& accountId, conversation.mode = conversation::to_mode(details["mode"].toInt()); conversation.isRequest = false; conversation.needsSyncing = false; + emit linked.conversationUpdated(conversationId); + Q_EMIT linked.dataChanged(indexOf(conversationId)); auto id = ConfigurationManager::instance().loadConversationMessages(linked.owner.id, conversationId, "", 0); + auto& peers = peersForConversation(conversation); + if (peers.size() == 1) + emit linked.conversationReady(conversationId, peers.front()); + return; } invalidateModel(); // we use conversationReady callback only for conversation with one participant. We could use @@ -2324,36 +2367,33 @@ ConversationModelPimpl::slotConversationRemoved(const QString& accountId, // we should create non swarm conversation only for removed one-to-one conversation. if (conversation.mode != conversation::Mode::ONE_TO_ONE) { // remove swarm conversation + Q_EMIT linked.beginRemoveRows(conversationIndex); conversations.erase(conversations.begin() + conversationIndex); emit linked.conversationRemoved(conversationId); + Q_EMIT linked.endRemoveRows(); return; } auto& peers = peersForConversation(conversation); if (peers.isEmpty()) { // remove swarm conversation + Q_EMIT linked.beginRemoveRows(conversationIndex); conversations.erase(conversations.begin() + conversationIndex); emit linked.conversationRemoved(conversationId); + Q_EMIT linked.endRemoveRows(); return; } auto contactId = peers.first(); // remove swarm conversation + Q_EMIT linked.beginRemoveRows(conversationIndex); conversations.erase(conversations.begin() + conversationIndex); - auto contact = linked.owner.contactModel->getContact(contactId); - if (contact.profileInfo.type != api::profile::Type::JAMI) { - emit linked.conversationRemoved(conversationId); - return; - } - Q_EMIT linked.beginInsertRows(conversations.size()); + emit linked.conversationRemoved(conversationId); + Q_EMIT linked.endRemoveRows(); auto conv = storage::getConversationsWithPeer(db, contactId); if (conv.empty()) { conv.push_back(storage::beginConversationWithPeer(db, contactId)); } addConversationWith(conv[0], contactId); - invalidateModel(); - emit linked.conversationRemoved(conversationId); emit linked.newConversation(conv[0]); - emit linked.modelChanged(); - Q_EMIT linked.endInsertRows(); } catch (...) { } } @@ -2420,6 +2460,7 @@ ConversationModelPimpl::slotContactAdded(const QString& contactUri) QStringList swarms = ConfigurationManager::instance().getConversations(linked.owner.id); bool needsSyncing = swarms.indexOf(conversation.uid) == -1; if (conversation.needsSyncing != needsSyncing) { + conversation.isRequest = false; conversation.needsSyncing = needsSyncing; invalidateModel(); emit linked.modelChanged(); @@ -2430,8 +2471,14 @@ ConversationModelPimpl::slotContactAdded(const QString& contactUri) conv.push_back(storage::beginConversationWithPeer(db, contactUri)); } // remove temporary conversation that was added when receiving an incoming request - if (indexOf(contactUri) >= 0) { - conversations.erase(conversations.begin() + indexOf(contactUri)); + auto contactIdx = indexOf(contactUri); + if (contactIdx >= 0) { + Q_EMIT linked.beginRemoveRows(contactIdx); + conversations.erase(conversations.begin() + contactIdx); + Q_EMIT linked.endRemoveRows(); + + invalidateModel(); + emit linked.modelChanged(); } // add a conversation if not exists addConversation = indexOf(conv[0]) == -1; @@ -2447,13 +2494,9 @@ ConversationModelPimpl::slotContactAdded(const QString& contactUri) } } if (addConversation) { - Q_EMIT linked.beginInsertRows(conversations.size()); addConversationWith(conv[0], contactUri); - invalidateModel(); emit linked.conversationReady(conv[0], contactUri); emit linked.newConversation(conv[0]); - emit linked.modelChanged(); - Q_EMIT linked.endInsertRows(); } } @@ -2461,7 +2504,7 @@ void ConversationModelPimpl::addContactRequest(const QString& contactUri) { try { - auto& conv = getConversationForPeerUri(contactUri).get(); + getConversationForPeerUri(contactUri).get(); // request from contact already exists, return return; } catch (std::out_of_range&) { @@ -2617,9 +2660,8 @@ ConversationModelPimpl::addSwarmConversation(const QString& convId) for (auto& member : members) { // this check should be removed once all usage of participants replaced by // peersForConversation. We should have ourself in participants list - if (member["uri"] != accountURI) { + if (member["uri"] != accountURI) participants.append(member["uri"]); - } } if (participants.isEmpty()) { return; @@ -2799,7 +2841,7 @@ ConversationModelPimpl::slotIncomingCall(const QString& fromId, const QString& c qDebug() << "Add call to conversation with " << fromId; conversation.callId = callId; - addOrUpdateCallMessage(callId, fromId); + addOrUpdateCallMessage(callId, fromId, true); emit behaviorController.showIncomingCallView(linked.owner.id, conversation.uid); } @@ -3318,7 +3360,7 @@ ConversationModel::acceptTransfer(const QString& convUid, } void -ConversationModel::cancelTransfer(const QString& convUid, const QString& interactionId) +ConversationModel::cancelTransfer(const QString& convUid, const QString& fileId) { // For this action, we change interaction status before effective canceling as daemon will // emit Finished event code immediately (before leaving this method) in non-DBus mode. @@ -3328,13 +3370,13 @@ ConversationModel::cancelTransfer(const QString& convUid, const QString& interac if (conversationIdx != -1) { std::lock_guard<std::mutex> lk(pimpl_->interactionsLocks[convUid]); auto& interactions = pimpl_->conversations[conversationIdx].interactions; - auto it = interactions.find(interactionId); + auto it = interactions.find(fileId); if (it != interactions.end()) { it->second.status = interaction::Status::TRANSFER_CANCELED; // update information in the db storage::updateInteractionStatus(pimpl_->db, - interactionId, + fileId, interaction::Status::TRANSFER_CANCELED); emitUpdated = true; itCopy = it->second; @@ -3344,13 +3386,12 @@ ConversationModel::cancelTransfer(const QString& convUid, const QString& interac // for swarm conversations we need to provide conversation id to accept file, for not swarm // conversations we need peer uri lrc::api::datatransfer::Info info = {}; - getTransferInfo(convUid, interactionId, info); - auto identifier = info.conversationId.isEmpty() ? info.peerUri : convUid; + getTransferInfo(convUid, fileId, info); // Forward cancel action to daemon (will invoke slotTransferStatusCanceled) - owner.dataTransferModel->cancel(owner.id, identifier, interactionId); + owner.dataTransferModel->cancel(owner.id, convUid, fileId); pimpl_->invalidateModel(); - emit interactionStatusUpdated(convUid, interactionId, itCopy); - emit pimpl_->behaviorController.newReadInteraction(owner.id, convUid, interactionId); + emit interactionStatusUpdated(convUid, fileId, itCopy); + emit pimpl_->behaviorController.newReadInteraction(owner.id, convUid, fileId); } } @@ -3359,15 +3400,24 @@ ConversationModel::getTransferInfo(const QString& conversationId, const QString& interactionId, datatransfer::Info& info) { - try { - auto dringId = pimpl_->linked.owner.dataTransferModel->getDringIdFromInteractionId( - interactionId); - pimpl_->linked.owner.dataTransferModel->transferInfo(owner.id, - conversationId, - dringId, - info); - } catch (...) { - info.status = datatransfer::Status::INVALID; + auto convOpt = getConversationForUid(conversationId); + if (!convOpt) + return; + auto fileId = owner.dataTransferModel->getFileIdFromInteractionId(interactionId); + if (convOpt->get().mode == conversation::Mode::NON_SWARM) { + try { + owner.dataTransferModel->transferInfo(owner.id, fileId, info); + } catch (...) { + info.status = datatransfer::Status::INVALID; + } + } else { + QString path; + qlonglong bytesProgress, totalSize; + owner.dataTransferModel + ->fileTransferInfo(owner.id, conversationId, fileId, path, totalSize, bytesProgress); + info.path = path; + info.totalSize = totalSize; + info.progress = bytesProgress; } } @@ -3378,7 +3428,7 @@ ConversationModel::getNumberOfUnreadMessagesFor(const QString& convUid) } bool -ConversationModelPimpl::usefulDataFromDataTransfer(DataTransferId dringId, +ConversationModelPimpl::usefulDataFromDataTransfer(const QString& fileId, const datatransfer::Info& info, QString& interactionId, QString& conversationId) @@ -3386,19 +3436,19 @@ ConversationModelPimpl::usefulDataFromDataTransfer(DataTransferId dringId, if (info.accountId != linked.owner.id) return false; try { - interactionId = linked.owner.dataTransferModel->getInteractionIdFromDringId(dringId); + interactionId = linked.owner.dataTransferModel->getInteractionIdFromFileId(fileId); conversationId = info.conversationId.isEmpty() ? storage::conversationIdFromInteractionId(db, interactionId) : info.conversationId; } catch (const std::out_of_range& e) { - qWarning() << "Couldn't get interaction from daemon Id: " << dringId; + qWarning() << "Couldn't get interaction from daemon Id: " << fileId; return false; } return true; } void -ConversationModelPimpl::slotTransferStatusCreated(DataTransferId dringId, datatransfer::Info info) +ConversationModelPimpl::slotTransferStatusCreated(const QString& fileId, datatransfer::Info info) { // check if transfer is for the current account if (info.accountId != linked.owner.id) @@ -3428,8 +3478,8 @@ ConversationModelPimpl::slotTransferStatusCreated(DataTransferId dringId, datatr const auto& convId = convIds[0]; auto interactionId = storage::addDataTransferToConversation(db, convId, info); - // map dringId and interactionId for latter retrivial from client (that only known the interactionId) - linked.owner.dataTransferModel->registerTransferId(dringId, interactionId); + // map fileId and interactionId for latter retrivial from client (that only known the interactionId) + linked.owner.dataTransferModel->registerTransferId(fileId, interactionId); auto interaction = interaction::Info {info.isOutgoing ? "" : info.peerUri, info.isOutgoing ? info.path : info.displayName, @@ -3464,22 +3514,22 @@ ConversationModelPimpl::slotTransferStatusCreated(DataTransferId dringId, datatr } void -ConversationModelPimpl::slotTransferStatusAwaitingPeer(DataTransferId dringId, +ConversationModelPimpl::slotTransferStatusAwaitingPeer(const QString& fileId, datatransfer::Info info) { if (info.accountId != linked.owner.id) return; bool intUpdated; - updateTransferStatus(dringId, info, interaction::Status::TRANSFER_AWAITING_PEER, intUpdated); + updateTransferStatus(fileId, info, interaction::Status::TRANSFER_AWAITING_PEER, intUpdated); } void -ConversationModelPimpl::slotTransferStatusAwaitingHost(DataTransferId dringId, +ConversationModelPimpl::slotTransferStatusAwaitingHost(const QString& fileId, datatransfer::Info info) { if (info.accountId != linked.owner.id) return; - awaitingHost(dringId, info); + awaitingHost(fileId, info); } bool @@ -3494,18 +3544,18 @@ ConversationModelPimpl::hasOneOneSwarmWith(const QString& participant) } void -ConversationModelPimpl::awaitingHost(DataTransferId dringId, datatransfer::Info info) +ConversationModelPimpl::awaitingHost(const QString& fileId, datatransfer::Info info) { if (info.accountId != linked.owner.id) return; QString interactionId; QString conversationId; - if (not usefulDataFromDataTransfer(dringId, info, interactionId, conversationId)) + if (not usefulDataFromDataTransfer(fileId, info, interactionId, conversationId)) return; bool intUpdated; - if (!updateTransferStatus(dringId, + if (!updateTransferStatus(fileId, info, interaction::Status::TRANSFER_AWAITING_HOST, intUpdated)) { @@ -3527,11 +3577,22 @@ ConversationModelPimpl::awaitingHost(DataTransferId dringId, datatransfer::Info return; } } + handleIncomingFile(conversationId, interactionId, info.displayName, info.totalSize); +} + +void +ConversationModelPimpl::handleIncomingFile(const QString& convId, + const QString& interactionId, + const QString& displayName, + int totalSize) +{ // If it's an accepted file type and less than 20 MB, accept transfer. if (linked.owner.dataTransferModel->automaticAcceptTransfer) { if (linked.owner.dataTransferModel->acceptBehindMb == 0 - || info.totalSize < linked.owner.dataTransferModel->acceptBehindMb * 1024 * 1024) { - acceptTransfer(conversationId, interactionId, info.displayName); + || (totalSize > 0 + && static_cast<unsigned>(totalSize) + < linked.owner.dataTransferModel->acceptBehindMb * 1024 * 1024)) { + acceptTransfer(convId, interactionId, displayName); } } } @@ -3554,48 +3615,79 @@ ConversationModelPimpl::acceptTransfer(const QString& convUid, if (!dir.exists()) dir.mkpath("."); auto& conversation = getConversationForUid(convUid).get(); - // for swarm conversation we need converstion id to accept file and for not swarm participant uri - auto identifier = conversation.mode != conversation::Mode::NON_SWARM - ? convUid - : peersForConversation(conversation).front(); - auto acceptedFilePath = linked.owner.dataTransferModel->accept(linked.owner.id, - identifier, - interactionId, - destinationDir + path, - 0); - auto dringId = linked.owner.dataTransferModel->getDringIdFromInteractionId(interactionId); - if (transfIdToDbIntId.find(QString::number(dringId)) != transfIdToDbIntId.end()) { - auto dbInteractionId = transfIdToDbIntId[QString::number(dringId)]; - storage::updateInteractionBody(db, dbInteractionId, acceptedFilePath); - storage::updateInteractionStatus(db, - dbInteractionId, - interaction::Status::TRANSFER_ACCEPTED); - } else { - storage::updateInteractionBody(db, interactionId, acceptedFilePath); - storage::updateInteractionStatus(db, interactionId, interaction::Status::TRANSFER_ACCEPTED); - } - // prepare interaction Info and emit signal for the client - auto conversationIdx = indexOf(convUid); - interaction::Info itCopy; - bool emitUpdated = false; - if (conversationIdx != -1) { - std::lock_guard<std::mutex> lk(interactionsLocks[convUid]); - auto& interactions = conversations[conversationIdx].interactions; - auto it = interactions.find(interactionId); - if (it != interactions.end()) { - it->second.body = acceptedFilePath; - it->second.status = interaction::Status::TRANSFER_ACCEPTED; - emitUpdated = true; - itCopy = it->second; + if (conversation.mode == conversation::Mode::NON_SWARM) { + auto acceptedFilePath = linked.owner.dataTransferModel->accept(linked.owner.id, + interactionId, + destinationDir + path, + 0); + auto fileId = linked.owner.dataTransferModel->getFileIdFromInteractionId(interactionId); + if (transfIdToDbIntId.find(fileId) != transfIdToDbIntId.end()) { + auto dbInteractionId = transfIdToDbIntId[fileId]; + storage::updateInteractionBody(db, dbInteractionId, acceptedFilePath); + storage::updateInteractionStatus(db, + dbInteractionId, + interaction::Status::TRANSFER_ACCEPTED); + } else { + storage::updateInteractionBody(db, interactionId, acceptedFilePath); + storage::updateInteractionStatus(db, + interactionId, + interaction::Status::TRANSFER_ACCEPTED); } + // prepare interaction Info and emit signal for the client + auto conversationIdx = indexOf(convUid); + interaction::Info itCopy; + bool emitUpdated = false; + if (conversationIdx != -1) { + std::lock_guard<std::mutex> lk(interactionsLocks[convUid]); + auto& interactions = conversations[conversationIdx].interactions; + auto it = interactions.find(interactionId); + if (it != interactions.end()) { + it->second.body = acceptedFilePath; + it->second.status = interaction::Status::TRANSFER_ACCEPTED; + emitUpdated = true; + itCopy = it->second; + } + } + if (emitUpdated) { + if (isCoreDialog(conversations[conversationIdx])) { + sendContactRequest(peersForConversation(conversations[conversationIdx]).front()); + } + invalidateModel(); + emit linked.interactionStatusUpdated(convUid, interactionId, itCopy); + emit behaviorController.newReadInteraction(linked.owner.id, convUid, interactionId); + } + return; } - if (emitUpdated) { - if (isCoreDialog(conversations[conversationIdx])) { - sendContactRequest(peersForConversation(conversations[conversationIdx]).front()); + + auto interaction = conversation.interactions.find(interactionId); + if (interaction != conversation.interactions.end()) { + auto displayName = interaction->second.commit["displayName"]; + auto fileId = interaction->second.commit["fileId"]; + if (fileId.isEmpty()) { + qWarning() << "Cannot download file without fileId"; } - invalidateModel(); - emit linked.interactionStatusUpdated(convUid, interactionId, itCopy); - emit behaviorController.newReadInteraction(linked.owner.id, convUid, interactionId); + if (displayName.isEmpty()) { + displayName = interactionId; + } + int i = 0; + auto path = destinationDir + displayName; + do { + if (i > 0) { + path = destinationDir + QString::number(i) + displayName; + } + QFileInfo fi(path); + if (!fi.isFile()) + break; + ++i; + + } while (i < 1000); + if (i == 1000) { + qWarning() << "Too much duplicates for " << destinationDir << path; + return; + } + linked.owner.dataTransferModel->download(linked.owner.id, convUid, fileId, path); + } else { + qWarning() << "Cannot download file without valid interaction"; } } @@ -3607,17 +3699,17 @@ ConversationModelPimpl::invalidateModel() } void -ConversationModelPimpl::slotTransferStatusOngoing(DataTransferId dringId, datatransfer::Info info) +ConversationModelPimpl::slotTransferStatusOngoing(const QString& fileId, datatransfer::Info info) { if (info.accountId != linked.owner.id) return; QString interactionId; QString conversationId; - if (not usefulDataFromDataTransfer(dringId, info, interactionId, conversationId)) + if (not usefulDataFromDataTransfer(fileId, info, interactionId, conversationId)) return; bool intUpdated; - if (!updateTransferStatus(dringId, info, interaction::Status::TRANSFER_ONGOING, intUpdated)) { + if (!updateTransferStatus(fileId, info, interaction::Status::TRANSFER_ONGOING, intUpdated)) { return; } if (!intUpdated) { @@ -3632,13 +3724,13 @@ ConversationModelPimpl::slotTransferStatusOngoing(DataTransferId dringId, datatr } void -ConversationModelPimpl::slotTransferStatusFinished(DataTransferId dringId, datatransfer::Info info) +ConversationModelPimpl::slotTransferStatusFinished(const QString& fileId, datatransfer::Info info) { if (info.accountId != linked.owner.id) return; QString interactionId; QString conversationId; - if (not usefulDataFromDataTransfer(dringId, info, interactionId, conversationId)) + if (not usefulDataFromDataTransfer(fileId, info, interactionId, conversationId)) return; // prepare interaction Info and emit signal for the client auto conversationIdx = indexOf(conversationId); @@ -3663,65 +3755,65 @@ ConversationModelPimpl::slotTransferStatusFinished(DataTransferId dringId, datat if (emitUpdated) { invalidateModel(); if (conversations[conversationIdx].mode != conversation::Mode::NON_SWARM) { - if (transfIdToDbIntId.find(QString::number(dringId)) != transfIdToDbIntId.end()) { - auto dbIntId = transfIdToDbIntId[QString::number(dringId)]; + if (transfIdToDbIntId.find(fileId) != transfIdToDbIntId.end()) { + auto dbIntId = transfIdToDbIntId[fileId]; storage::updateInteractionStatus(db, dbIntId, newStatus); } } else { storage::updateInteractionStatus(db, interactionId, newStatus); } emit linked.interactionStatusUpdated(conversationId, interactionId, itCopy); - transfIdToDbIntId.remove(QString::number(dringId)); + transfIdToDbIntId.remove(fileId); } } } void -ConversationModelPimpl::slotTransferStatusCanceled(DataTransferId dringId, datatransfer::Info info) +ConversationModelPimpl::slotTransferStatusCanceled(const QString& fileId, datatransfer::Info info) { if (info.accountId != linked.owner.id) return; bool intUpdated; - updateTransferStatus(dringId, info, interaction::Status::TRANSFER_CANCELED, intUpdated); + updateTransferStatus(fileId, info, interaction::Status::TRANSFER_CANCELED, intUpdated); } void -ConversationModelPimpl::slotTransferStatusError(DataTransferId dringId, datatransfer::Info info) +ConversationModelPimpl::slotTransferStatusError(const QString& fileId, datatransfer::Info info) { if (info.accountId != linked.owner.id) return; bool intUpdated; - updateTransferStatus(dringId, info, interaction::Status::TRANSFER_ERROR, intUpdated); + updateTransferStatus(fileId, info, interaction::Status::TRANSFER_ERROR, intUpdated); } void -ConversationModelPimpl::slotTransferStatusUnjoinable(DataTransferId dringId, datatransfer::Info info) +ConversationModelPimpl::slotTransferStatusUnjoinable(const QString& fileId, datatransfer::Info info) { if (info.accountId != linked.owner.id) return; bool intUpdated; - updateTransferStatus(dringId, info, interaction::Status::TRANSFER_UNJOINABLE_PEER, intUpdated); + updateTransferStatus(fileId, info, interaction::Status::TRANSFER_UNJOINABLE_PEER, intUpdated); } void -ConversationModelPimpl::slotTransferStatusTimeoutExpired(DataTransferId dringId, +ConversationModelPimpl::slotTransferStatusTimeoutExpired(const QString& fileId, datatransfer::Info info) { if (info.accountId != linked.owner.id) return; bool intUpdated; - updateTransferStatus(dringId, info, interaction::Status::TRANSFER_TIMEOUT_EXPIRED, intUpdated); + updateTransferStatus(fileId, info, interaction::Status::TRANSFER_TIMEOUT_EXPIRED, intUpdated); } bool -ConversationModelPimpl::updateTransferStatus(DataTransferId dringId, +ConversationModelPimpl::updateTransferStatus(const QString& fileId, datatransfer::Info info, interaction::Status newStatus, bool& updated) { QString interactionId; QString conversationId; - if (not usefulDataFromDataTransfer(dringId, info, interactionId, conversationId)) { + if (not usefulDataFromDataTransfer(fileId, info, interactionId, conversationId)) { return false; } @@ -3729,13 +3821,7 @@ ConversationModelPimpl::updateTransferStatus(DataTransferId dringId, if (conversationIdx < 0) { return false; } - if (conversations[conversationIdx].mode != conversation::Mode::NON_SWARM) { - if (transfIdToDbIntId.find(QString::number(dringId)) == transfIdToDbIntId.end()) { - return false; - } - auto dbIntId = transfIdToDbIntId[QString::number(dringId)]; - storage::updateInteractionStatus(db, dbIntId, newStatus); - } else { + if (conversations[conversationIdx].mode == conversation::Mode::NON_SWARM) { storage::updateInteractionStatus(db, interactionId, newStatus); } bool emitUpdated = false; diff --git a/src/datatransfermodel.cpp b/src/datatransfermodel.cpp index c691cb56..11a55c93 100644 --- a/src/datatransfermodel.cpp +++ b/src/datatransfermodel.cpp @@ -82,8 +82,8 @@ public: QString getUniqueFilePath(const QString& filename); DataTransferModel& upLink; - std::map<DataTransferId, QString> dring2lrcIdMap; - std::map<QString, DataTransferId> lrc2dringIdMap; // stricly the reverse map of dring2lrcIdMap + MapStringString file2InteractionId; + MapStringString interactionToFileId; // stricly the reverse map of file2InteractionId }; DataTransferModel::Impl::Impl(DataTransferModel& up_link) @@ -113,11 +113,11 @@ DataTransferModel::Impl::getUniqueFilePath(const QString& filename) } void -DataTransferModel::registerTransferId(DataTransferId dringId, const QString& interactionId) +DataTransferModel::registerTransferId(const QString& fileId, const QString& interactionId) { - pimpl_->dring2lrcIdMap.emplace(dringId, interactionId); - pimpl_->lrc2dringIdMap.erase(interactionId); // Because a file transfer can be retried - pimpl_->lrc2dringIdMap.emplace(interactionId, dringId); + pimpl_->file2InteractionId[fileId] = interactionId; + pimpl_->interactionToFileId.remove(interactionId); // Because a file transfer can be retried + pimpl_->interactionToFileId[interactionId] = fileId; } DataTransferModel::DataTransferModel() @@ -129,17 +129,12 @@ DataTransferModel::~DataTransferModel() = default; void DataTransferModel::transferInfo(const QString& accountId, - const QString& conversationId, - DataTransferId ringId, + const QString& fileId, datatransfer::Info& lrc_info) { DataTransferInfo infoFromDaemon; - if (ConfigurationManager::instance().dataTransferInfo(accountId, - conversationId, - ringId, - infoFromDaemon) - == 0) { - lrc_info.uid = QString::number(ringId); + if (ConfigurationManager::instance().dataTransferInfo(accountId, fileId, infoFromDaemon) == 0) { + lrc_info.uid = fileId; lrc_info.status = convertDataTransferEvent( DRing::DataTransferEventCode(infoFromDaemon.lastEvent)); lrc_info.isOutgoing = !(infoFromDaemon.flags @@ -159,89 +154,92 @@ DataTransferModel::transferInfo(const QString& accountId, } void -DataTransferModel::sendFile(const QString& account_id, +DataTransferModel::sendFile(const QString& accountId, const QString& peer_uri, const QString& conversationId, - const QString& file_path, - const QString& display_name) + const QString& filePath, + const QString& displayName) { - DataTransferInfo info; + if (conversationId.isEmpty()) { + // Fallback + DataTransferInfo info; #ifdef ENABLE_LIBWRAP - DRing::DataTransferId id; + DRing::DataTransferId id; #else - qulonglong id; + qulonglong id; #endif - info.accountId = account_id; - info.peer = peer_uri; - info.path = file_path; - info.conversationId = conversationId; - info.displayName = display_name; - info.bytesProgress = 0; - if (ConfigurationManager::instance().sendFile(info, id) != 0) { - qDebug() << "DataTransferModel::sendFile(), error"; + info.accountId = accountId; + info.peer = peer_uri; + info.path = filePath; + info.conversationId = conversationId; + info.displayName = displayName; + info.bytesProgress = 0; + if (ConfigurationManager::instance().sendFileLegacy(info, id) != 0) + qWarning() << "DataTransferModel::sendFile(), error"; return; } + + ConfigurationManager::instance().sendFile(accountId, + conversationId, + filePath, + displayName, + {} /* TODO parent */); } void -DataTransferModel::bytesProgress(const QString& accountId, - const QString& conversationId, - const QString& interactionId, - int64_t& total, - int64_t& progress) +DataTransferModel::fileTransferInfo(const QString& accountId, + const QString& conversationId, + const QString& fileId, + QString& path, + qlonglong& total, + qlonglong& progress) { ConfigurationManager::instance() -#ifdef ENABLE_LIBWRAP - .dataTransferBytesProgress(accountId, - conversationId, - pimpl_->lrc2dringIdMap.at(interactionId), - total, - progress); -#else - .dataTransferBytesProgress(accountId, - conversationId, - pimpl_->lrc2dringIdMap.at(interactionId), - reinterpret_cast<qlonglong&>(total), - reinterpret_cast<qlonglong&>(progress)); -#endif + .fileTransferInfo(accountId, conversationId, fileId, path, total, progress); } QString DataTransferModel::accept(const QString& accountId, - const QString& conversationId, - const QString& interactionId, + const QString& fileId, const QString& file_path, std::size_t offset) { auto unique_file_path = pimpl_->getUniqueFilePath(file_path); - auto dring_id = pimpl_->lrc2dringIdMap.at(interactionId); - ConfigurationManager::instance().acceptFileTransfer(accountId, - conversationId, - dring_id, - unique_file_path, - offset); + auto dring_id = pimpl_->interactionToFileId[fileId]; + ConfigurationManager::instance().acceptFileTransfer(accountId, dring_id, unique_file_path); return unique_file_path; } +void +DataTransferModel::download(const QString& accountId, + const QString& convId, + const QString& fileId, + const QString& path) +{ + ConfigurationManager::instance().downloadFile(accountId, convId, fileId, path); +} + void DataTransferModel::cancel(const QString& accountId, const QString& conversationId, const QString& interactionId) { - auto dring_id = pimpl_->lrc2dringIdMap.at(interactionId); - ConfigurationManager::instance().cancelDataTransfer(accountId, conversationId, dring_id); + qWarning() << "@@@ " << accountId << " - " << conversationId << " - " << interactionId; + ConfigurationManager::instance().cancelDataTransfer(accountId, + conversationId, + getFileIdFromInteractionId(interactionId)); } QString -DataTransferModel::getInteractionIdFromDringId(DataTransferId dringId) +DataTransferModel::getInteractionIdFromFileId(const QString& fileId) { - return pimpl_->dring2lrcIdMap.at(dringId); + return pimpl_->file2InteractionId[fileId]; } -DataTransferId -DataTransferModel::getDringIdFromInteractionId(const QString& interactionId) +QString +DataTransferModel::getFileIdFromInteractionId(const QString& interactionId) { - return pimpl_->lrc2dringIdMap.at(interactionId); + return pimpl_->interactionToFileId[interactionId]; } QString diff --git a/src/messageslist.cpp b/src/messageslist.cpp index 6fdc88ba..795b6bbc 100644 --- a/src/messageslist.cpp +++ b/src/messageslist.cpp @@ -79,21 +79,24 @@ MessagesList::erase(QString msgId) return 1; } } + return 0; } + interaction::Info& MessagesList::operator[](QString messageId) { for (auto it = interactions_.cbegin(); it != interactions_.cend(); ++it) { - if (it->first == messageId) { - return const_cast<interaction::Info&>(it->second); - } - } - // element not find, add it to the end - interaction::Info newMessage = {}; - interactions_.insert(interactions_.end(), qMakePair(messageId, newMessage)); - if (interactions_.last().first == messageId) { - return const_cast<interaction::Info&>(interactions_.last().second); - } + if (it->first == messageId) { + return const_cast<interaction::Info&>(it->second); + } + } + // element not find, add it to the end + interaction::Info newMessage = {}; + interactions_.insert(interactions_.end(), qMakePair(messageId, newMessage)); + if (interactions_.last().first == messageId) { + return const_cast<interaction::Info&>(interactions_.last().second); + } + throw std::out_of_range("Cannot find message"); } iterator @@ -200,15 +203,14 @@ int MessagesList::indexOfMessage(QString msgId, bool reverse) const { auto getIndex = [reverse, &msgId](const auto& start, const auto& end) -> int { - auto it = std::find_if(start, end, [&msgId] (const auto& it) { return it.first == msgId; }); + auto it = std::find_if(start, end, [&msgId](const auto& it) { return it.first == msgId; }); if (it == end) { return -1; } - return reverse ? std::distance(it, end) - 1 : std::distance(start, it); + return reverse ? std::distance(it, end) - 1 : std::distance(start, it); }; - return reverse ? - getIndex(interactions_.rbegin(), interactions_.rend()) : - getIndex(interactions_.begin(), interactions_.end()); + return reverse ? getIndex(interactions_.rbegin(), interactions_.rend()) + : getIndex(interactions_.begin(), interactions_.end()); } void diff --git a/src/newaccountmodel.cpp b/src/newaccountmodel.cpp index fe644aa6..344299d3 100644 --- a/src/newaccountmodel.cpp +++ b/src/newaccountmodel.cpp @@ -482,7 +482,7 @@ NewAccountModelPimpl::updateAccountDetails(account::Info& accountInfo) // Fill account::Info::confProperties credentials VectorMapStringString credGet = ConfigurationManager::instance().getCredentials(accountInfo.id); VectorMapStringString credToStore; - for (auto const& i : credGet.toStdVector()) { + for (auto const& i : std::vector<MapStringString>(credGet.begin(), credGet.end())) { MapStringString credMap; for (auto const& j : i.toStdMap()) { credMap[j.first] = j.second; diff --git a/src/qtwrapper/configurationmanager_wrap.h b/src/qtwrapper/configurationmanager_wrap.h index 7a833ab9..25412ec0 100644 --- a/src/qtwrapper/configurationmanager_wrap.h +++ b/src/qtwrapper/configurationmanager_wrap.h @@ -259,11 +259,13 @@ public: exportable_callback<DataTransferSignal::DataTransferEvent>( [this](const std::string& accountId, const std::string& conversationId, - const uint64_t& transfer_id, + const std::string& interactionId, + const std::string& fileId, const uint32_t& code) { Q_EMIT this->dataTransferEvent(QString(accountId.c_str()), QString(conversationId.c_str()), - transfer_id, + QString(interactionId.c_str()), + QString(fileId.c_str()), code); }), }; @@ -325,6 +327,17 @@ public Q_SLOTS: // METHODS return temp; } + void downloadFile(const QString& accountId, + const QString& convId, + const QString& fileId, + const QString& path) + { + DRing::downloadFile(accountId.toStdString(), + convId.toStdString(), + fileId.toStdString(), + path.toStdString()); + } + bool exportOnRing(const QString& accountID, const QString& password) { return DRing::exportOnRing(accountID.toStdString(), password.toStdString()); @@ -794,7 +807,7 @@ public Q_SLOTS: // METHODS return convertMap(DRing::getContactDetails(accountID.toStdString(), uri.toStdString())); } - uint32_t sendFile(const DataTransferInfo& lrc_info, DRing::DataTransferId& id) + uint32_t sendFileLegacy(const DataTransferInfo& lrc_info, DRing::DataTransferId& id) { DRing::DataTransferInfo dring_info; dring_info.accountId = lrc_info.accountId.toStdString(); @@ -807,19 +820,27 @@ public Q_SLOTS: // METHODS dring_info.displayName = lrc_info.displayName.toStdString(); dring_info.path = lrc_info.path.toStdString(); dring_info.mimetype = lrc_info.mimetype.toStdString(); - return uint32_t(DRing::sendFile(dring_info, id)); + return uint32_t(DRing::sendFileLegacy(dring_info, id)); } - uint32_t dataTransferInfo(QString accountId, - QString conversationId, - const DRing::DataTransferId& transfer_id, - DataTransferInfo& lrc_info) + void sendFile(const QString& accountId, + const QString& conversationId, + const QString& filePath, + const QString& fileDisplayName, + const QString& parent) + { + DRing::sendFile(accountId.toStdString(), + conversationId.toStdString(), + filePath.toStdString(), + fileDisplayName.toStdString(), + parent.toStdString()); + } + + uint32_t dataTransferInfo(QString accountId, QString transfer_id, DataTransferInfo& lrc_info) { DRing::DataTransferInfo dring_info; - auto error = uint32_t(DRing::dataTransferInfo(accountId.toStdString(), - conversationId.toStdString(), - transfer_id, - dring_info)); + auto error = uint32_t( + DRing::dataTransferInfo(accountId.toStdString(), transfer_id.toStdString(), dring_info)); lrc_info.accountId = QString::fromStdString(dring_info.accountId); lrc_info.lastEvent = quint32(dring_info.lastEvent); lrc_info.flags = dring_info.flags; @@ -833,39 +854,36 @@ public Q_SLOTS: // METHODS return error; } - uint64_t dataTransferBytesProgress(QString accountId, - QString conversationId, - const DRing::DataTransferId& transfer_id, - int64_t& total, - int64_t& progress) - { - return uint32_t(DRing::dataTransferBytesProgress(accountId.toStdString(), - conversationId.toStdString(), - transfer_id, - total, - progress)); + uint64_t fileTransferInfo(QString accountId, + QString conversationId, + QString fileId, + QString& path, + int64_t& total, + int64_t& progress) + { + std::string pathstr; + auto result = uint32_t(DRing::fileTransferInfo(accountId.toStdString(), + conversationId.toStdString(), + fileId.toStdString(), + pathstr, + total, + progress)); + path = pathstr.c_str(); + return result; } - uint32_t acceptFileTransfer(QString accountId, - QString conversationId, - const DRing::DataTransferId& transfer_id, - const QString& file_path, - int64_t offset) + uint32_t acceptFileTransfer(QString accountId, const QString& fileId, const QString& file_path) { return uint32_t(DRing::acceptFileTransfer(accountId.toStdString(), - conversationId.toStdString(), - transfer_id, - file_path.toStdString(), - offset)); + fileId.toStdString(), + file_path.toStdString())); } - uint32_t cancelDataTransfer(QString accountId, - QString conversationId, - const DRing::DataTransferId& transfer_id) + uint32_t cancelDataTransfer(QString accountId, QString conversationId, QString transfer_id) { return uint32_t(DRing::cancelDataTransfer(accountId.toStdString(), conversationId.toStdString(), - transfer_id)); + transfer_id.toStdString())); } void enableProxyClient(const QString& accountID, bool enable) @@ -1068,7 +1086,8 @@ Q_SIGNALS: // SIGNALS void profileReceived(const QString& accountID, const QString& peer, const QString& vCard); void dataTransferEvent(const QString& accountId, const QString& conversationId, - DataTransferId transfer_id, + const QString& interactionId, + const QString& fileId, uint code); void deviceRevocationEnded(const QString& accountId, const QString& deviceId, int status); void accountProfileReceived(const QString& accountId, diff --git a/src/web-chatview/chatview.js b/src/web-chatview/chatview.js index 311d50a7..4fe5b26d 100644 --- a/src/web-chatview/chatview.js +++ b/src/web-chatview/chatview.js @@ -24,6 +24,8 @@ var historyBuffer = [] // If we use qt var use_qt = false +var is_swarm = false + if (navigator.userAgent == "jami-windows") { use_qt = true } @@ -185,6 +187,11 @@ function init_picker(dark) { }); } +/* exported set_is_swarm */ +function set_is_swarm(value) { + is_swarm = value +} + function set_titles() { if (use_qt){ backButton.title = i18nStringData["Hide chat view"] @@ -951,14 +958,14 @@ function humanFileSize(bytes) { */ function updateProgressBar(progress_bar, message_object) { var delivery_status = message_object["delivery_status"] - if ("progress" in message_object && !isErrorStatus(delivery_status) && message_object["progress"] !== 100) { + if (delivery_status === "ongoing" && "progress" in message_object && message_object["progress"] !== 100) { var progress_percent = (100 * message_object["progress"] / message_object["totalSize"]) if (progress_percent !== 100) - progress_bar.childNodes[0].setAttribute("style", "width: " + progress_percent + "%") + progress_bar.childNodes[0].setAttribute("style", "display: block; width: " + progress_percent + "%") else - progress_bar.setAttribute("style", "display: none") + progress_bar.setAttribute("style", "display: none;") } else - progress_bar.setAttribute("style", "display: none") + progress_bar.setAttribute("style", "display: none;") } /** @@ -976,7 +983,7 @@ function isErrorStatus(status) { * Build a new file interaction * @param message_id */ -function fileInteraction(message_id, message_direction) { +function fileInteraction(message_id) { var message_wrapper = document.createElement("div") message_wrapper.setAttribute("class", "message_wrapper") @@ -1030,6 +1037,7 @@ function fileInteraction(message_id, message_direction) { var message_transfer_progress_completion = document.createElement("span") message_transfer_progress_bar.appendChild(message_transfer_progress_completion) message_wrapper.appendChild(message_transfer_progress_bar) + message_transfer_progress_completion.setAttribute("style", "display: none;") const internal_mes_wrapper = document.createElement("div") internal_mes_wrapper.setAttribute("class", "internal_mes_wrapper") @@ -1105,6 +1113,9 @@ function updateFileInteraction(message_div, message_object, forceTypeToFile = fa refuseSvg = "<svg height=\"24\" viewBox=\"0 0 24 24\" width=\"24\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/><path d=\"M0 0h24v24H0z\" fill=\"none\"/></svg>", fileSvg = "<svg class=\"filesvg\" height=\"24\" viewBox=\"0 0 24 24\" width=\"24\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M16.5 6v11.5c0 2.21-1.79 4-4 4s-4-1.79-4-4V5c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5v10.5c0 .55-.45 1-1 1s-1-.45-1-1V6H10v9.5c0 1.38 1.12 2.5 2.5 2.5s2.5-1.12 2.5-2.5V5c0-2.21-1.79-4-4-4S7 2.79 7 5v12.5c0 3.04 2.46 5.5 5.5 5.5s5.5-2.46 5.5-5.5V6h-1.5z\"/><path d=\"M0 0h24v24H0z\" fill=\"none\"/></svg>", warningSvg = "<svg class=\"filesvg\" height=\"24\" viewBox=\"0 0 24 24\" width=\"24\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M0 0h24v24H0z\" fill=\"none\"/><path d=\"M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z\"/></svg>" + if (is_swarm) { + acceptSvg = "<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 0 24 24\" width=\"24px\"><path d=\"M0 0h24v24H0z\" fill=\"none\"/><path d=\"M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z\"/></svg>" + } var message_delivery_status = message_object["delivery_status"] var message_direction = message_object["direction"] var message_id = message_object["id"] @@ -1129,7 +1140,7 @@ function updateFileInteraction(message_div, message_object, forceTypeToFile = fa media_wrapper.parentNode.removeChild(media_wrapper) } - var new_interaction = fileInteraction(message_id, message_direction) + var new_interaction = fileInteraction(message_id) var new_message_wrapper = new_interaction.querySelector(".message_wrapper") wrapper.prepend(new_message_wrapper) updateFileInteraction(message_div, message_object, true) @@ -1281,19 +1292,22 @@ function updateFileInteraction(message_div, message_object, forceTypeToFile = fa left_buttons.appendChild(accept_button) } - var refuse_button = document.createElement("div") - refuse_button.innerHTML = refuseSvg - refuse_button.setAttribute("title", use_qt ? i18nStringData["Refuse"] : - i18n.gettext("Refuse")) - refuse_button.setAttribute("class", "flat-button refuse") - refuse_button.onclick = function () { - if (use_qt) { - window.jsbridge.refuseFile(message_id) - } else { - window.prompt(`REFUSE_FILE:${message_id}`) + if (!is_swarm || message_delivery_status.indexOf("ongoing") === 0)Â { + var refuse_button = document.createElement("div") + refuse_button.innerHTML = refuseSvg + refuse_button.setAttribute("title", use_qt ? i18nStringData["Refuse"] : + i18n.gettext("Refuse")) + refuse_button.setAttribute("class", "flat-button refuse") + refuse_button.onclick = function () { + if (use_qt) { + window.jsbridge.refuseFile(message_id) + } else { + window.prompt(`REFUSE_FILE:${message_id}`) + } } + left_buttons.appendChild(refuse_button) } - left_buttons.appendChild(refuse_button) + } else { var status_button = document.createElement("div") var statusFile = fileSvg @@ -1665,7 +1679,7 @@ function buildNewMessage(message_object) { media_wrapper.parentNode.removeChild(media_wrapper) } - var new_interaction = fileInteraction(message_id, message_direction) + var new_interaction = fileInteraction(message_id) var new_message_wrapper = new_interaction.querySelector(".message_wrapper") wrapper.prepend(new_message_wrapper) updateFileInteraction(message_div, message_object, true) @@ -1674,7 +1688,8 @@ function buildNewMessage(message_object) { message_div.querySelector("img").id = message_id message_div.querySelector("img").msg_obj = message_object } else { - message_div.append(fileInteraction(message_id, message_direction)) + message_div.append(fileInteraction(message_id)) + updateProgressBar(message_div.querySelector(".message_progress_bar"), message_object) } } else if (message_type === "text") { // TODO add the possibility to update messages (remove and rebuild) -- GitLab