1 /* 2 Copyright © 2015-2019 by The qTox Project Contributors 3 4 This file is part of qTox, a Qt-based graphical interface for Tox. 5 6 qTox is libre software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 qTox is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with qTox. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #ifndef HISTORY_H 21 #define HISTORY_H 22 23 #include <QDateTime> 24 #include <QHash> 25 #include <QPointer> 26 #include <QVector> 27 28 #include <cassert> 29 #include <cstdint> 30 #include <tox/toxencryptsave.h> 31 32 #include "src/core/toxfile.h" 33 #include "src/core/toxpk.h" 34 #include "src/persistence/db/rawdatabase.h" 35 #include "src/widget/searchtypes.h" 36 37 class Profile; 38 class HistoryKeeper; 39 40 enum class HistMessageContentType 41 { 42 message, 43 file 44 }; 45 46 class HistMessageContent 47 { 48 public: HistMessageContent(QString message)49 HistMessageContent(QString message) 50 : data(std::make_shared<QString>(std::move(message))) 51 , type(HistMessageContentType::message) 52 {} 53 HistMessageContent(ToxFile file)54 HistMessageContent(ToxFile file) 55 : data(std::make_shared<ToxFile>(std::move(file))) 56 , type(HistMessageContentType::file) 57 {} 58 getType()59 HistMessageContentType getType() const 60 { 61 return type; 62 } 63 asMessage()64 QString& asMessage() 65 { 66 assert(type == HistMessageContentType::message); 67 return *static_cast<QString*>(data.get()); 68 } 69 asFile()70 ToxFile& asFile() 71 { 72 assert(type == HistMessageContentType::file); 73 return *static_cast<ToxFile*>(data.get()); 74 } 75 asMessage()76 const QString& asMessage() const 77 { 78 assert(type == HistMessageContentType::message); 79 return *static_cast<QString*>(data.get()); 80 } 81 asFile()82 const ToxFile& asFile() const 83 { 84 assert(type == HistMessageContentType::file); 85 return *static_cast<ToxFile*>(data.get()); 86 } 87 88 private: 89 // Not really shared but shared_ptr has support for shared_ptr<void> 90 std::shared_ptr<void> data; 91 HistMessageContentType type; 92 }; 93 94 struct FileDbInsertionData 95 { 96 FileDbInsertionData(); 97 98 RowId historyId; 99 QString friendPk; 100 QString fileId; 101 QString fileName; 102 QString filePath; 103 int64_t size; 104 int direction; 105 }; 106 Q_DECLARE_METATYPE(FileDbInsertionData); 107 108 enum class MessageState 109 { 110 complete, 111 pending, 112 broken 113 }; 114 115 class History : public QObject, public std::enable_shared_from_this<History> 116 { 117 Q_OBJECT 118 public: 119 struct HistMessage 120 { HistMessageHistMessage121 HistMessage(RowId id, MessageState state, QDateTime timestamp, QString chat, QString dispName, 122 QString sender, QString message) 123 : chat{chat} 124 , sender{sender} 125 , dispName{dispName} 126 , timestamp{timestamp} 127 , id{id} 128 , state{state} 129 , content(std::move(message)) 130 {} 131 HistMessageHistMessage132 HistMessage(RowId id, MessageState state, QDateTime timestamp, QString chat, QString dispName, 133 QString sender, ToxFile file) 134 : chat{chat} 135 , sender{sender} 136 , dispName{dispName} 137 , timestamp{timestamp} 138 , id{id} 139 , state{state} 140 , content(std::move(file)) 141 {} 142 143 144 QString chat; 145 QString sender; 146 QString dispName; 147 QDateTime timestamp; 148 RowId id; 149 MessageState state; 150 HistMessageContent content; 151 }; 152 153 struct DateIdx 154 { 155 QDate date; 156 size_t numMessagesIn; 157 }; 158 159 public: 160 explicit History(std::shared_ptr<RawDatabase> db); 161 ~History(); 162 163 bool isValid(); 164 165 bool historyExists(const ToxPk& friendPk); 166 167 void eraseHistory(); 168 void removeFriendHistory(const QString& friendPk); 169 void addNewMessage(const QString& friendPk, const QString& message, const QString& sender, 170 const QDateTime& time, bool isDelivered, QString dispName, 171 const std::function<void(RowId)>& insertIdCallback = {}); 172 173 void addNewFileMessage(const QString& friendPk, const QString& fileId, 174 const QString& fileName, const QString& filePath, int64_t size, 175 const QString& sender, const QDateTime& time, QString const& dispName); 176 177 void setFileFinished(const QString& fileId, bool success, const QString& filePath, const QByteArray& fileHash); 178 size_t getNumMessagesForFriend(const ToxPk& friendPk); 179 size_t getNumMessagesForFriendBeforeDate(const ToxPk& friendPk, const QDateTime& date); 180 QList<HistMessage> getMessagesForFriend(const ToxPk& friendPk, size_t firstIdx, size_t lastIdx); 181 QList<HistMessage> getUndeliveredMessagesForFriend(const ToxPk& friendPk); 182 QDateTime getDateWhereFindPhrase(const QString& friendPk, const QDateTime& from, QString phrase, 183 const ParameterSearch& parameter); 184 QList<DateIdx> getNumMessagesForFriendBeforeDateBoundaries(const ToxPk& friendPk, 185 const QDate& from, size_t maxNum); 186 187 void markAsDelivered(RowId messageId); 188 189 protected: 190 QVector<RawDatabase::Query> 191 generateNewMessageQueries(const QString& friendPk, const QString& message, 192 const QString& sender, const QDateTime& time, bool isDelivered, 193 QString dispName, std::function<void(RowId)> insertIdCallback = {}); 194 195 signals: 196 void fileInsertionReady(FileDbInsertionData data); 197 void fileInserted(RowId dbId, QString fileId); 198 199 private slots: 200 void onFileInsertionReady(FileDbInsertionData data); 201 void onFileInserted(RowId dbId, QString fileId); 202 203 private: 204 bool historyAccessBlocked(); 205 static RawDatabase::Query generateFileFinished(RowId fileId, bool success, 206 const QString& filePath, const QByteArray& fileHash); 207 std::shared_ptr<RawDatabase> db; 208 209 210 QHash<QString, int64_t> peers; 211 struct FileInfo 212 { 213 bool finished = false; 214 bool success = false; 215 QString filePath; 216 QByteArray fileHash; 217 RowId fileId{-1}; 218 }; 219 220 // This needs to be a shared pointer to avoid callback lifetime issues 221 QHash<QString, FileInfo> fileInfos; 222 }; 223 224 #endif // HISTORY_H 225