libQuotient
A Qt library for building matrix clients
roommessageevent.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de>
2 // SPDX-FileCopyrightText: 2016 Kitsune Ral <Kitsune-Ral@users.sf.net>
3 // SPDX-FileCopyrightText: 2017 Roman Plášil <me@rplasil.name>
4 // SPDX-License-Identifier: LGPL-2.1-or-later
5 
6 #pragma once
7 
8 #include "eventcontent.h"
9 #include "eventrelation.h"
10 #include "roomevent.h"
11 
12 class QFileInfo;
13 
14 namespace Quotient {
15 
16 /**
17  * The event class corresponding to m.room.message events
18  */
19 class QUOTIENT_API RoomMessageEvent : public RoomEvent {
20  Q_GADGET
21 public:
22  QUO_EVENT(RoomMessageEvent, "m.room.message")
23 
24  enum class MsgType {
25  Text,
26  Emote,
27  Notice,
28  Image,
29  File,
30  Location,
31  Video,
32  Audio,
33  Unknown
34  };
35 
36  RoomMessageEvent(const QString& plainBody, const QString& jsonMsgType,
37  EventContent::TypedBase* content = nullptr);
38  explicit RoomMessageEvent(const QString& plainBody,
39  MsgType msgType = MsgType::Text,
40  EventContent::TypedBase* content = nullptr);
41 
42  explicit RoomMessageEvent(const QJsonObject& obj);
43 
44  MsgType msgtype() const;
45  QString rawMsgtype() const;
46  QString plainBody() const;
47  const EventContent::TypedBase* content() const { return _content.data(); }
48  void editContent(auto visitor)
49  {
50  visitor(*_content);
51  editJson()[ContentKey] = assembleContentJson(plainBody(), rawMsgtype(), _content.data());
52  }
53  QMimeType mimeType() const;
54  //! \brief Determine whether the message has text content
55  //!
56  //! \return true, if the message type is one of m.text, m.notice, m.emote,
57  //! or the message type is unspecified (in which case plainBody()
58  //! can still be examined); false otherwise
59  bool hasTextContent() const;
60  //! \brief Determine whether the message has a file/attachment
61  //!
62  //! \return true, if the message has a data structure corresponding to
63  //! a file (such as m.file or m.audio); false otherwise
64  bool hasFileContent() const;
65  //! \brief Determine whether the message has a thumbnail
66  //!
67  //! \return true, if the message has a data structure corresponding to
68  //! a thumbnail (the message type may be one for visual content,
69  //! such as m.image, or generic binary content, i.e. m.file);
70  //! false otherwise
71  bool hasThumbnail() const;
72 
73  //! \brief Obtain id of an event replaced by the current one
74  //! \sa RoomEvent::isReplaced, RoomEvent::replacedBy
75  QString replacedEvent() const;
76 
77  //! \brief Determine whether the event has been replaced
78  //!
79  //! \return true if this event has been overridden by another event
80  //! with `"rel_type": "m.replace"`; false otherwise
81  bool isReplaced() const;
82 
83  QString replacedBy() const;
84 
85  QString fileNameToDownload() const;
86 
87  static QString rawMsgTypeForUrl(const QUrl& url);
88  static QString rawMsgTypeForFile(const QFileInfo& fi);
89 
90 private:
91  QScopedPointer<EventContent::TypedBase> _content;
92 
93  // FIXME: should it really be static?
94  static QJsonObject assembleContentJson(const QString& plainBody,
95  const QString& jsonMsgType,
96  EventContent::TypedBase* content);
97 
98  Q_ENUM(MsgType)
99 };
100 
101 using MessageEventType = RoomMessageEvent::MsgType;
102 
103 namespace EventContent {
104 
105  // Additional event content types
106 
107  /**
108  * Rich text content for m.text, m.emote, m.notice
109  *
110  * Available fields: mimeType, body. The body can be either rich text
111  * or plain text, depending on what mimeType specifies.
112  */
113  class QUOTIENT_API TextContent : public TypedBase {
114  public:
115  TextContent(QString text, const QString& contentType,
116  std::optional<EventRelation> relatesTo = {});
117  explicit TextContent(const QJsonObject& json);
118 
119  QMimeType type() const override { return mimeType; }
120 
121  QMimeType mimeType;
122  QString body;
123  std::optional<EventRelation> relatesTo;
124 
125  protected:
126  void fillJson(QJsonObject& json) const override;
127  };
128 
129  /**
130  * Content class for m.location
131  *
132  * Available fields:
133  * - corresponding to the top-level JSON:
134  * - geoUri ("geo_uri" in JSON)
135  * - corresponding to the "info" subobject:
136  * - thumbnail.url ("thumbnail_url" in JSON)
137  * - corresponding to the "info/thumbnail_info" subobject:
138  * - thumbnail.payloadSize
139  * - thumbnail.mimeType
140  * - thumbnail.imageSize
141  */
142  class QUOTIENT_API LocationContent : public TypedBase {
143  public:
144  LocationContent(const QString& geoUri, const Thumbnail& thumbnail = {});
145  explicit LocationContent(const QJsonObject& json);
146 
147  QMimeType type() const override;
148 
149  public:
150  QString geoUri;
151  Thumbnail thumbnail;
152 
153  protected:
154  void fillJson(QJsonObject& o) const override;
155  };
156 
157  /**
158  * A base class for info types that include duration: audio and video
159  */
160  template <typename InfoT>
161  class PlayableContent : public UrlBasedContent<InfoT> {
162  public:
163  using UrlBasedContent<InfoT>::UrlBasedContent;
164  PlayableContent(const QJsonObject& json)
165  : UrlBasedContent<InfoT>(json)
166  , duration(FileInfo::originalInfoJson["duration"_ls].toInt())
167  {}
168 
169  protected:
170  void fillInfoJson(QJsonObject& infoJson) const override
171  {
172  infoJson.insert(QStringLiteral("duration"), duration);
173  }
174 
175  public:
176  int duration;
177  };
178 
179  /**
180  * Content class for m.video
181  *
182  * Available fields:
183  * - corresponding to the top-level JSON:
184  * - url
185  * - filename (extension to the CS API spec)
186  * - corresponding to the "info" subobject:
187  * - payloadSize ("size" in JSON)
188  * - mimeType ("mimetype" in JSON)
189  * - duration
190  * - imageSize (QSize for a combination of "h" and "w" in JSON)
191  * - thumbnail.url ("thumbnail_url" in JSON)
192  * - corresponding to the "info/thumbnail_info" subobject: contents of
193  * thumbnail field, in the same vein as for "info":
194  * - payloadSize
195  * - mimeType
196  * - imageSize
197  */
198  using VideoContent = PlayableContent<ImageInfo>;
199 
200  /**
201  * Content class for m.audio
202  *
203  * Available fields:
204  * - corresponding to the top-level JSON:
205  * - url
206  * - filename (extension to the CS API spec)
207  * - corresponding to the "info" subobject:
208  * - payloadSize ("size" in JSON)
209  * - mimeType ("mimetype" in JSON)
210  * - duration
211  * - thumbnail.url ("thumbnail_url" in JSON - extension to the spec)
212  * - corresponding to the "info/thumbnail_info" subobject: contents of
213  * thumbnail field (extension to the spec):
214  * - payloadSize
215  * - mimeType
216  * - imageSize
217  */
218  using AudioContent = PlayableContent<FileInfo>;
219 } // namespace EventContent
220 } // namespace Quotient