qtui: Set proper icon for "About Quassel" menu option
[quassel.git] / src / core / abstractsqlstorage.h
1 /***************************************************************************
2  *   Copyright (C) 2005-2018 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #pragma once
22
23 #include "storage.h"
24
25 #include <memory>
26
27 #include <QSqlDatabase>
28 #include <QSqlQuery>
29 #include <QSqlError>
30
31 class AbstractSqlMigrationReader;
32 class AbstractSqlMigrationWriter;
33
34 class AbstractSqlStorage : public Storage
35 {
36     Q_OBJECT
37
38 public:
39     AbstractSqlStorage(QObject *parent = 0);
40     virtual ~AbstractSqlStorage();
41
42     virtual std::unique_ptr<AbstractSqlMigrationReader> createMigrationReader() { return {}; }
43     virtual std::unique_ptr<AbstractSqlMigrationWriter> createMigrationWriter() { return {}; }
44
45 public slots:
46     virtual State init(const QVariantMap &settings = QVariantMap(),
47                        const QProcessEnvironment &environment = {},
48                        bool loadFromEnvironment = false);
49     virtual bool setup(const QVariantMap &settings = QVariantMap(),
50                        const QProcessEnvironment &environment = {},
51                        bool loadFromEnvironment = false);
52
53 protected:
54     inline virtual void sync() {};
55
56     QSqlDatabase logDb();
57
58     /**
59      * Fetch an SQL query string by name and optional schema version
60      *
61      * Loads the named SQL query from the built-in SQL resource collection, returning it as a
62      * string.  If a version is specified, it'll be loaded from the schema version-specific folder
63      * instead.
64      *
65      * @see schemaVersion()
66      *
67      * @param[in] queryName  File name of the SQL query, minus the .sql extension
68      * @param[in] version
69      * @parblock
70      * SQL schema version; if 0, fetches from current version, otherwise loads from the specified
71      * schema version instead of the current schema files.
72      * @endparblock
73      * @return String with the requested SQL query, ready for parameter substitution
74      */
75     QString queryString(const QString &queryName, int version = 0);
76
77     QStringList setupQueries();
78
79     QStringList upgradeQueries(int ver);
80     bool upgradeDb();
81
82     bool watchQuery(QSqlQuery &query);
83
84     int schemaVersion();
85     virtual int installedSchemaVersion() { return -1; };
86     virtual bool updateSchemaVersion(int newVersion) = 0;
87     virtual bool setupSchemaVersion(int version) = 0;
88
89     virtual void setConnectionProperties(const QVariantMap &properties,
90                                          const QProcessEnvironment &environment,
91                                          bool loadFromEnvironment) = 0;
92     virtual QString driverName() = 0;
93     inline virtual QString hostName() { return QString(); }
94     inline virtual int port() { return -1; }
95     virtual QString databaseName() = 0;
96     inline virtual QString userName() { return QString(); }
97     inline virtual QString password() { return QString(); }
98
99     //! Initialize db specific features on connect
100     /** This is called every time a connection to a specific SQL backend is established
101      *  the default implementation does nothing.
102      *
103      *  When reimplementing this method, don't use logDB() inside this function as
104      *  this would cause as we're just about to initialize that DB connection.
105      */
106     inline virtual bool initDbSession(QSqlDatabase & /* db */) { return true; }
107
108 private slots:
109     void connectionDestroyed();
110
111 private:
112     void addConnectionToPool();
113     void dbConnect(QSqlDatabase &db);
114
115     int _schemaVersion;
116     bool _debug;
117
118     static int _nextConnectionId;
119     QMutex _connectionPoolMutex;
120     // we let a Connection Object manage each actual db connection
121     // those objects reside in the thread the connection belongs to
122     // which allows us thread safe termination of a connection
123     class Connection;
124     QHash<QThread *, Connection *> _connectionPool;
125 };
126
127 struct SenderData {
128     QString sender;
129     QString realname;
130     QString avatarurl;
131
132     friend uint qHash(const SenderData &key);
133     friend bool operator==(const SenderData &a, const SenderData &b);
134 };
135
136 // ========================================
137 //  AbstractSqlStorage::Connection
138 // ========================================
139 class AbstractSqlStorage::Connection : public QObject
140 {
141     Q_OBJECT
142
143 public:
144     Connection(const QString &name, QObject *parent = 0);
145     ~Connection();
146
147     inline QLatin1String name() const { return QLatin1String(_name); }
148
149 private:
150     QByteArray _name;
151 };
152
153
154 // ========================================
155 //  AbstractSqlMigrator
156 // ========================================
157 class AbstractSqlMigrator
158 {
159 public:
160     // migration objects
161     struct QuasselUserMO {
162         UserId id;
163         QString username;
164         QString password;
165         int hashversion;
166         QString authenticator;
167     };
168
169     struct SenderMO {
170         qint64 senderId;
171         QString sender;
172         QString realname;
173         QString avatarurl;
174         SenderMO() : senderId(0) {}
175     };
176
177     struct IdentityMO {
178         IdentityId id;
179         UserId userid;
180         QString identityname;
181         QString realname;
182         QString awayNick;
183         bool awayNickEnabled;
184         QString awayReason;
185         bool awayReasonEnabled;
186         bool autoAwayEnabled;
187         int autoAwayTime;
188         QString autoAwayReason;
189         bool autoAwayReasonEnabled;
190         bool detachAwayEnabled;
191         QString detachAwayReason;
192         bool detachAwayReasonEnabled;
193         QString ident;
194         QString kickReason;
195         QString partReason;
196         QString quitReason;
197         QByteArray sslCert;
198         QByteArray sslKey;
199     };
200
201     struct IdentityNickMO {
202         int nickid;
203         IdentityId identityId;
204         QString nick;
205     };
206
207     struct NetworkMO {
208         NetworkId networkid;
209         UserId userid;
210         QString networkname;
211         IdentityId identityid;
212         QString encodingcodec;
213         QString decodingcodec;
214         QString servercodec;
215         bool userandomserver;
216         QString perform;
217         bool useautoidentify;
218         QString autoidentifyservice;
219         QString autoidentifypassword;
220         bool useautoreconnect;
221         int autoreconnectinterval;
222         int autoreconnectretries;
223         bool unlimitedconnectretries;
224         bool rejoinchannels;
225         // Custom rate limiting
226         bool usecustommessagerate;
227         int messagerateburstsize;
228         int messageratedelay;
229         bool unlimitedmessagerate;
230         // ...
231         bool connected;
232         QString usermode;
233         QString awaymessage;
234         QString attachperform;
235         QString detachperform;
236         bool usesasl;
237         QString saslaccount;
238         QString saslpassword;
239     };
240
241     struct BufferMO {
242         BufferId bufferid;
243         UserId userid;
244         int groupid;
245         NetworkId networkid;
246         QString buffername;
247         QString buffercname;
248         int buffertype;
249         qint64 lastmsgid;
250         qint64 lastseenmsgid;
251         qint64 markerlinemsgid;
252         int bufferactivity;
253         int highlightcount;
254         QString key;
255         bool joined;
256         QString cipher;
257     };
258
259     struct BacklogMO {
260         MsgId messageid;
261         QDateTime time; // has to be in UTC!
262         BufferId bufferid;
263         int type;
264         int flags;
265         qint64 senderid;
266         QString senderprefixes;
267         QString message;
268     };
269
270     struct IrcServerMO {
271         int serverid;
272         UserId userid;
273         NetworkId networkid;
274         QString hostname;
275         int port;
276         QString password;
277         bool ssl;
278         bool sslverify;     /// If true, validate SSL certificates
279         int sslversion;
280         bool useproxy;
281         int proxytype;
282         QString proxyhost;
283         int proxyport;
284         QString proxyuser;
285         QString proxypass;
286     };
287
288     struct UserSettingMO {
289         UserId userid;
290         QString settingname;
291         QByteArray settingvalue;
292     };
293
294     struct CoreStateMO {
295         QString key;
296         QByteArray value;
297     };
298
299     enum MigrationObject {
300         QuasselUser,
301         Sender,
302         Identity,
303         IdentityNick,
304         Network,
305         Buffer,
306         Backlog,
307         IrcServer,
308         UserSetting,
309         CoreState
310     };
311
312     AbstractSqlMigrator();
313     virtual ~AbstractSqlMigrator() {}
314
315     static QString migrationObject(MigrationObject moType);
316
317 protected:
318     void newQuery(const QString &query, QSqlDatabase db);
319     virtual void resetQuery();
320     virtual bool prepareQuery(MigrationObject mo) = 0;
321     bool exec();
322     inline bool next() { return _query->next(); }
323     inline QVariant value(int index) { return _query->value(index); }
324     inline void bindValue(const QString &placeholder, const QVariant &val) { _query->bindValue(placeholder, val); }
325     inline void bindValue(int pos, const QVariant &val) { _query->bindValue(pos, val); }
326
327     inline QSqlError lastError() { return _query ? _query->lastError() : QSqlError(); }
328     void dumpStatus();
329     inline QString executedQuery() { return _query ? _query->executedQuery() : QString(); }
330     inline QVariantList boundValues();
331
332     virtual bool transaction() = 0;
333     virtual void rollback() = 0;
334     virtual bool commit() = 0;
335
336 private:
337     QSqlQuery *_query;
338 };
339
340
341 class AbstractSqlMigrationReader : public AbstractSqlMigrator
342 {
343 public:
344     AbstractSqlMigrationReader();
345
346     virtual bool readMo(QuasselUserMO &user) = 0;
347     virtual bool readMo(IdentityMO &identity) = 0;
348     virtual bool readMo(IdentityNickMO &identityNick) = 0;
349     virtual bool readMo(NetworkMO &network) = 0;
350     virtual bool readMo(BufferMO &buffer) = 0;
351     virtual bool readMo(SenderMO &sender) = 0;
352     virtual bool readMo(BacklogMO &backlog) = 0;
353     virtual bool readMo(IrcServerMO &ircserver) = 0;
354     virtual bool readMo(UserSettingMO &userSetting) = 0;
355     virtual bool readMo(CoreStateMO &coreState) = 0;
356
357     bool migrateTo(AbstractSqlMigrationWriter *writer);
358
359 private:
360     void abortMigration(const QString &errorMsg = QString());
361     bool finalizeMigration();
362
363     template<typename T> bool transferMo(MigrationObject moType, T &mo);
364
365     AbstractSqlMigrationWriter *_writer;
366 };
367
368
369 class AbstractSqlMigrationWriter : public AbstractSqlMigrator
370 {
371 public:
372     virtual bool writeMo(const QuasselUserMO &user) = 0;
373     virtual bool writeMo(const IdentityMO &identity) = 0;
374     virtual bool writeMo(const IdentityNickMO &identityNick) = 0;
375     virtual bool writeMo(const NetworkMO &network) = 0;
376     virtual bool writeMo(const BufferMO &buffer) = 0;
377     virtual bool writeMo(const SenderMO &sender) = 0;
378     virtual bool writeMo(const BacklogMO &backlog) = 0;
379     virtual bool writeMo(const IrcServerMO &ircserver) = 0;
380     virtual bool writeMo(const UserSettingMO &userSetting) = 0;
381     virtual bool writeMo(const CoreStateMO &coreState) = 0;
382
383     inline bool migrateFrom(AbstractSqlMigrationReader *reader) { return reader->migrateTo(this); }
384
385     // called after migration process
386     virtual inline bool postProcess() { return true; }
387     friend class AbstractSqlMigrationReader;
388 };