diff options
Diffstat (limited to 'events/roommessageevent.cpp')
-rw-r--r-- | events/roommessageevent.cpp | 229 |
1 files changed, 122 insertions, 107 deletions
diff --git a/events/roommessageevent.cpp b/events/roommessageevent.cpp index 48f52453..09465238 100644 --- a/events/roommessageevent.cpp +++ b/events/roommessageevent.cpp @@ -19,7 +19,7 @@ #include "roommessageevent.h" #include <QtCore/QJsonObject> -#include <QtCore/QDateTime> +#include <QtCore/QMimeDatabase> #include <QtCore/QDebug> using namespace QMatrixClient; @@ -27,20 +27,18 @@ using namespace QMatrixClient; class RoomMessageEvent::Private { public: - Private() {} + Private() : msgtype(MessageEventType::Unknown), content(nullptr) {} QString userId; MessageEventType msgtype; - QDateTime hsob_ts; - MessageEventContent* content; + QString plainBody; + MessageEventContent::Base* content; }; RoomMessageEvent::RoomMessageEvent() : Event(EventType::RoomMessage) , d(new Private) -{ - d->content = nullptr; -} +{ } RoomMessageEvent::~RoomMessageEvent() { @@ -57,21 +55,42 @@ MessageEventType RoomMessageEvent::msgtype() const return d->msgtype; } +QString RoomMessageEvent::plainBody() const +{ + return d->plainBody; +} + QString RoomMessageEvent::body() const { - return d->content->body; + return plainBody(); } -QDateTime RoomMessageEvent::hsob_ts() const +using namespace MessageEventContent; + +Base* RoomMessageEvent::content() const { - return d->hsob_ts; + return d->content; } -MessageEventContent* RoomMessageEvent::content() const +template <class ContentT> +Base* make(const QJsonObject& json) { - return d->content; + return new ContentT(json); } +Base* makeVideoContent(const QJsonObject& json) +{ + auto c = new VideoContent(json); + // Only for m.video, the spec puts a thumbnail inside "info" JSON key. Once + // this is fixed, VideoContent creation will switch to make<>(). + const QJsonObject infoJson = json["info"].toObject(); + if (infoJson.contains("thumbnail_url")) + c->thumbnail = ImageInfo(infoJson["thumbnail_url"].toString(), + infoJson["thumbnail_info"].toObject()); + + return c; +}; + RoomMessageEvent* RoomMessageEvent::fromJson(const QJsonObject& obj) { RoomMessageEvent* e = new RoomMessageEvent(); @@ -84,107 +103,103 @@ RoomMessageEvent* RoomMessageEvent::fromJson(const QJsonObject& obj) } if( obj.contains("content") ) { - QJsonObject content = obj.value("content").toObject(); - QString msgtype = content.value("msgtype").toString(); - - if( msgtype == "m.text" ) - { - e->d->msgtype = MessageEventType::Text; - e->d->content = new MessageEventContent(); - } - else if( msgtype == "m.emote" ) - { - e->d->msgtype = MessageEventType::Emote; - e->d->content = new MessageEventContent(); - } - else if( msgtype == "m.notice" ) - { - e->d->msgtype = MessageEventType::Notice; - e->d->content = new MessageEventContent(); - } - else if( msgtype == "m.image" ) - { - e->d->msgtype = MessageEventType::Image; - ImageEventContent* c = new ImageEventContent; - c->url = QUrl(content.value("url").toString()); - QJsonObject info = content.value("info").toObject(); - c->height = info.value("h").toInt(); - c->width = info.value("w").toInt(); - c->size = info.value("size").toInt(); - c->mimetype = info.value("mimetype").toString(); - e->d->content = c; - } - else if( msgtype == "m.file" ) - { - e->d->msgtype = MessageEventType::File; - FileEventContent* c = new FileEventContent; - c->filename = content.value("filename").toString(); - c->url = QUrl(content.value("url").toString()); - QJsonObject info = content.value("info").toObject(); - c->size = info.value("size").toInt(); - c->mimetype = info.value("mimetype").toString(); - e->d->content = c; - } - else if( msgtype == "m.location" ) - { - e->d->msgtype = MessageEventType::Location; - LocationEventContent* c = new LocationEventContent; - c->geoUri = content.value("geo_uri").toString(); - c->thumbnailUrl = QUrl(content.value("thumbnail_url").toString()); - QJsonObject info = content.value("thumbnail_info").toObject(); - c->thumbnailHeight = info.value("h").toInt(); - c->thumbnailWidth = info.value("w").toInt(); - c->thumbnailSize = info.value("size").toInt(); - c->thumbnailMimetype = info.value("mimetype").toString(); - e->d->content = c; - } - else if( msgtype == "m.video" ) + const QJsonObject content = obj["content"].toObject(); + if ( content.contains("msgtype") && content.contains("body") ) { - e->d->msgtype = MessageEventType::Video; - VideoEventContent* c = new VideoEventContent; - c->url = QUrl(content.value("url").toString()); - QJsonObject info = content.value("info").toObject(); - c->height = info.value("h").toInt(); - c->width = info.value("w").toInt(); - c->duration = info.value("duration").toInt(); - c->size = info.value("size").toInt(); - c->thumbnailUrl = QUrl(info.value("thumnail_url").toString()); - QJsonObject thumbnailInfo = content.value("thumbnail_info").toObject(); - c->thumbnailHeight = thumbnailInfo.value("h").toInt(); - c->thumbnailWidth = thumbnailInfo.value("w").toInt(); - c->thumbnailSize = thumbnailInfo.value("size").toInt(); - c->thumbnailMimetype = thumbnailInfo.value("mimetype").toString(); - e->d->content = c; - } - else if( msgtype == "m.audio" ) - { - e->d->msgtype = MessageEventType::Audio; - AudioEventContent* c = new AudioEventContent; - c->url = QUrl(content.value("url").toString()); - QJsonObject info = content.value("info").toObject(); - c->duration = info.value("duration").toInt(); - c->mimetype = info.value("mimetype").toString(); - c->size = info.value("size").toInt(); - e->d->content = c; + e->d->plainBody = content["body"].toString(); + + struct Factory + { + QString jsonTag; + MessageEventType enumTag; + Base*(*make)(const QJsonObject& json); + }; + + const Factory factories[] { + { "m.text", MessageEventType::Text, make<TextContent> }, + { "m.emote", MessageEventType::Emote, make<TextContent> }, + { "m.notice", MessageEventType::Notice, make<TextContent> }, + { "m.image", MessageEventType::Image, make<ImageContent> }, + { "m.file", MessageEventType::File, make<FileContent> }, + { "m.location", MessageEventType::Location, make<LocationContent> }, + { "m.video", MessageEventType::Video, makeVideoContent }, + { "m.audio", MessageEventType::Audio, make<AudioContent> }, + // Insert new message types before this line + }; + + QString msgtype = content.value("msgtype").toString(); + for (auto f: factories) + { + if (msgtype == f.jsonTag) + { + e->d->msgtype = f.enumTag; + e->d->content = f.make(content); + break; + } + } + if (e->d->msgtype == MessageEventType::Unknown) + { + qDebug() << "RoomMessageEvent: unknown msgtype: " << msgtype; + qDebug() << obj; + e->d->content = new Base; + } } else { - qDebug() << "RoomMessageEvent: unknown msgtype: " << msgtype; + qWarning() << "RoomMessageEvent(" << e->id() << "): no body or msgtype"; qDebug() << obj; - e->d->msgtype = MessageEventType::Unknown; - e->d->content = new MessageEventContent; - } - - if( content.contains("body") ) - { - e->d->content->body = content.value("body").toString(); - } else { - qDebug() << "RoomMessageEvent: body not found"; } -// e->d->hsob_ts = QDateTime::fromMSecsSinceEpoch( content.value("hsoc_ts").toInt() ); -// } else { -// qDebug() << "RoomMessageEvent: hsoc_ts not found"; -// } } return e; } + +using namespace MessageEventContent; + +TextContent::TextContent(const QJsonObject& json) +{ + QMimeDatabase db; + + // Special-casing the custom matrix.org's (actually, Vector's) way + // of sending HTML messages. + if (json["format"].toString() == "org.matrix.custom.html") + { + mimeType = db.mimeTypeForName("text/html"); + body = json["formatted_body"].toString(); + } else { + // Best-guessing from the content + body = json["body"].toString(); + mimeType = db.mimeTypeForData(body.toUtf8()); + } +} + +FileInfo::FileInfo(QUrl u, const QJsonObject& infoJson, QString originalFilename) + : url(u) + , fileSize(infoJson["size"].toInt()) + , mimetype(QMimeDatabase().mimeTypeForName(infoJson["mimetype"].toString())) + , originalName(originalFilename) +{ + if (!mimetype.isValid()) + mimetype = QMimeDatabase().mimeTypeForData(QByteArray()); +} + +ImageInfo::ImageInfo(QUrl u, const QJsonObject& infoJson) + : FileInfo(u, infoJson) + , imageSize(infoJson["w"].toInt(), infoJson["h"].toInt()) +{ } + +LocationContent::LocationContent(const QJsonObject& json) + : geoUri(json["geo_uri"].toString()) + , thumbnail(json["thumbnail_url"].toString(), + json["thumbnail_info"].toObject()) +{ } + +VideoInfo::VideoInfo(QUrl u, const QJsonObject& infoJson) + : FileInfo(u, infoJson) + , duration(infoJson["duration"].toInt()) + , imageSize(infoJson["w"].toInt(), infoJson["h"].toInt()) +{ } + +AudioInfo::AudioInfo(QUrl u, const QJsonObject& infoJson) + : FileInfo(u, infoJson) + , duration(infoJson["duration"].toInt()) +{ } |