aboutsummaryrefslogtreecommitdiff
path: root/lib/events/roommessageevent.cpp
diff options
context:
space:
mode:
authorKitsune Ral <Kitsune-Ral@users.sf.net>2019-08-02 09:32:49 +0900
committerKitsune Ral <Kitsune-Ral@users.sf.net>2019-08-02 09:32:49 +0900
commit35cfef7a4253d49a37e5ce21c337fbb3d2633c42 (patch)
treedfcc77c4e404b6b8f07a4c9ee6283e70e4723883 /lib/events/roommessageevent.cpp
parent5b37e15d6a57d3b689c88f5cfce7afea9787a034 (diff)
parent5b236dfe895c7766002559570aa29c9033009228 (diff)
downloadlibquotient-35cfef7a4253d49a37e5ce21c337fbb3d2633c42.tar.gz
libquotient-35cfef7a4253d49a37e5ce21c337fbb3d2633c42.zip
Merge branch 'master' into use-clang-format
Diffstat (limited to 'lib/events/roommessageevent.cpp')
-rw-r--r--lib/events/roommessageevent.cpp107
1 files changed, 82 insertions, 25 deletions
diff --git a/lib/events/roommessageevent.cpp b/lib/events/roommessageevent.cpp
index c7f17303..da8d59ca 100644
--- a/lib/events/roommessageevent.cpp
+++ b/lib/events/roommessageevent.cpp
@@ -30,12 +30,12 @@ using namespace EventContent;
using MsgType = RoomMessageEvent::MsgType;
-static const auto RelatesToKey = "m.relates_to"_ls;
-static const auto MsgTypeKey = "msgtype"_ls;
-static const auto BodyKey = "body"_ls;
-static const auto FormattedBodyKey = "formatted_body"_ls;
+static const auto RelatesToKeyL = "m.relates_to"_ls;
+static const auto MsgTypeKeyL = "msgtype"_ls;
+static const auto FormattedBodyKeyL = "formatted_body"_ls;
static const auto TextTypeKey = "m.text";
+static const auto EmoteTypeKey = "m.emote";
static const auto NoticeTypeKey = "m.notice";
static const auto HtmlContentTypeId = QStringLiteral("org.matrix.custom.html");
@@ -49,7 +49,7 @@ TypedBase* make(const QJsonObject& json)
template <>
TypedBase* make<TextContent>(const QJsonObject& json)
{
- return json.contains(FormattedBodyKey) || json.contains(RelatesToKey)
+ return json.contains(FormattedBodyKeyL) || json.contains(RelatesToKeyL)
? new TextContent(json)
: nullptr;
}
@@ -63,7 +63,7 @@ struct MsgTypeDesc
const std::vector<MsgTypeDesc> msgTypes = {
{ TextTypeKey, MsgType::Text, make<TextContent> },
- { QStringLiteral("m.emote"), MsgType::Emote, 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> },
@@ -101,11 +101,25 @@ QJsonObject RoomMessageEvent::assembleContentJson(const QString& plainBody,
TypedBase* content)
{
auto json = content ? content->toJson() : QJsonObject();
- if (jsonMsgType != TextTypeKey && jsonMsgType != NoticeTypeKey
- && json.contains(RelatesToKey)) {
- json.remove(RelatesToKey);
- qCWarning(EVENTS) << RelatesToKey << "cannot be used in" << jsonMsgType
- << "messages; the relation has been stripped off";
+ if (json.contains(RelatesToKeyL)) {
+ if (jsonMsgType != TextTypeKey && jsonMsgType != NoticeTypeKey
+ && jsonMsgType != EmoteTypeKey) {
+ json.remove(RelatesToKeyL);
+ qCWarning(EVENTS)
+ << RelatesToKeyL << "cannot be used in" << jsonMsgType
+ << "messages; the relation has been stripped off";
+ } else {
+ // 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);
+ if (textContent->relatesTo->type == RelatesTo::ReplacementTypeId()) {
+ auto newContentJson = json.take("m.new_content"_ls).toObject();
+ newContentJson.insert(BodyKey, plainBody);
+ newContentJson.insert(TypeKey, jsonMsgType);
+ json.insert(QStringLiteral("m.new_content"), newContentJson);
+ json[BodyKeyL] = "* " + plainBody;
+ }
+ }
}
json.insert(QStringLiteral("msgtype"), jsonMsgType);
json.insert(QStringLiteral("body"), plainBody);
@@ -166,8 +180,8 @@ RoomMessageEvent::RoomMessageEvent(const QJsonObject& obj)
if (isRedacted())
return;
const QJsonObject content = contentJson();
- if (content.contains(MsgTypeKey) && content.contains(BodyKey)) {
- auto msgtype = content[MsgTypeKey].toString();
+ if (content.contains(MsgTypeKeyL) && content.contains(BodyKeyL)) {
+ auto msgtype = content[MsgTypeKeyL].toString();
bool msgTypeFound = false;
for (const auto& mt : msgTypes)
if (mt.matrixType == msgtype) {
@@ -193,12 +207,12 @@ RoomMessageEvent::MsgType RoomMessageEvent::msgtype() const
QString RoomMessageEvent::rawMsgtype() const
{
- return contentJson()[MsgTypeKey].toString();
+ return contentJson()[MsgTypeKeyL].toString();
}
QString RoomMessageEvent::plainBody() const
{
- return contentJson()[BodyKey].toString();
+ return contentJson()[BodyKeyL].toString();
}
QMimeType RoomMessageEvent::mimeType() const
@@ -225,6 +239,17 @@ bool RoomMessageEvent::hasThumbnail() const
return content() && content()->thumbnailInfo();
}
+QString RoomMessageEvent::replacedEvent() const
+{
+ if (!content() || !hasTextContent())
+ return {};
+
+ const auto& rel = static_cast<const TextContent*>(content())->relatesTo;
+ return !rel.omitted() && rel->type == RelatesTo::ReplacementTypeId()
+ ? rel->eventId
+ : QString();
+}
+
QString rawMsgTypeForMimeType(const QMimeType& mimeType)
{
auto name = mimeType.name();
@@ -256,39 +281,71 @@ TextContent::TextContent(const QString& text, const QString& contentType,
mimeType = QMimeDatabase().mimeTypeForName("text/html");
}
+namespace QMatrixClient
+{
+// 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())
+ return none;
+ const auto replyJson = jo.value(RelatesTo::ReplyTypeId()).toObject();
+ if (!replyJson.isEmpty())
+ return replyTo(fromJson<QString>(replyJson[EventIdKeyL]));
+
+ return RelatesTo { jo.value("rel_type"_ls).toString(),
+ jo.value(EventIdKeyL).toString() };
+}
+} // namespace QMatrixClient
+
TextContent::TextContent(const QJsonObject& json)
+ : 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();
// Special-casing the custom matrix.org's (actually, Riot's) way
// of sending HTML messages.
- if (json["format"_ls].toString() == HtmlContentTypeId) {
+ if (actualJson["format"_ls].toString() == HtmlContentTypeId) {
mimeType = HtmlMimeType;
- body = json[FormattedBodyKey].toString();
+ body = actualJson[FormattedBodyKeyL].toString();
} else {
// Falling back to plain text, as there's no standard way to describe
// rich text in messages.
mimeType = PlainTextMimeType;
- body = json[BodyKey].toString();
+ body = actualJson[BodyKeyL].toString();
}
- const auto replyJson =
- json[RelatesToKey].toObject().value(RelatesTo::ReplyTypeId()).toObject();
- if (!replyJson.isEmpty())
- relatesTo = replyTo(fromJson<QString>(replyJson[EventIdKeyL]));
}
void TextContent::fillJson(QJsonObject* json) const
{
+ static const auto FormatKey = QStringLiteral("format");
+ static const auto FormattedBodyKey = QStringLiteral("formatted_body");
+
Q_ASSERT(json);
if (mimeType.inherits("text/html")) {
- json->insert(QStringLiteral("format"), HtmlContentTypeId);
- json->insert(QStringLiteral("formatted_body"), body);
+ json->insert(FormatKey, HtmlContentTypeId);
+ json->insert(FormattedBodyKey, body);
}
- if (!relatesTo.omitted())
+ if (!relatesTo.omitted()) {
json->insert(QStringLiteral("m.relates_to"),
QJsonObject { { relatesTo->type, relatesTo->eventId } });
+ if (relatesTo->type == RelatesTo::ReplacementTypeId()) {
+ QJsonObject newContentJson;
+ if (mimeType.inherits("text/html")) {
+ json->insert(FormatKey, HtmlContentTypeId);
+ json->insert(FormattedBodyKey, body);
+ }
+ json->insert(QStringLiteral("m.new_content"), newContentJson);
+ }
+ }
}
LocationContent::LocationContent(const QString& geoUri,