1 /*
2    Drawpile - a collaborative drawing program.
3 
4    Copyright (C) 2013-2019 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 #ifndef DP_NET_META_TRANSPARENT_H
20 #define DP_NET_META_TRANSPARENT_H
21 
22 #include "message.h"
23 
24 #include <QList>
25 #include <QString>
26 
27 namespace protocol {
28 
29 /**
30  * @brief Inform the client of a new user
31  *
32  * This message is sent only be the server. It associates a username
33  * with a context ID.
34  *
35  */
36 class UserJoin : public Message {
37 public:
38 	static const uint8_t FLAG_AUTH = 0x01; // authenticated user (not a guest)
39 	static const uint8_t FLAG_MOD = 0x02;  // user is a moderator
40 	static const uint8_t FLAG_BOT = 0x04;  // user is a bot
41 
UserJoin(uint8_t ctx,uint8_t flags,const QByteArray & name,const QByteArray & avatar)42 	UserJoin(uint8_t ctx, uint8_t flags, const QByteArray &name, const QByteArray &avatar) : Message(MSG_USER_JOIN, ctx), m_name(name), m_avatar(avatar), m_flags(flags) { Q_ASSERT(name.length()>0 && name.length()<256); }
43 	UserJoin(uint8_t ctx, uint8_t flags, const QString &name, const QByteArray &avatar=QByteArray()) : UserJoin(ctx, flags, name.toUtf8(), avatar) {}
44 
45 	static UserJoin *deserialize(uint8_t ctx, const uchar *data, uint len);
46 	static UserJoin *fromText(uint8_t ctx, const Kwargs &kwargs);
47 
name()48 	QString name() const { return QString::fromUtf8(m_name); }
49 
avatar()50 	QByteArray avatar() const { return m_avatar; }
51 
flags()52 	uint8_t flags() const { return m_flags; }
53 
isModerator()54 	bool isModerator() const { return m_flags & FLAG_MOD; }
isAuthenticated()55 	bool isAuthenticated() const { return m_flags & FLAG_AUTH; }
isBot()56 	bool isBot() const { return m_flags & FLAG_BOT; }
57 
messageName()58 	QString messageName() const override { return QStringLiteral("join"); }
59 
60 protected:
61 	int payloadLength() const override;
62 	int serializePayload(uchar *data) const override;
63 	Kwargs kwargs() const override;
64 
65 private:
66 	QByteArray m_name;
67 	QByteArray m_avatar;
68 	uint8_t m_flags;
69 };
70 
71 /**
72  * @brief Inform the client of a user leaving
73  *
74  * This message is sent only by the server. Upon receiving this message,
75  * clients will typically remove the user from the user listing. The client
76  * is also allowed to release resources associated with this context ID.
77  */
78 class UserLeave : public ZeroLengthMessage<UserLeave> {
79 public:
UserLeave(uint8_t ctx)80 	explicit UserLeave(uint8_t ctx) : ZeroLengthMessage(MSG_USER_LEAVE, ctx) {}
81 
messageName()82 	QString messageName() const override { return "leave"; }
83 };
84 
85 /**
86  * @brief Session ownership change
87  *
88  * This message sets the users who have operator status. It can be
89  * sent by users who are already operators or by the server (ctx=0).
90  *
91  * The list of operators implicitly contains the user who sends the
92  * message, thus users cannot deop themselves.
93  *
94  * The server sanitizes the ID list so, when distributed to other users,
95  * it does not contain any duplicates or non-existing users.
96  */
97 class SessionOwner : public Message {
98 public:
SessionOwner(uint8_t ctx,QList<uint8_t> ids)99 	SessionOwner(uint8_t ctx, QList<uint8_t> ids) : Message(MSG_SESSION_OWNER, ctx), m_ids(ids) { }
100 
101 	static SessionOwner *deserialize(uint8_t ctx, const uchar *data, int buflen);
102 	static SessionOwner *fromText(uint8_t ctx, const Kwargs &kwargs);
103 
ids()104 	QList<uint8_t> ids() const { return m_ids; }
setIds(const QList<uint8_t> ids)105 	void setIds(const QList<uint8_t> ids) { m_ids = ids; }
106 
messageName()107 	QString messageName() const override { return "owner"; }
108 
109 protected:
110 	int payloadLength() const override;
111 	int serializePayload(uchar *data) const override;
112 	Kwargs kwargs() const override;
113 
114 private:
115 	QList<uint8_t> m_ids;
116 };
117 
118 /**
119  * @brief List of trusted users
120  *
121  * This message sets the list of user who have been tagged as trusted,
122  * but who are not operators. The meaning of "trusted" is a mostly
123  * clientside concept, but the session can be configured to allow trusted
124  * users access to some operator commands. (Deputies)
125  *
126  * This command can be sent by operators or by the server (ctx=0).
127  *
128  * The server sanitizes the ID list so, when distributed to other users,
129  * it does not contain any duplicates or non-existing users.
130  */
131 class TrustedUsers : public Message {
132 public:
TrustedUsers(uint8_t ctx,QList<uint8_t> ids)133 	TrustedUsers(uint8_t ctx, QList<uint8_t> ids) : Message(MSG_TRUSTED_USERS, ctx), m_ids(ids) { }
134 
135 	static TrustedUsers *deserialize(uint8_t ctx, const uchar *data, int buflen);
136 	static TrustedUsers *fromText(uint8_t ctx, const Kwargs &kwargs);
137 
ids()138 	QList<uint8_t> ids() const { return m_ids; }
setIds(const QList<uint8_t> ids)139 	void setIds(const QList<uint8_t> ids) { m_ids = ids; }
140 
messageName()141 	QString messageName() const override { return "trusted"; }
142 
143 protected:
144 	int payloadLength() const override;
145 	int serializePayload(uchar *data) const override;
146 	Kwargs kwargs() const override;
147 
148 private:
149 	QList<uint8_t> m_ids;
150 };
151 
152 /**
153  * @brief A chat message
154  *
155  * Chat message sent by the server with the context ID 0 are server messages.
156  * (Typically a Command message is used for server announcements, but the Chat message
157  * is used for those messages that must be stored in the session history.)
158  */
159 class Chat : public Message {
160 public:
161 	// Transparent flags: these affect serverside behavior
162 	static const uint8_t FLAG_BYPASS = 0x01; // bypass session history and send directly to logged in users
163 
164 	// Opaque flags: the server doesn't know anything about these
165 	static const uint8_t FLAG_SHOUT = 0x01;  // public announcement
166 	static const uint8_t FLAG_ACTION = 0x02; // this is an "action message" (like /me in IRC)
167 	static const uint8_t FLAG_PIN = 0x04;    // pin this message
168 
Chat(uint8_t ctx,uint8_t tflags,uint8_t oflags,const QByteArray & msg)169 	Chat(uint8_t ctx, uint8_t tflags, uint8_t oflags, const QByteArray &msg) : Message(MSG_CHAT, ctx), m_tflags(tflags), m_oflags(oflags), m_msg(msg) {}
Chat(uint8_t ctx,uint8_t tflags,uint8_t oflags,const QString & msg)170 	Chat(uint8_t ctx, uint8_t tflags, uint8_t oflags, const QString &msg) : Chat(ctx, tflags, oflags, msg.toUtf8()) {}
171 
172 	//! Construct a regular chat message
regular(uint8_t ctx,const QString & message,bool bypass)173 	static MessagePtr regular(uint8_t ctx, const QString &message, bool bypass) { return MessagePtr(new Chat(ctx, bypass ? FLAG_BYPASS : 0, 0, message.toUtf8())); }
174 
175 	//! Construct a public announcement message
announce(uint8_t ctx,const QString & message)176 	static MessagePtr announce(uint8_t ctx, const QString &message) { return MessagePtr(new Chat(ctx, 0, FLAG_SHOUT, message.toUtf8())); }
177 
178 	//! Construct an action type message
action(uint8_t ctx,const QString & message,bool bypass)179 	static MessagePtr action(uint8_t ctx, const QString &message, bool bypass) { return MessagePtr(new Chat(ctx, bypass ? FLAG_BYPASS : 0, FLAG_ACTION, message.toUtf8())); }
180 
181 	//! Construct a pinned message
pin(uint8_t ctx,const QString & message)182 	static MessagePtr pin(uint8_t ctx, const QString &message) { return MessagePtr(new Chat(ctx, 0, FLAG_SHOUT|FLAG_PIN, message.toUtf8())); }
183 
184 	static Chat *deserialize(uint8_t ctx, const uchar *data, uint len);
185 	static Chat *fromText(uint8_t ctx, const Kwargs &kwargs);
186 
transparentFlags()187 	uint8_t transparentFlags() const { return m_tflags; }
opaqueFlags()188 	uint8_t opaqueFlags() const { return m_oflags; }
189 
message()190 	QString message() const { return QString::fromUtf8(m_msg); }
191 
192 	/**
193 	 * @brief Is this a history bypass message?
194 	 *
195 	 * If this flag is set, the message is sent directly to other users and not included
196 	 * in the session history.
197 	 */
isBypass()198 	bool isBypass() const { return m_tflags & FLAG_BYPASS; }
199 
200 	/**
201 	 * @brief Is this a shout?
202 	 *
203 	 * Shout messages are highlighted so they stand out. Typically used
204 	 * without the BYPASS flag.
205 	 *
206 	 * Clientside only.
207 	 */
isShout()208 	bool isShout() const { return m_oflags & FLAG_SHOUT; }
209 
210 	/**
211 	 * @brief Is this an action message?
212 	 *
213 	 * Clientside only.
214 	 */
isAction()215 	bool isAction() const { return m_oflags & FLAG_ACTION; }
216 
217 	/**
218 	 * @brief Is this a pinned chat message?
219 	 *
220 	 * Clientside only. Requires OP privileges.
221 	 */
isPin()222 	bool isPin() const { return m_oflags & FLAG_PIN; }
223 
messageName()224 	QString messageName() const override { return QStringLiteral("chat"); }
225 
226 protected:
227     int payloadLength() const override;
228 	int serializePayload(uchar *data) const override;
229 	Kwargs kwargs() const override;
230 
231 private:
232 	uint8_t m_tflags;
233 	uint8_t m_oflags;
234 	QByteArray m_msg;
235 };
236 
237 /**
238  * @brief A private chat message
239  *
240  * Note. This message type was added in protocol 4.21.2 (v. 2.1.0). For backward compatiblity,
241  * the server will not send any private messages from itself; it will only relay them from
242  * other users.
243  *
244  * Private messages always bypass the session history.
245  */
246 class PrivateChat : public Message {
247 public:
248 	// Opaque flags: the server doesn't know anything about these
249 	static const uint8_t FLAG_ACTION = 0x02; // this is an "action message" (like /me in IRC)
250 
PrivateChat(uint8_t ctx,uint8_t target,uint8_t oflags,const QByteArray & msg)251 	PrivateChat(uint8_t ctx, uint8_t target, uint8_t oflags, const QByteArray &msg) : Message(MSG_PRIVATE_CHAT, ctx), m_target(target), m_oflags(oflags), m_msg(msg) {}
PrivateChat(uint8_t ctx,uint8_t target,uint8_t oflags,const QString & msg)252 	PrivateChat(uint8_t ctx, uint8_t target, uint8_t oflags, const QString &msg) : PrivateChat(ctx, target, oflags, msg.toUtf8()) {}
253 
254 	//! Construct a regular chat message
regular(uint8_t ctx,uint8_t target,const QString & message)255 	static MessagePtr regular(uint8_t ctx, uint8_t target, const QString &message) { return MessagePtr(new PrivateChat(ctx, target, 0, message.toUtf8())); }
256 
257 	//! Construct an action type message
action(uint8_t ctx,uint8_t target,const QString & message)258 	static MessagePtr action(uint8_t ctx, uint8_t target, const QString &message) { return MessagePtr(new PrivateChat(ctx, target, FLAG_ACTION, message.toUtf8())); }
259 
260 	static PrivateChat *deserialize(uint8_t ctx, const uchar *data, uint len);
261 	static PrivateChat *fromText(uint8_t ctx, const Kwargs &kwargs);
262 
263 	//! Recipient ID
target()264 	uint8_t target() const { return m_target; }
265 
opaqueFlags()266 	uint8_t opaqueFlags() const { return m_oflags; }
267 
message()268 	QString message() const { return QString::fromUtf8(m_msg); }
269 
270 	//! Is this an action message? (client side only)
isAction()271 	bool isAction() const { return m_oflags & FLAG_ACTION; }
272 
messageName()273 	QString messageName() const override { return QStringLiteral("pm"); }
274 
275 protected:
276 	int payloadLength() const override;
277 	int serializePayload(uchar *data) const override;
278 	Kwargs kwargs() const override;
279 
280 private:
281 	uint8_t m_target;
282 	uint8_t m_oflags;
283 	QByteArray m_msg;
284 };
285 
286 /**
287  * @brief Soft reset point marker
288  *
289  * This message marks the point in the session history where soft reset occurs.
290  * Soft resetting is not actually implemented yet; this is here for forward compatiblity.
291  *
292  * All users should truncate their own session history when receiving this message,
293  * since undos cannot cross the reset boundary.
294  *
295  * The current client implementation handles the history truncation part. This is
296  * enough to be compatible with future clients capable of initiating soft reset.
297  */
298 class SoftResetPoint : public ZeroLengthMessage<SoftResetPoint> {
299 public:
SoftResetPoint(uint8_t ctx)300 	explicit SoftResetPoint(uint8_t ctx) : ZeroLengthMessage(MSG_SOFTRESET, ctx) { }
messageName()301 	QString messageName() const override { return QStringLiteral("softreset"); }
302 };
303 
304 }
305 
306 #endif
307