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