aboutsummaryrefslogtreecommitdiff
path: root/lib/events/roommessageevent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/events/roommessageevent.cpp')
-rw-r--r--lib/events/roommessageevent.cpp154
1 files changed, 81 insertions, 73 deletions
diff --git a/lib/events/roommessageevent.cpp b/lib/events/roommessageevent.cpp
index 1edf82e4..616a034f 100644
--- a/lib/events/roommessageevent.cpp
+++ b/lib/events/roommessageevent.cpp
@@ -13,26 +13,25 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "roommessageevent.h"
#include "logging.h"
-#include <QtCore/QMimeDatabase>
#include <QtCore/QFileInfo>
+#include <QtCore/QMimeDatabase>
#include <QtGui/QImageReader>
#include <QtMultimedia/QMediaResource>
-using namespace QMatrixClient;
+using namespace Quotient;
using namespace EventContent;
using MsgType = RoomMessageEvent::MsgType;
static const auto RelatesToKeyL = "m.relates_to"_ls;
static const auto MsgTypeKeyL = "msgtype"_ls;
-static const auto BodyKeyL = "body"_ls;
static const auto FormattedBodyKeyL = "formatted_body"_ls;
static const auto TextTypeKey = "m.text";
@@ -51,31 +50,33 @@ template <>
TypedBase* make<TextContent>(const QJsonObject& json)
{
return json.contains(FormattedBodyKeyL) || json.contains(RelatesToKeyL)
- ? new TextContent(json) : nullptr;
+ ? new TextContent(json)
+ : nullptr;
}
-struct MsgTypeDesc
-{
+struct MsgTypeDesc {
QString matrixType;
MsgType enumType;
TypedBase* (*maker)(const QJsonObject&);
};
-const std::vector<MsgTypeDesc> msgTypes =
- { { TextTypeKey, MsgType::Text, make<TextContent> }
- , { EmoteTypeKey, MsgType::Emote, make<TextContent> }
- , { NoticeTypeKey, MsgType::Notice, make<TextContent> }
- , { QStringLiteral("m.image"), MsgType::Image, make<ImageContent> }
- , { QStringLiteral("m.file"), MsgType::File, make<FileContent> }
- , { QStringLiteral("m.location"), MsgType::Location, make<LocationContent> }
- , { QStringLiteral("m.video"), MsgType::Video, make<VideoContent> }
- , { QStringLiteral("m.audio"), MsgType::Audio, make<AudioContent> }
- };
+const std::vector<MsgTypeDesc> msgTypes = {
+ { TextTypeKey, MsgType::Text, make<TextContent> },
+ { EmoteTypeKey, MsgType::Emote, make<TextContent> },
+ { NoticeTypeKey, MsgType::Notice, make<TextContent> },
+ { QStringLiteral("m.image"), MsgType::Image, make<ImageContent> },
+ { QStringLiteral("m.file"), MsgType::File, make<FileContent> },
+ { QStringLiteral("m.location"), MsgType::Location, make<LocationContent> },
+ { QStringLiteral("m.video"), MsgType::Video, make<VideoContent> },
+ { QStringLiteral("m.audio"), MsgType::Audio, make<AudioContent> }
+};
QString msgTypeToJson(MsgType enumType)
{
auto it = std::find_if(msgTypes.begin(), msgTypes.end(),
- [=](const MsgTypeDesc& mtd) { return mtd.enumType == enumType; });
+ [=](const MsgTypeDesc& mtd) {
+ return mtd.enumType == enumType;
+ });
if (it != msgTypes.end())
return it->matrixType;
@@ -85,15 +86,23 @@ QString msgTypeToJson(MsgType enumType)
MsgType jsonToMsgType(const QString& matrixType)
{
auto it = std::find_if(msgTypes.begin(), msgTypes.end(),
- [=](const MsgTypeDesc& mtd) { return mtd.matrixType == matrixType; });
+ [=](const MsgTypeDesc& mtd) {
+ return mtd.matrixType == matrixType;
+ });
if (it != msgTypes.end())
return it->enumType;
return MsgType::Unknown;
}
+inline bool isReplacement(const Omittable<RelatesTo>& rel)
+{
+ return rel && rel->type == RelatesTo::ReplacementTypeId();
+}
+
QJsonObject RoomMessageEvent::assembleContentJson(const QString& plainBody,
- const QString& jsonMsgType, TypedBase* content)
+ const QString& jsonMsgType,
+ TypedBase* content)
{
auto json = content ? content->toJson() : QJsonObject();
if (json.contains(RelatesToKeyL)) {
@@ -107,9 +116,10 @@ QJsonObject RoomMessageEvent::assembleContentJson(const QString& plainBody,
// After the above, we know for sure that the content is TextContent
// and that its RelatesTo structure is not omitted
auto* textContent = static_cast<const TextContent*>(content);
+ Q_ASSERT(textContent && textContent->relatesTo.has_value());
if (textContent->relatesTo->type == RelatesTo::ReplacementTypeId()) {
auto newContentJson = json.take("m.new_content"_ls).toObject();
- newContentJson.insert(BodyKeyL, plainBody);
+ newContentJson.insert(BodyKey, plainBody);
newContentJson.insert(MsgTypeKeyL, jsonMsgType);
json.insert(QStringLiteral("m.new_content"), newContentJson);
json[MsgTypeKeyL] = jsonMsgType;
@@ -124,24 +134,24 @@ QJsonObject RoomMessageEvent::assembleContentJson(const QString& plainBody,
}
RoomMessageEvent::RoomMessageEvent(const QString& plainBody,
- const QString& jsonMsgType, TypedBase* content)
+ const QString& jsonMsgType,
+ TypedBase* content)
: RoomEvent(typeId(), matrixTypeId(),
assembleContentJson(plainBody, jsonMsgType, content))
, _content(content)
-{ }
+{}
-RoomMessageEvent::RoomMessageEvent(const QString& plainBody,
- MsgType msgType, TypedBase* content)
+RoomMessageEvent::RoomMessageEvent(const QString& plainBody, MsgType msgType,
+ TypedBase* content)
: RoomMessageEvent(plainBody, msgTypeToJson(msgType), content)
-{ }
+{}
TypedBase* contentFromFile(const QFileInfo& file, bool asGenericFile)
{
auto filePath = file.absoluteFilePath();
auto localUrl = QUrl::fromLocalFile(filePath);
auto mimeType = QMimeDatabase().mimeTypeForFile(file);
- if (!asGenericFile)
- {
+ if (!asGenericFile) {
auto mimeTypeName = mimeType.name();
if (mimeTypeName.startsWith("image/"))
return new ImageContent(localUrl, file.size(), mimeType,
@@ -163,11 +173,12 @@ TypedBase* contentFromFile(const QFileInfo& file, bool asGenericFile)
}
RoomMessageEvent::RoomMessageEvent(const QString& plainBody,
- const QFileInfo& file, bool asGenericFile)
+ const QFileInfo& file, bool asGenericFile)
: RoomMessageEvent(plainBody,
- asGenericFile ? QStringLiteral("m.file") : rawMsgTypeForFile(file),
- contentFromFile(file, asGenericFile))
-{ }
+ asGenericFile ? QStringLiteral("m.file")
+ : rawMsgTypeForFile(file),
+ contentFromFile(file, asGenericFile))
+{}
RoomMessageEvent::RoomMessageEvent(const QJsonObject& obj)
: RoomEvent(typeId(), obj), _content(nullptr)
@@ -175,26 +186,21 @@ RoomMessageEvent::RoomMessageEvent(const QJsonObject& obj)
if (isRedacted())
return;
const QJsonObject content = contentJson();
- if ( content.contains(MsgTypeKeyL) && content.contains(BodyKeyL) )
- {
+ if (content.contains(MsgTypeKeyL) && content.contains(BodyKeyL)) {
auto msgtype = content[MsgTypeKeyL].toString();
bool msgTypeFound = false;
- for (const auto& mt: msgTypes)
- if (mt.matrixType == msgtype)
- {
+ for (const auto& mt : msgTypes)
+ if (mt.matrixType == msgtype) {
_content.reset(mt.maker(content));
msgTypeFound = true;
}
- if (!msgTypeFound)
- {
+ if (!msgTypeFound) {
qCWarning(EVENTS) << "RoomMessageEvent: unknown msg_type,"
<< " full content dump follows";
qCWarning(EVENTS) << formatJson << content;
}
- }
- else
- {
+ } else {
qCWarning(EVENTS) << "No body or msgtype in room message event";
qCWarning(EVENTS) << formatJson << obj;
}
@@ -218,15 +224,15 @@ QString RoomMessageEvent::plainBody() const
QMimeType RoomMessageEvent::mimeType() const
{
static const auto PlainTextMimeType =
- QMimeDatabase().mimeTypeForName("text/plain");
+ QMimeDatabase().mimeTypeForName("text/plain");
return _content ? _content->type() : PlainTextMimeType;
}
bool RoomMessageEvent::hasTextContent() const
{
- return !content() ||
- (msgtype() == MsgType::Text || msgtype() == MsgType::Emote ||
- msgtype() == MsgType::Notice);
+ return !content()
+ || (msgtype() == MsgType::Text || msgtype() == MsgType::Emote
+ || msgtype() == MsgType::Notice);
}
bool RoomMessageEvent::hasFileContent() const
@@ -245,17 +251,18 @@ QString RoomMessageEvent::replacedEvent() const
return {};
const auto& rel = static_cast<const TextContent*>(content())->relatesTo;
- return !rel.omitted() && rel->type == RelatesTo::ReplacementTypeId()
- ? rel->eventId : QString();
+ return isReplacement(rel) ? rel->eventId : QString();
}
QString rawMsgTypeForMimeType(const QMimeType& mimeType)
{
auto name = mimeType.name();
- return name.startsWith("image/") ? QStringLiteral("m.image") :
- name.startsWith("video/") ? QStringLiteral("m.video") :
- name.startsWith("audio/") ? QStringLiteral("m.audio") :
- QStringLiteral("m.file");
+ return name.startsWith("image/")
+ ? QStringLiteral("m.image")
+ : name.startsWith("video/")
+ ? QStringLiteral("m.video")
+ : name.startsWith("audio/") ? QStringLiteral("m.audio")
+ : QStringLiteral("m.file");
}
QString RoomMessageEvent::rawMsgTypeForUrl(const QUrl& url)
@@ -268,18 +275,21 @@ QString RoomMessageEvent::rawMsgTypeForFile(const QFileInfo& fi)
return rawMsgTypeForMimeType(QMimeDatabase().mimeTypeForFile(fi));
}
-TextContent::TextContent(const QString& text, const QString& contentType,
+TextContent::TextContent(QString text, const QString& contentType,
Omittable<RelatesTo> relatesTo)
- : mimeType(QMimeDatabase().mimeTypeForName(contentType)), body(text)
+ : mimeType(QMimeDatabase().mimeTypeForName(contentType))
+ , body(std::move(text))
, relatesTo(std::move(relatesTo))
{
if (contentType == HtmlContentTypeId)
mimeType = QMimeDatabase().mimeTypeForName("text/html");
}
-namespace QMatrixClient
-{
-Omittable<RelatesTo> relationFromJson(const QJsonValue& jv)
+namespace Quotient {
+// Overload the default fromJson<> logic that defined in converters.h
+// as we want
+template <>
+Omittable<RelatesTo> fromJson(const QJsonValue& jv)
{
const auto jo = jv.toObject();
if (jo.isEmpty())
@@ -291,22 +301,21 @@ Omittable<RelatesTo> relationFromJson(const QJsonValue& jv)
return RelatesTo { jo.value("rel_type"_ls).toString(),
jo.value(EventIdKeyL).toString() };
}
-}
+} // namespace Quotient
TextContent::TextContent(const QJsonObject& json)
- : relatesTo(relationFromJson(json[RelatesToKeyL]))
+ : relatesTo(fromJson<Omittable<RelatesTo>>(json[RelatesToKeyL]))
{
QMimeDatabase db;
static const auto PlainTextMimeType = db.mimeTypeForName("text/plain");
static const auto HtmlMimeType = db.mimeTypeForName("text/html");
- const auto actualJson =
- relatesTo.omitted() || relatesTo->type != RelatesTo::ReplacementTypeId()
- ? json : json.value("m.new_content"_ls).toObject();
+ const auto actualJson = isReplacement(relatesTo)
+ ? json.value("m.new_content"_ls).toObject()
+ : json;
// Special-casing the custom matrix.org's (actually, Riot's) way
// of sending HTML messages.
- if (actualJson["format"_ls].toString() == HtmlContentTypeId)
- {
+ if (actualJson["format"_ls].toString() == HtmlContentTypeId) {
mimeType = HtmlMimeType;
body = actualJson[FormattedBodyKeyL].toString();
} else {
@@ -320,22 +329,21 @@ TextContent::TextContent(const QJsonObject& json)
void TextContent::fillJson(QJsonObject* json) const
{
static const auto FormatKey = QStringLiteral("format");
- static const auto RichBodyKey = QStringLiteral("formatted_body");
+ static const auto FormattedBodyKey = QStringLiteral("formatted_body");
Q_ASSERT(json);
- if (mimeType.inherits("text/html"))
- {
+ if (mimeType.inherits("text/html")) {
json->insert(FormatKey, HtmlContentTypeId);
- json->insert(RichBodyKey, body);
+ json->insert(FormattedBodyKey, body);
}
- if (!relatesTo.omitted()) {
+ if (relatesTo) {
json->insert(QStringLiteral("m.relates_to"),
- QJsonObject { { relatesTo->type, relatesTo->eventId } });
+ QJsonObject { { "rel_type", relatesTo->type }, { EventIdKey, relatesTo->eventId } });
if (relatesTo->type == RelatesTo::ReplacementTypeId()) {
QJsonObject newContentJson;
if (mimeType.inherits("text/html")) {
json->insert(FormatKey, HtmlContentTypeId);
- json->insert(RichBodyKey, body);
+ json->insert(FormattedBodyKey, body);
}
json->insert(QStringLiteral("m.new_content"), newContentJson);
}
@@ -345,13 +353,13 @@ void TextContent::fillJson(QJsonObject* json) const
LocationContent::LocationContent(const QString& geoUri,
const Thumbnail& thumbnail)
: geoUri(geoUri), thumbnail(thumbnail)
-{ }
+{}
LocationContent::LocationContent(const QJsonObject& json)
: TypedBase(json)
, geoUri(json["geo_uri"_ls].toString())
, thumbnail(json["info"_ls].toObject())
-{ }
+{}
QMimeType LocationContent::type() const
{