1 /*
2  *  Kaidan - A user-friendly XMPP client for every device!
3  *
4  *  Copyright (C) 2016-2021 Kaidan developers and contributors
5  *  (see the LICENSE file for a full list of copyright authors)
6  *
7  *  Kaidan is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  In addition, as a special exception, the author of Kaidan gives
13  *  permission to link the code of its release with the OpenSSL
14  *  project's "OpenSSL" library (or with modified versions of it that
15  *  use the same license as the "OpenSSL" library), and distribute the
16  *  linked executables. You must obey the GNU General Public License in
17  *  all respects for all of the code used other than "OpenSSL". If you
18  *  modify this file, you may extend this exception to your version of
19  *  the file, but you are not obligated to do so.  If you do not wish to
20  *  do so, delete this exception statement from your version.
21  *
22  *  Kaidan is distributed in the hope that it will be useful,
23  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
24  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  *  GNU General Public License for more details.
26  *
27  *  You should have received a copy of the GNU General Public License
28  *  along with Kaidan.  If not, see <http://www.gnu.org/licenses/>.
29  */
30 
31 #pragma once
32 
33 #include <QObject>
34 
35 #include "Message.h"
36 
37 class QSqlQuery;
38 class QSqlRecord;
39 
40 /**
41  * @class The MessageDb is used to query the 'messages' database table. It's used by the
42  * MessageModel to load messages and by the MessageHandler to insert messages.
43  *
44  * All queries must be executed only after the Kaidan SQL connection has been opened in
45  * the Database class.
46  */
47 class MessageDb : public QObject
48 {
49 	Q_OBJECT
50 
51 public:
52 	explicit MessageDb(QObject *parent = nullptr);
53 	~MessageDb();
54 
55 	static MessageDb *instance();
56 
57 	/**
58 	 * Parses a list of messages from a SELECT query.
59 	 */
60 	static void parseMessagesFromQuery(QSqlQuery &query, QVector<Message> &msgs);
61 
62 	/**
63 	 * Creates an @c QSqlRecord for updating an old message to a new message.
64 	 *
65 	 * @param oldMsg Full message as it is currently saved
66 	 * @param newMsg Full message as it should be after the update query ran.
67 	 */
68 	static QSqlRecord createUpdateRecord(const Message &oldMsg,
69 	                                     const Message &newMsg);
70 
71 signals:
72 	/**
73 	 * Can be used to triggerd fetchMessages()
74 	 */
75 	void fetchMessagesRequested(const QString &user1,
76 	                            const QString &user2,
77 	                            int index);
78 
79 	/**
80 	 *  Emitted to fetch pending messages.
81 	 */
82 	void fetchPendingMessagesRequested(const QString &userJid);
83 	void fetchLastMessageStampRequested();
84 
85 	void updateMessageRequested(const QString &id, const std::function<void (Message &)> &updateMsg);
86 	void removeAllMessagesRequested();
87 
88 	/**
89 	 * Emitted when new messages have been fetched
90 	 */
91 	void messagesFetched(const QVector<Message> &messages);
92 
93 	/**
94 	 * Emitted when pending messages have been fetched
95 	 */
96 	void pendingMessagesFetched(const QVector<Message> &messages);
97 
98 	/**
99 	 * Emitted when the latest message stamp was fetched
100 	 */
101 	void lastMessageStampFetched(const QDateTime &stamp);
102 
103 	void messageAdded(const Message &msg, MessageOrigin origin);
104 
105 public slots:
106 	/**
107 	 * @brief Fetches more entries from the database and emits messagesFetched() with
108 	 * the results.
109 	 *
110 	 * @param user1 Messages are from or to this JID.
111 	 * @param user2 Messages are from or to this JID.
112 	 * @param index Number of entries to be skipped, used for paging.
113 	 */
114 	void fetchMessages(const QString &user1,
115 	                   const QString &user2,
116 	                   int index);
117 
118 	/**
119 	 * @brief Fetches messages that are marked as pending.
120 	 *
121 	 * @param userJid JID of the user whose messages should be fetched
122 	 */
123 	void fetchPendingMessages(const QString &userJid);
124 
125 	/**
126 	 * Fetches the last message and returns it.
127 	 */
128 	Message fetchLastMessage(const QString &user1, const QString &user2);
129 
130 	/**
131 	 * Fetch the latest message stamp
132 	 */
133 	void fetchLastMessageStamp();
134 
135 	/**
136 	 * Adds a message to the database.
137 	 */
138 	void addMessage(const Message &msg, MessageOrigin origin);
139 
140 	/**
141 	 * Removes all messages of an account or an account's chat.
142 	 *
143 	 * @param accountJid JID of the account whose messages are being removed
144 	 * @param chatJid JID of the chat whose messages are being removed (optional)
145 	 */
146 	void removeMessages(const QString &accountJid, const QString &chatJid = {});
147 
148 	/**
149 	 * Loads a message, runs the update lambda and writes it to the DB again.
150 	 *
151 	 * @param updateMsg Function that changes the message
152 	 */
153 	void updateMessage(const QString &id,
154 			   const std::function<void (Message &)> &updateMsg);
155 
156 	/**
157 	 * Updates message by @c UPDATE record: This means it doesn't load the message
158 	 * from the database and writes it again, but executes an UPDATE query.
159 	 *
160 	 * @param updateRecord
161 	 */
162 	void updateMessageRecord(const QString &id,
163 	                         const QSqlRecord &updateRecord);
164 
165 private slots:
166 	/**
167 	 * Checks whether a message already exists in the database
168 	 */
169 	bool checkMessageExists(const Message &message);
170 
171 private:
172 	static MessageDb *s_instance;
173 };
174