diff --git a/res/io.github.qtox.qTox.appdata.xml b/res/io.github.qtox.qTox.appdata.xml index e901f29b0..69335fd36 100644 --- a/res/io.github.qtox.qTox.appdata.xml +++ b/res/io.github.qtox.qTox.appdata.xml @@ -63,6 +63,10 @@ https://qtox.github.io barrdetwix@gmail.com qTox + + intense + intense + diff --git a/src/core/corefile.cpp b/src/core/corefile.cpp index b2d90f005..81d10cb8c 100644 --- a/src/core/corefile.cpp +++ b/src/core/corefile.cpp @@ -95,9 +95,9 @@ void CoreFile::sendAvatarFile(uint32_t friendId, const QByteArray& data) uint8_t *file_id = nullptr; uint8_t *file_name = nullptr; size_t nameLength = 0; + uint8_t avatarHash[TOX_HASH_LENGTH]; if (!data.isEmpty()) { static_assert(TOX_HASH_LENGTH <= TOX_FILE_ID_LENGTH, "TOX_HASH_LENGTH > TOX_FILE_ID_LENGTH!"); - uint8_t avatarHash[TOX_HASH_LENGTH]; tox_hash(avatarHash, (uint8_t*)data.data(), data.size()); filesize = data.size(); file_id = avatarHash; diff --git a/src/model/chatroom/friendchatroom.cpp b/src/model/chatroom/friendchatroom.cpp index 79f06a63f..d97d4d148 100644 --- a/src/model/chatroom/friendchatroom.cpp +++ b/src/model/chatroom/friendchatroom.cpp @@ -22,6 +22,7 @@ #include "src/model/dialogs/idialogsmanager.h" #include "src/model/friend.h" #include "src/model/group.h" +#include "src/model/status.h" #include "src/persistence/settings.h" #include "src/widget/contentdialog.h" @@ -67,7 +68,7 @@ void FriendChatroom::setActive(bool _active) bool FriendChatroom::canBeInvited() const { - return frnd->isOnline(); + return Status::isOnline(frnd->getStatus()); } int FriendChatroom::getCircleId() const diff --git a/src/model/chatroom/groupchatroom.cpp b/src/model/chatroom/groupchatroom.cpp index 3efeb8669..3c8327948 100644 --- a/src/model/chatroom/groupchatroom.cpp +++ b/src/model/chatroom/groupchatroom.cpp @@ -25,6 +25,7 @@ #include "src/model/dialogs/idialogsmanager.h" #include "src/model/friend.h" #include "src/model/group.h" +#include "src/model/status.h" #include "src/persistence/settings.h" GroupChatroom::GroupChatroom(Group* group, IDialogsManager* dialogsManager) @@ -64,7 +65,7 @@ void GroupChatroom::inviteFriend(const ToxPk& pk) const Friend* frnd = FriendList::findFriend(pk); const auto friendId = frnd->getId(); const auto groupId = group->getId(); - const auto canInvite = frnd->isOnline(); + const auto canInvite = Status::isOnline(frnd->getStatus()); if (canInvite) { Core::getInstance()->groupInviteFriend(friendId, groupId); diff --git a/src/model/friend.cpp b/src/model/friend.cpp index 08f80dadf..c34058e18 100644 --- a/src/model/friend.cpp +++ b/src/model/friend.cpp @@ -152,8 +152,15 @@ bool Friend::getEventFlag() const void Friend::setStatus(Status::Status s) { if (friendStatus != s) { + auto oldStatus = friendStatus; friendStatus = s; emit statusChanged(friendPk, friendStatus); + if (!Status::isOnline(oldStatus) && Status::isOnline(friendStatus)) { + emit onlineOfflineChanged(friendPk, true); + } else if (Status::isOnline(oldStatus) && !Status::isOnline(friendStatus)) { + emit onlineOfflineChanged(friendPk, false); + } + } } @@ -162,11 +169,6 @@ Status::Status Friend::getStatus() const return friendStatus; } -bool Friend::isOnline() const -{ - return friendStatus != Status::Status::Offline && friendStatus != Status::Status::Blocked; -} - bool Friend::useHistory() const { return true; diff --git a/src/model/friend.h b/src/model/friend.h index 7cc6bf7cf..46f1c08d8 100644 --- a/src/model/friend.h +++ b/src/model/friend.h @@ -53,14 +53,13 @@ public: void setStatus(Status::Status s); Status::Status getStatus() const; - bool isOnline() const; - bool useHistory() const final; signals: void nameChanged(const ToxPk& friendId, const QString& name); void aliasChanged(const ToxPk& friendId, QString alias); void statusChanged(const ToxPk& friendId, Status::Status status); + void onlineOfflineChanged(const ToxPk& friendId, bool isOnline); void statusMessageChanged(const ToxPk& friendId, const QString& message); void loadChatHistory(); diff --git a/src/model/friendmessagedispatcher.cpp b/src/model/friendmessagedispatcher.cpp index 803b4645c..9a7a10cc6 100644 --- a/src/model/friendmessagedispatcher.cpp +++ b/src/model/friendmessagedispatcher.cpp @@ -19,6 +19,7 @@ #include "friendmessagedispatcher.h" #include "src/persistence/settings.h" +#include "src/model/status.h" namespace { @@ -49,7 +50,7 @@ FriendMessageDispatcher::FriendMessageDispatcher(Friend& f_, MessageProcessor pr , offlineMsgEngine(&f_, &messageSender_) , processor(std::move(processor_)) { - connect(&f, &Friend::statusChanged, this, &FriendMessageDispatcher::onFriendStatusChange); + connect(&f, &Friend::onlineOfflineChanged, this, &FriendMessageDispatcher::onFriendOnlineOfflineChanged); } /** @@ -69,7 +70,7 @@ FriendMessageDispatcher::sendMessage(bool isAction, const QString& content) bool messageSent = false; - if (f.isOnline()) { + if (Status::isOnline(f.getStatus())) { messageSent = sendMessageToCore(messageSender, f, message, receipt); } @@ -107,9 +108,9 @@ void FriendMessageDispatcher::onReceiptReceived(ReceiptNum receipt) * @brief Handles status change for friend * @note Parameters just to fit slot api */ -void FriendMessageDispatcher::onFriendStatusChange(const ToxPk&, Status::Status) +void FriendMessageDispatcher::onFriendOnlineOfflineChanged(const ToxPk&, bool isOnline) { - if (f.isOnline()) { + if (isOnline) { offlineMsgEngine.deliverOfflineMsgs(); } } diff --git a/src/model/friendmessagedispatcher.h b/src/model/friendmessagedispatcher.h index 74b210916..63efe5e13 100644 --- a/src/model/friendmessagedispatcher.h +++ b/src/model/friendmessagedispatcher.h @@ -44,7 +44,7 @@ public: void onReceiptReceived(ReceiptNum receipt); void clearOutgoingMessages(); private slots: - void onFriendStatusChange(const ToxPk& key, Status::Status status); + void onFriendOnlineOfflineChanged(const ToxPk& key, bool isOnline); private: Friend& f; diff --git a/src/model/status.cpp b/src/model/status.cpp index 292ad97c3..50220126a 100644 --- a/src/model/status.cpp +++ b/src/model/status.cpp @@ -75,4 +75,9 @@ namespace Status return ":/img/status/" + statusSuffix + eventSuffix + ".svg"; } } + + bool isOnline(Status status) + { + return status != Status::Offline && status != Status::Blocked; + } } // namespace Status diff --git a/src/model/status.h b/src/model/status.h index b80c014cf..5ee11664e 100644 --- a/src/model/status.h +++ b/src/model/status.h @@ -38,6 +38,7 @@ namespace Status QString getIconPath(Status status, bool event = false); QString getTitle(Status status); QString getAssetSuffix(Status status); + bool isOnline(Status status); } #endif // STATUS_H diff --git a/src/persistence/history.cpp b/src/persistence/history.cpp index 4822b0274..d641e8cbd 100644 --- a/src/persistence/history.cpp +++ b/src/persistence/history.cpp @@ -195,10 +195,11 @@ bool dbSchema3to4(RawDatabase& db) /** * @brief Upgrade the db schema +* @return True if the schema upgrade succeded, false otherwise * @note On future alterations of the database all you have to do is bump the SCHEMA_VERSION * variable and add another case to the switch statement below. Make sure to fall through on each case. */ -void dbSchemaUpgrade(std::shared_ptr& db) +bool dbSchemaUpgrade(std::shared_ptr& db) { int64_t databaseSchemaVersion; @@ -206,19 +207,17 @@ void dbSchemaUpgrade(std::shared_ptr& db) databaseSchemaVersion = row[0].toLongLong(); }))) { qCritical() << "History failed to read user_version"; - db.reset(); - return; + return false; } if (databaseSchemaVersion > SCHEMA_VERSION) { qWarning().nospace() << "Database version (" << databaseSchemaVersion << ") is newer than we currently support (" << SCHEMA_VERSION << "). Please upgrade qTox"; // We don't know what future versions have done, we have to disable db access until we re-upgrade - db.reset(); - return; + return false; } else if (databaseSchemaVersion == SCHEMA_VERSION) { // No work to do - return; + return true; } switch (databaseSchemaVersion) { @@ -231,22 +230,19 @@ void dbSchemaUpgrade(std::shared_ptr& db) const bool newDb = isNewDb(db, success); if (!success) { qCritical() << "Failed to create current db schema"; - db.reset(); - return; + return false; } if (newDb) { if (!createCurrentSchema(*db)) { qCritical() << "Failed to create current db schema"; - db.reset(); - return; + return false; } qDebug() << "Database created at schema version" << SCHEMA_VERSION; break; // new db is the only case where we don't incrementally upgrade through each version } else { if (!dbSchema0to1(*db)) { qCritical() << "Failed to upgrade db to schema version 1, aborting"; - db.reset(); - return; + return false; } qDebug() << "Database upgraded incrementally to schema version 1"; } @@ -255,23 +251,20 @@ void dbSchemaUpgrade(std::shared_ptr& db) case 1: if (!dbSchema1to2(*db)) { qCritical() << "Failed to upgrade db to schema version 2, aborting"; - db.reset(); - return; + return false; } qDebug() << "Database upgraded incrementally to schema version 2"; //fallthrough case 2: if (!dbSchema2to3(*db)) { qCritical() << "Failed to upgrade db to schema version 3, aborting"; - db.reset(); - return; + return false; } qDebug() << "Database upgraded incrementally to schema version 3"; case 3: if (!dbSchema3to4(*db)) { qCritical() << "Failed to upgrade db to schema version 4, aborting"; - db.reset(); - return; + return false; } qDebug() << "Database upgraded incrementally to schema version 4"; // etc. @@ -279,6 +272,8 @@ void dbSchemaUpgrade(std::shared_ptr& db) qInfo() << "Database upgrade finished (databaseSchemaVersion" << databaseSchemaVersion << "->" << SCHEMA_VERSION << ")"; } + + return true; } MessageState getMessageState(bool isPending, bool isBroken) @@ -318,18 +313,19 @@ FileDbInsertionData::FileDbInsertionData() * @brief Prepares the database to work with the history. * @param db This database will be prepared for use with the history. */ -History::History(std::shared_ptr db) - : db(db) +History::History(std::shared_ptr db_) + : db(db_) { if (!isValid()) { qWarning() << "Database not open, init failed"; return; } - dbSchemaUpgrade(db); + const auto upgradeSucceeded = dbSchemaUpgrade(db); // dbSchemaUpgrade may have put us in an invalid state - if (!isValid()) { + if (!upgradeSucceeded) { + db.reset(); return; } @@ -370,6 +366,10 @@ bool History::isValid() */ bool History::historyExists(const ToxPk& friendPk) { + if (historyAccessBlocked()) { + return false; + } + return !getMessagesForFriend(friendPk, 0, 1).empty(); } @@ -588,6 +588,10 @@ void History::addNewFileMessage(const QString& friendPk, const QString& fileId, const QString& fileName, const QString& filePath, int64_t size, const QString& sender, const QDateTime& time, QString const& dispName) { + if (historyAccessBlocked()) { + return; + } + // This is an incredibly far from an optimal way of implementing this, // but given the frequency that people are going to be initiating a file // transfer we can probably live with it. @@ -644,11 +648,7 @@ void History::addNewMessage(const QString& friendPk, const QString& message, con const QDateTime& time, bool isDelivered, QString dispName, const std::function& insertIdCallback) { - if (!Settings::getInstance().getEnableLogging()) { - qWarning() << "Blocked a message from being added to database while history is disabled"; - return; - } - if (!isValid()) { + if (historyAccessBlocked()) { return; } @@ -659,6 +659,10 @@ void History::addNewMessage(const QString& friendPk, const QString& message, con void History::setFileFinished(const QString& fileId, bool success, const QString& filePath, const QByteArray& fileHash) { + if (historyAccessBlocked()) { + return; + } + auto& fileInfo = fileInfos[fileId]; if (fileInfo.fileId.get() == -1) { fileInfo.finished = true; @@ -674,11 +678,19 @@ void History::setFileFinished(const QString& fileId, bool success, const QString size_t History::getNumMessagesForFriend(const ToxPk& friendPk) { + if (historyAccessBlocked()) { + return 0; + } + return getNumMessagesForFriendBeforeDate(friendPk, QDateTime()); } size_t History::getNumMessagesForFriendBeforeDate(const ToxPk& friendPk, const QDateTime& date) { + if (historyAccessBlocked()) { + return 0; + } + QString queryText = QString("SELECT COUNT(history.id) " "FROM history " "JOIN peers chat ON chat_id = chat.id " @@ -704,6 +716,10 @@ size_t History::getNumMessagesForFriendBeforeDate(const ToxPk& friendPk, const Q QList History::getMessagesForFriend(const ToxPk& friendPk, size_t firstIdx, size_t lastIdx) { + if (historyAccessBlocked()) { + return {}; + } + QList messages; // Don't forget to update the rowCallback if you change the selected columns! @@ -763,6 +779,10 @@ QList History::getMessagesForFriend(const ToxPk& friendPk, QList History::getUndeliveredMessagesForFriend(const ToxPk& friendPk) { + if (historyAccessBlocked()) { + return {}; + } + auto queryText = QString("SELECT history.id, faux_offline_pending.id, timestamp, chat.public_key, " "aliases.display_name, sender.public_key, message, broken_messages.id " @@ -809,6 +829,10 @@ QList History::getUndeliveredMessagesForFriend(const ToxPk QDateTime History::getDateWhereFindPhrase(const QString& friendPk, const QDateTime& from, QString phrase, const ParameterSearch& parameter) { + if (historyAccessBlocked()) { + return QDateTime(); + } + QDateTime result; auto rowCallback = [&result](const QVector& row) { result = QDateTime::fromMSecsSinceEpoch(row[0].toLongLong()); @@ -903,6 +927,10 @@ QList History::getNumMessagesForFriendBeforeDateBoundaries(con const QDate& from, size_t maxNum) { + if (historyAccessBlocked()) { + return {}; + } + auto friendPkString = friendPk.toString(); // No guarantee that this is the most efficient way to do this... @@ -954,9 +982,29 @@ QList History::getNumMessagesForFriendBeforeDateBoundaries(con */ void History::markAsDelivered(RowId messageId) { - if (!isValid()) { + if (historyAccessBlocked()) { return; } db->execLater(QString("DELETE FROM faux_offline_pending WHERE id=%1;").arg(messageId.get())); } + +/** +* @brief Determines if history access should be blocked +* @return True if history should not be accessed +*/ +bool History::historyAccessBlocked() +{ + if (!Settings::getInstance().getEnableLogging()) { + assert(false); + qCritical() << "Blocked history access while history is disabled"; + return true; + } + + if (!isValid()) { + return true; + } + + return false; + +} diff --git a/src/persistence/history.h b/src/persistence/history.h index 9c5b10cba..b2b04cfc4 100644 --- a/src/persistence/history.h +++ b/src/persistence/history.h @@ -201,6 +201,7 @@ private slots: void onFileInserted(RowId dbId, QString fileId); private: + bool historyAccessBlocked(); static RawDatabase::Query generateFileFinished(RowId fileId, bool success, const QString& filePath, const QByteArray& fileHash); std::shared_ptr db; diff --git a/src/persistence/offlinemsgengine.cpp b/src/persistence/offlinemsgengine.cpp index b1cff673b..6026145bf 100644 --- a/src/persistence/offlinemsgengine.cpp +++ b/src/persistence/offlinemsgengine.cpp @@ -23,6 +23,7 @@ #include "src/nexus.h" #include "src/persistence/profile.h" #include "src/persistence/settings.h" +#include "src/model/status.h" #include #include #include @@ -91,7 +92,7 @@ void OfflineMsgEngine::deliverOfflineMsgs() { QMutexLocker ml(&mutex); - if (!f->isOnline()) { + if (!Status::isOnline(f->getStatus())) { return; } @@ -138,8 +139,8 @@ void OfflineMsgEngine::removeAllMessages() void OfflineMsgEngine::completeMessage(QMap::iterator msgIt) { msgIt->completionFn(); - sentMessages.erase(msgIt); receivedReceipts.removeOne(msgIt.key()); + sentMessages.erase(msgIt); } void OfflineMsgEngine::checkForCompleteMessages(ReceiptNum receipt) diff --git a/src/widget/about/aboutfriendform.cpp b/src/widget/about/aboutfriendform.cpp index 9a1d36cc0..0ac94de13 100644 --- a/src/widget/about/aboutfriendform.cpp +++ b/src/widget/about/aboutfriendform.cpp @@ -92,7 +92,7 @@ void AboutFriendForm::onAutoAcceptDirClicked() void AboutFriendForm::onAutoAcceptDirChanged(const QString& path) { - const bool enabled = path.isNull(); + const bool enabled = !path.isNull(); ui->autoacceptfile->setChecked(enabled); ui->selectSaveDir->setEnabled(enabled); ui->selectSaveDir->setText(enabled ? path : tr("Auto-accept for this contact is disabled")); diff --git a/src/widget/form/chatform.cpp b/src/widget/form/chatform.cpp index 992f7e234..acd2997db 100644 --- a/src/widget/form/chatform.cpp +++ b/src/widget/form/chatform.cpp @@ -404,7 +404,7 @@ void ChatForm::updateCallButtons() CoreAV* av = Core::getInstance()->getAv(); const bool audio = av->isCallActive(f); const bool video = av->isCallVideoEnabled(f); - const bool online = f->isOnline(); + const bool online = Status::isOnline(f->getStatus()); headWidget->updateCallButtons(online, audio, video); updateMuteMicButton(); updateMuteVolButton(); @@ -431,7 +431,7 @@ void ChatForm::onFriendStatusChanged(uint32_t friendId, Status::Status status) return; } - if (!f->isOnline()) { + if (!Status::isOnline(f->getStatus())) { // Hide the "is typing" message when a friend goes offline setFriendTyping(false); } diff --git a/src/widget/form/genericchatform.cpp b/src/widget/form/genericchatform.cpp index dfd35cc6e..2d332fefb 100644 --- a/src/widget/form/genericchatform.cpp +++ b/src/widget/form/genericchatform.cpp @@ -980,6 +980,10 @@ void GenericChatForm::searchInBegin(const QString& phrase, const ParameterSearch return; } + if (messages.size() == 0) { + return; + } + if (chatLog.getNextIdx() == messages.rbegin()->first + 1) { disableSearchText(); } else { diff --git a/src/widget/form/groupchatform.cpp b/src/widget/form/groupchatform.cpp index 58e23b027..454afbb92 100644 --- a/src/widget/form/groupchatform.cpp +++ b/src/widget/form/groupchatform.cpp @@ -307,7 +307,7 @@ void GroupChatForm::dropEvent(QDropEvent* ev) int friendId = frnd->getId(); int groupId = group->getId(); - if (frnd->isOnline()) { + if (Status::isOnline(frnd->getStatus())) { Core::getInstance()->groupInviteFriend(friendId, groupId); } } diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 761d84749..956ab0fd8 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -1228,7 +1228,7 @@ void Widget::onFriendStatusChanged(int friendId, Status::Status status) FriendWidget* widget = friendWidgets[f->getPublicKey()]; if (isActualChange) { - if (!f->isOnline()) { + if (!Status::isOnline(f->getStatus())) { contactListWidget->moveWidget(widget, Status::Status::Online); } else if (status == Status::Status::Offline) { contactListWidget->moveWidget(widget, Status::Status::Offline); diff --git a/test/persistence/offlinemsgengine_test.cpp b/test/persistence/offlinemsgengine_test.cpp index 22dcdf848..5a421d07c 100644 --- a/test/persistence/offlinemsgengine_test.cpp +++ b/test/persistence/offlinemsgengine_test.cpp @@ -19,6 +19,7 @@ #include "src/core/core.h" #include "src/model/friend.h" +#include "src/model/status.h" #include "src/persistence/offlinemsgengine.h" #include @@ -35,7 +36,7 @@ public: } bool sendMessage(uint32_t friendId, const QString& message, ReceiptNum& receipt) override { - if (f->isOnline()) { + if (Status::isOnline(f->getStatus())) { receipt.get() = receiptNum++; if (!dropReceipts) { msgs.push_back(message); @@ -45,7 +46,7 @@ public: } else { numMessagesFailed++; } - return f->isOnline(); + return Status::isOnline(f->getStatus()); } signals: