1 /*
2    Drawpile - a collaborative drawing program.
3 
4    Copyright (C) 2017-2018 Calle Laakkonen
5 
6    Drawpile is free 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    Drawpile 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 Drawpile.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #ifndef DP_SERVER_FILEDHISTORY_H
21 #define DP_SERVER_FILEDHISTORY_H
22 
23 #include "sessionhistory.h"
24 #include "../libshared/net/protover.h"
25 
26 #include <QDir>
27 #include <QVector>
28 #include <QSet>
29 
30 namespace server {
31 
32 class FiledHistory : public SessionHistory
33 {
34 	Q_OBJECT
35 public:
36 	~FiledHistory();
37 
38 	/**
39 	 * @brief Start a new file backed history
40 	 * @param dir where to put the session files
41 	 * @param id session ID
42 	 * @param alias ID alias
43 	 * @param version full protocol version
44 	 * @param founder name of the session founder
45 	 * @param parent
46 	 * @return FiledHistory object or nullptr on error
47 	 */
48 	static FiledHistory *startNew(const QDir &dir, const QString &id, const QString &alias, const protocol::ProtocolVersion &version, const QString &founder, QObject *parent=nullptr);
49 
50 	/**
51 	 * @brief Load a session from file
52 	 * @param path
53 	 * @param parent
54 	 * @return
55 	 */
56 	static FiledHistory *load(const QString &path, QObject *parent=nullptr);
57 
58 	/**
59 	 * @brief Close the currently open block (if any) and start a new one
60 	 */
61 	void closeBlock();
62 
63 	/**
64 	 * @brief Enable archival mode
65 	 *
66 	 * In archive mode, files are not deleted when session ends or is reset.
67 	 * Instead, ".archived" is appended to the end of the journal file on termination.
68 	 * @param archive
69 	 */
setArchive(bool archive)70 	void setArchive(bool archive) { m_archive = archive; }
71 
72 	//! Get the metadata journal file name for the given session ID
73 	static QString journalFilename(const QString &id);
74 
idAlias()75 	QString idAlias() const override { return m_alias; }
founderName()76 	QString founderName() const override { return m_founder; }
protocolVersion()77 	protocol::ProtocolVersion protocolVersion() const override { return m_version; }
passwordHash()78 	QByteArray passwordHash() const override { return m_password; }
opwordHash()79 	QByteArray opwordHash() const override { return m_opword; }
maxUsers()80 	int maxUsers() const override { return m_maxUsers; }
title()81 	QString title() const override { return m_title; }
autoResetThreshold()82 	uint autoResetThreshold() const override { return m_autoResetThreshold; }
flags()83 	Flags flags() const override { return m_flags; }
84 
85 	void setPasswordHash(const QByteArray &password) override;
86 	void setOpwordHash(const QByteArray &opword) override;
87 	void setMaxUsers(int max) override;
88 	void setTitle(const QString &title) override;
89 	void setFlags(Flags f) override;
90 	void setAutoResetThreshold(uint limit) override;
91 	void joinUser(uint8_t id, const QString &name) override;
92 
93 	void terminate() override;
94 	void cleanupBatches(int before) override;
95 	std::tuple<protocol::MessageList, int> getBatch(int after) const override;
96 
97 	void addAnnouncement(const QString &) override;
98 	void removeAnnouncement(const QString &url) override;
announcements()99 	QStringList announcements() const override { return m_announcements; }
100 
101 	void setAuthenticatedOperator(const QString &authId, bool op) override;
102 	void setAuthenticatedTrust(const QString &authId, bool trusted) override;
isOperator(const QString & authId)103 	bool isOperator(const QString &authId) const override { return m_ops.contains(authId); }
isTrusted(const QString & authId)104 	bool isTrusted(const QString &authId) const override { return m_trusted.contains(authId); }
isAuthenticatedOperators()105 	bool isAuthenticatedOperators() const override { return !m_ops.isEmpty(); }
106 
107 protected:
108 	void historyAdd(const protocol::MessagePtr &msg) override;
109 	void historyReset(const protocol::MessageList &newHistory) override;
110 	void historyAddBan(int id, const QString &username, const QHostAddress &ip, const QString &extAuthId, const QString &bannedBy) override;
111 	void historyRemoveBan(int id) override;
112 
113 	void timerEvent(QTimerEvent *event) override;
114 
115 private:
116 	FiledHistory(const QDir &dir, QFile *journal, const QString &id, const QString &alias, const protocol::ProtocolVersion &version, const QString &founder, QObject *parent);
117 	FiledHistory(const QDir &dir, QFile *journal, const QString &id, QObject *parent);
118 
119 	struct Block {
120 		qint64 startOffset;
121 		int startIndex;
122 		int count;
123 		qint64 endOffset;
124 		protocol::MessageList messages;
125 	};
126 
127 	bool create();
128 	bool load();
129 	bool scanBlocks();
130 	bool initRecording();
131 
132 	QDir m_dir;
133 	QFile *m_journal;
134 	QFile *m_recording;
135 
136 	// Current state:
137 	QString m_alias;
138 	QString m_founder;
139 	QString m_title;
140 	protocol::ProtocolVersion m_version;
141 	QByteArray m_password;
142 	QByteArray m_opword;
143 	int m_maxUsers;
144 	uint m_autoResetThreshold;
145 	Flags m_flags;
146 	QStringList m_announcements;
147 	QSet<QString> m_ops;
148 	QSet<QString> m_trusted;
149 
150 	QVector<Block> m_blocks;
151 	int m_fileCount;
152 	bool m_archive;
153 };
154 
155 }
156 
157 #endif
158