File indexing completed on 2024-10-06 12:54:22
0001 /* 0002 SPDX-FileCopyrightText: 2017-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "message.h" 0008 #include "ruqola_debug.h" 0009 #include <KLocalizedString> 0010 #include <QCborValue> 0011 #include <QDateTime> 0012 #include <QJsonArray> 0013 #include <QJsonDocument> 0014 0015 Message::Message(EmojiManager *emojiManager) 0016 : mEmojiManager(emojiManager) 0017 { 0018 } 0019 0020 Message::~Message() = default; 0021 0022 void Message::parseMessage(const QJsonObject &o, bool restApi) 0023 { 0024 const QString roomId = o.value(QLatin1String("rid")).toString(); 0025 0026 // t ? I can't find it. 0027 const QString type = o.value(QLatin1String("t")).toString(); 0028 0029 mMessageId = o.value(QLatin1String("_id")).toString(); 0030 mRoomId = roomId; 0031 mText = o.value(QLatin1String("msg")).toString(); 0032 if (restApi) { 0033 mUpdatedAt = Utils::parseIsoDate(QStringLiteral("_updatedAt"), o); 0034 setEditedAt(Utils::parseIsoDate(QStringLiteral("editedAt"), o)); 0035 setTimeStamp(Utils::parseIsoDate(QStringLiteral("ts"), o)); 0036 mThreadLastMessage = Utils::parseIsoDate(QStringLiteral("tlm"), o); 0037 mDiscussionLastMessage = Utils::parseIsoDate(QStringLiteral("dlm"), o); 0038 } else { 0039 setTimeStamp(Utils::parseDate(QStringLiteral("ts"), o)); 0040 mUpdatedAt = Utils::parseDate(QStringLiteral("_updatedAt"), o); 0041 setEditedAt(Utils::parseDate(QStringLiteral("editedAt"), o)); 0042 // Verify if a day we will use not restapi for it. 0043 mThreadLastMessage = Utils::parseDate(QStringLiteral("tlm"), o); 0044 // Verify if a day we will use not restapi for it. 0045 mDiscussionLastMessage = Utils::parseDate(QStringLiteral("dlm"), o); 0046 } 0047 0048 QStringList lst; 0049 const QJsonArray replieArray = o.value(QLatin1String("replies")).toArray(); 0050 const auto nbReplieArrayCount{replieArray.count()}; 0051 lst.reserve(nbReplieArrayCount); 0052 for (auto i = 0; i < nbReplieArrayCount; ++i) { 0053 lst.append(replieArray.at(i).toVariant().toString()); 0054 } 0055 mReplies = lst; 0056 0057 const auto userObject = o.value(QLatin1String("u")).toObject(); 0058 mUsername = userObject.value(QLatin1String("username")).toString(); 0059 mName = userObject.value(QLatin1String("name")).toString(); 0060 mUserId = userObject.value(QLatin1String("_id")).toString(); 0061 mEditedByUsername = o.value(QLatin1String("editedBy")).toObject().value(QLatin1String("username")).toString(); 0062 mEditedByUserId = o.value(QLatin1String("editedBy")).toObject().value(QLatin1String("_id")).toString(); 0063 mAlias = o.value(QLatin1String("alias")).toString(); 0064 mAvatar = o.value(QLatin1String("avatar")).toString(); 0065 mGroupable = o.value(QLatin1String("groupable")).toBool(/*true*/ false); // Laurent, disable for the moment groupable 0066 mParseUrls = o.value(QLatin1String("parseUrls")).toBool(); 0067 mRole = o.value(QLatin1String("role")).toString(); 0068 mThreadCount = o.value(QLatin1String("tcount")).toInt(); 0069 mDiscussionCount = o.value(QLatin1String("dcount")).toInt(); 0070 mDiscussionRoomId = o.value(QLatin1String("drid")).toString(); 0071 mThreadMessageId = o.value(QLatin1String("tmid")).toString(); 0072 mEmoji = o.value(QLatin1String("emoji")).toString(); 0073 mMessageStarred.parse(o); 0074 mMessagePinned.parse(o); 0075 mMessageTranslation.parse(o); 0076 0077 mMessageType = Message::MessageType::NormalText; 0078 if (!type.isEmpty()) { 0079 if (type == QLatin1String("videoconf")) { 0080 mMessageType = VideoConference; 0081 // qDebug() << " VIDEO " << o; 0082 } else { 0083 mSystemMessageType = type; 0084 mMessageType = System; 0085 } 0086 } 0087 parseBlocks(o.value(QLatin1String("blocks")).toArray()); 0088 parseMentions(o.value(QLatin1String("mentions")).toArray()); 0089 0090 parseAttachment(o.value(QLatin1String("attachments")).toArray()); 0091 parseUrls(o.value(QLatin1String("urls")).toArray()); 0092 parseReactions(o.value(QLatin1String("reactions")).toObject()); 0093 parseChannels(o.value(QLatin1String("channels")).toArray()); 0094 // TODO unread element 0095 } 0096 0097 void Message::parseReactions(const QJsonObject &reacts) 0098 { 0099 if (!reacts.isEmpty()) { 0100 mReactions.parseReactions(reacts, mEmojiManager); 0101 } 0102 } 0103 0104 QString Message::editedDisplayTime() const 0105 { 0106 return mEditedDisplayTime; 0107 } 0108 0109 bool Message::isEditingMode() const 0110 { 0111 return mIsEditingMode; 0112 } 0113 0114 void Message::setIsEditingMode(bool isEditingMode) 0115 { 0116 mIsEditingMode = isEditingMode; 0117 } 0118 0119 bool Message::showIgnoredMessage() const 0120 { 0121 return mShowIgnoredMessage; 0122 } 0123 0124 void Message::setShowIgnoredMessage(bool showIgnoredMessage) 0125 { 0126 mShowIgnoredMessage = showIgnoredMessage; 0127 } 0128 0129 bool Message::pendingMessage() const 0130 { 0131 return mPendingMessage; 0132 } 0133 0134 void Message::setPendingMessage(bool pendingMessage) 0135 { 0136 mPendingMessage = pendingMessage; 0137 } 0138 0139 QString Message::emoji() const 0140 { 0141 return mEmoji; 0142 } 0143 0144 void Message::setEmoji(const QString &emoji) 0145 { 0146 mEmoji = emoji; 0147 } 0148 0149 QStringList Message::replies() const 0150 { 0151 return mReplies; 0152 } 0153 0154 void Message::setReplies(const QStringList &replies) 0155 { 0156 mReplies = replies; 0157 } 0158 0159 QString Message::name() const 0160 { 0161 return mName; 0162 } 0163 0164 void Message::setName(const QString &name) 0165 { 0166 mName = name; 0167 } 0168 0169 bool Message::isAutoTranslated() const 0170 { 0171 return !mMessageTranslation.translatedString().isEmpty(); 0172 } 0173 0174 bool Message::showTranslatedMessage() const 0175 { 0176 return mShowTranslatedMessage; 0177 } 0178 0179 void Message::setShowTranslatedMessage(bool showOriginalMessage) 0180 { 0181 mShowTranslatedMessage = showOriginalMessage; 0182 } 0183 0184 MessageTranslation Message::messageTranslation() const 0185 { 0186 return mMessageTranslation; 0187 } 0188 0189 void Message::setMessageTranslation(const MessageTranslation &messageTranslation) 0190 { 0191 mMessageTranslation = messageTranslation; 0192 } 0193 0194 QString Message::displayTime() const 0195 { 0196 return mDisplayTime; 0197 } 0198 0199 QString Message::threadMessageId() const 0200 { 0201 return mThreadMessageId; 0202 } 0203 0204 void Message::setThreadMessageId(const QString &threadMessageId) 0205 { 0206 mThreadMessageId = threadMessageId; 0207 } 0208 0209 QString Message::discussionRoomId() const 0210 { 0211 return mDiscussionRoomId; 0212 } 0213 0214 void Message::setDiscussionRoomId(const QString &discussionRoomId) 0215 { 0216 mDiscussionRoomId = discussionRoomId; 0217 } 0218 0219 int Message::discussionCount() const 0220 { 0221 return mDiscussionCount; 0222 } 0223 0224 void Message::setDiscussionCount(int discussionCount) 0225 { 0226 mDiscussionCount = discussionCount; 0227 } 0228 0229 qint64 Message::discussionLastMessage() const 0230 { 0231 return mDiscussionLastMessage; 0232 } 0233 0234 void Message::setDiscussionLastMessage(qint64 discussionLastMessage) 0235 { 0236 mDiscussionLastMessage = discussionLastMessage; 0237 } 0238 0239 qint64 Message::threadLastMessage() const 0240 { 0241 return mThreadLastMessage; 0242 } 0243 0244 void Message::setThreadLastMessage(qint64 threadLastMessage) 0245 { 0246 mThreadLastMessage = threadLastMessage; 0247 } 0248 0249 int Message::threadCount() const 0250 { 0251 return mThreadCount; 0252 } 0253 0254 void Message::setThreadCount(int threadCount) 0255 { 0256 mThreadCount = threadCount; 0257 } 0258 0259 MessageStarred Message::messageStarred() const 0260 { 0261 return mMessageStarred; 0262 } 0263 0264 void Message::setMessageStarred(MessageStarred messageStarred) 0265 { 0266 mMessageStarred = messageStarred; 0267 } 0268 0269 MessagePinned Message::messagePinned() const 0270 { 0271 return mMessagePinned; 0272 } 0273 0274 void Message::setMessagePinned(const MessagePinned &messagePinned) 0275 { 0276 mMessagePinned = messagePinned; 0277 } 0278 0279 bool Message::unread() const 0280 { 0281 return mUnread; 0282 } 0283 0284 void Message::setUnread(bool unread) 0285 { 0286 mUnread = unread; 0287 } 0288 0289 QString Message::role() const 0290 { 0291 return mRole; 0292 } 0293 0294 void Message::setRole(const QString &role) 0295 { 0296 mRole = role; 0297 } 0298 0299 void Message::parseChannels(const QJsonArray &channels) 0300 { 0301 mChannels.clear(); 0302 for (int i = 0, total = channels.size(); i < total; ++i) { 0303 const QJsonObject mention = channels.at(i).toObject(); 0304 mChannels.insert(mention.value(QLatin1String("name")).toString(), mention.value(QLatin1String("_id")).toString()); 0305 } 0306 } 0307 0308 QVector<Block> Message::blocks() const 0309 { 0310 return mBlocks; 0311 } 0312 0313 void Message::setBlocks(const QVector<Block> &newBlocks) 0314 { 0315 mBlocks = newBlocks; 0316 } 0317 0318 QString Message::originalMessageOrAttachmentDescription() const 0319 { 0320 if (attachments().empty()) { 0321 return text(); 0322 } 0323 return attachments().constFirst().description(); 0324 } 0325 0326 const QString &Message::localTranslation() const 0327 { 0328 return mLocalTranslation; 0329 } 0330 0331 void Message::setLocalTranslation(const QString &newLocalTranslation) 0332 { 0333 mLocalTranslation = newLocalTranslation; 0334 } 0335 0336 bool Message::hoverHighlight() const 0337 { 0338 return mHoverHighlight; 0339 } 0340 0341 void Message::setHoverHighlight(bool newShowReactionIcon) 0342 { 0343 mHoverHighlight = newShowReactionIcon; 0344 } 0345 0346 const QMap<QString, QString> &Message::channels() const 0347 { 0348 return mChannels; 0349 } 0350 0351 void Message::setChannels(const QMap<QString, QString> &newChannels) 0352 { 0353 mChannels = newChannels; 0354 } 0355 0356 void Message::parseBlocks(const QJsonArray &blocks) 0357 { 0358 mBlocks.clear(); 0359 for (int i = 0, total = blocks.count(); i < total; ++i) { 0360 const QJsonObject blockObject = blocks.at(i).toObject(); 0361 Block b; 0362 b.parseBlock(blockObject); 0363 if (b.isValid()) { 0364 mBlocks.append(std::move(b)); 0365 } 0366 } 0367 } 0368 0369 ModerationMessage Message::moderationMessage() const 0370 { 0371 return mModerationMessage; 0372 } 0373 0374 void Message::setModerationMessage(const ModerationMessage &newModerationMessage) 0375 { 0376 mModerationMessage = newModerationMessage; 0377 } 0378 0379 QColor Message::goToMessageBackgroundColor() const 0380 { 0381 return mGoToMessageBackgroundColor; 0382 } 0383 0384 void Message::setGoToMessageBackgroundColor(const QColor &newGoToMessageBackgroundColor) 0385 { 0386 mGoToMessageBackgroundColor = newGoToMessageBackgroundColor; 0387 } 0388 0389 void Message::setVideoConferenceInfo(const VideoConferenceInfo &info) 0390 { 0391 auto it = std::find_if(mBlocks.cbegin(), mBlocks.cend(), [info](const auto &block) { 0392 return block.blockId() == info.blockId(); 0393 }); 0394 if (it != mBlocks.cend()) { 0395 mBlocks.removeAll(*it); 0396 Block b(*it); 0397 b.setVideoConferenceInfo(info); 0398 mBlocks.append(b); 0399 } 0400 } 0401 0402 void Message::parseMentions(const QJsonArray &mentions) 0403 { 0404 mMentions.clear(); 0405 for (int i = 0; i < mentions.size(); i++) { 0406 const QJsonObject mention = mentions.at(i).toObject(); 0407 mMentions.insert(mention.value(QLatin1String("username")).toString(), mention.value(QLatin1String("_id")).toString()); 0408 } 0409 } 0410 0411 void Message::parseUrls(const QJsonArray &urls) 0412 { 0413 mUrls.clear(); 0414 if (!urls.isEmpty()) { 0415 qCDebug(RUQOLA_LOG) << " void Message::urls(const QJsonObject &attachments)" << urls; 0416 for (int i = 0; i < urls.size(); i++) { 0417 const QJsonObject url = urls.at(i).toObject(); 0418 MessageUrl messageUrl; 0419 messageUrl.setUrlId(Message::generateUniqueId(mMessageId, i)); 0420 messageUrl.parseUrl(url); 0421 if (!messageUrl.isEmpty()) { 0422 mUrls.append(messageUrl); 0423 } 0424 } 0425 } 0426 } 0427 0428 Reactions Message::reactions() const 0429 { 0430 return mReactions; 0431 } 0432 0433 void Message::setReactions(const Reactions &reactions) 0434 { 0435 mReactions = reactions; 0436 } 0437 0438 bool Message::isPinned() const 0439 { 0440 return mMessagePinned.pinned(); 0441 } 0442 0443 bool Message::isStarred() const 0444 { 0445 return mMessageStarred.isStarred(); 0446 } 0447 0448 void Message::setIsStarred(bool starred) 0449 { 0450 mMessageStarred.setIsStarred(starred); 0451 } 0452 0453 QMap<QString, QString> Message::mentions() const 0454 { 0455 return mMentions; 0456 } 0457 0458 void Message::setMentions(const QMap<QString, QString> &mentions) 0459 { 0460 mMentions = mentions; 0461 } 0462 0463 void Message::parseAttachment(const QJsonArray &attachments) 0464 { 0465 mAttachments.clear(); 0466 if (!attachments.isEmpty()) { 0467 // qDebug() << " void Message::parseAttachment(const QJsonObject &attachments)"<<attachments; 0468 for (int i = 0; i < attachments.size(); i++) { 0469 const QJsonObject attachment = attachments.at(i).toObject(); 0470 MessageAttachment messageAttachement; 0471 messageAttachement.parseAttachment(attachment); 0472 messageAttachement.setAttachmentId(Message::generateUniqueId(messageId(), i)); 0473 if (messageAttachement.isValid()) { 0474 mAttachments.append(messageAttachement); 0475 } 0476 } 0477 } 0478 } 0479 0480 bool Message::operator==(const Message &other) const 0481 { 0482 return (mMessageId == other.messageId()) && (mRoomId == other.roomId()) && (mText == other.text()) && (mTimeStamp == other.timeStamp()) 0483 && (mUsername == other.username()) && (mName == other.name()) && (mUserId == other.userId()) && (mUpdatedAt == other.updatedAt()) 0484 && (mEditedAt == other.editedAt()) && (mEditedByUsername == other.editedByUsername()) && (mEditedByUserId == other.editedByUserId()) 0485 && (mAlias == other.alias()) && (mAvatar == other.avatar()) && (mSystemMessageType == other.systemMessageType()) && (mGroupable == other.groupable()) 0486 && (mParseUrls == other.parseUrls()) && (mUrls == other.urls()) && (mAttachments == other.attachments()) && (mMentions == other.mentions()) 0487 && (mRole == other.role()) && (mReactions == other.reactions()) && (mUnread == other.unread()) && (mMessagePinned == other.messagePinned()) 0488 && (mMessageStarred == other.messageStarred()) && (mThreadCount == other.threadCount()) && (mThreadLastMessage == other.threadLastMessage()) 0489 && (mDiscussionCount == other.discussionCount()) && (mDiscussionLastMessage == other.discussionLastMessage()) 0490 && (mDiscussionRoomId == other.discussionRoomId()) && (mThreadMessageId == other.threadMessageId()) 0491 && (mMessageTranslation == other.messageTranslation()) && (mShowTranslatedMessage == other.showTranslatedMessage()) && (mReplies == other.replies()) 0492 && (mEmoji == other.emoji()) && (mPendingMessage == other.pendingMessage()) && (mShowIgnoredMessage == other.showIgnoredMessage()) 0493 && (mChannels == other.channels()) && (mLocalTranslation == other.localTranslation()) && (mBlocks == other.blocks()) 0494 && (mDisplayTime == other.mDisplayTime); 0495 } 0496 0497 bool Message::operator<(const Message &other) const 0498 { 0499 return mTimeStamp < other.mTimeStamp; 0500 } 0501 0502 QString Message::systemMessageType() const 0503 { 0504 return mSystemMessageType; 0505 } 0506 0507 void Message::setSystemMessageType(const QString &systemMessageType) 0508 { 0509 mSystemMessageType = systemMessageType; 0510 } 0511 0512 Message::MessageType Message::messageType() const 0513 { 0514 return mMessageType; 0515 } 0516 0517 QString Message::systemMessageText() const 0518 { 0519 if (mSystemMessageType == QLatin1String("uj")) { 0520 return i18n("%1 has joined the channel", mUsername); 0521 } else if (mSystemMessageType == QLatin1String("ul")) { 0522 return i18n("%1 has left the channel", mUsername); 0523 } else if (mSystemMessageType == QLatin1String("ult")) { 0524 return i18n("%1 left this Team", mUsername); 0525 } else if (mSystemMessageType == QLatin1String("room_changed_topic")) { 0526 if (mText.isEmpty()) { 0527 return i18n("Topic was cleared by: %1", mUsername); 0528 } else { 0529 return i18n("%2 changed topic to: <i>%1</i>", mText, mUsername); 0530 } 0531 } else if (mSystemMessageType == QLatin1String("au")) { 0532 return i18n("%2 added %1 to the conversation", mText, mUsername); 0533 } else if (mSystemMessageType == QLatin1Char('r')) { 0534 return i18n("%2 changed room name to <a href=\"ruqola:/room/%1\">#%1</a>", mText, mUsername); 0535 } else if (mSystemMessageType == QLatin1String("ru")) { 0536 return i18n("%2 removed user %1", mText, mUsername); 0537 } else if (mSystemMessageType == QLatin1String("room_changed_description")) { 0538 if (mText.isEmpty()) { 0539 return i18n("Description was cleared by %1", mUsername); 0540 } else { 0541 return i18n("%2 changed room description to %1", mText, mUsername); 0542 } 0543 } else if (mSystemMessageType == QLatin1String("room_changed_announcement")) { 0544 if (mText.isEmpty()) { 0545 return i18n("Announcement was cleared by %1", mUsername); 0546 } else { 0547 return i18n("%2 changed room announcement to %1", mText, mUsername); 0548 } 0549 } else if (mSystemMessageType == QLatin1String("room_changed_privacy")) { 0550 return i18n("%2 changed room privacy to %1", mText, mUsername); 0551 } else if (mSystemMessageType == QLatin1String("jitsi_call_started")) { 0552 return QStringLiteral("<a href=\"ruqola:/jitsicall/\">") + i18n("Click to join to video") + QStringLiteral("</a>"); 0553 } else if (mSystemMessageType == QLatin1String("rm")) { 0554 // TODO encrypted message 0555 return i18n("Message Deleted"); 0556 } else if (mSystemMessageType == QLatin1String("message_pinned")) { 0557 return i18n("Message Pinned"); 0558 } else if (mSystemMessageType == QLatin1String("otr")) { 0559 return i18n("Encrypted Message"); 0560 } else if (mSystemMessageType == QLatin1String("user-unmuted")) { 0561 return i18n("%1 was unmuted by %2", mText, mUsername); 0562 } else if (mSystemMessageType == QLatin1String("user-muted")) { 0563 return i18n("%1 was muted by %2", mText, mUsername); 0564 } else if (mSystemMessageType == QLatin1String("subscription-role-added")) { 0565 return i18n("Role \'%3\' was added to %1 by %2", mText, mUsername, mRole); 0566 } else if (mSystemMessageType == QLatin1String("subscription-role-removed")) { 0567 return i18n("Role \'%3\' was removed to %1 by %2", mText, mUsername, mRole); 0568 } else if (mSystemMessageType == QLatin1String("e2e")) { 0569 // TODO need to unencrypt it 0570 // return i18n("Encrypted message: %1", mText); 0571 return i18n("This message is end-to-end encrypted. To view it, you must enter your encryption key in your account settings."); 0572 } else if (mSystemMessageType == QLatin1String("discussion-created")) { 0573 return i18n("Discussion created about \"%1\"", mText); 0574 } else if (mSystemMessageType == QLatin1String("ut")) { 0575 return i18n("%1 has joined the conversation", mUsername); 0576 } else if (mSystemMessageType == QLatin1String("room-archived")) { 0577 return i18n("This room has been archived by %1", mUsername); 0578 } else if (mSystemMessageType == QLatin1String("room-unarchived")) { 0579 return i18n("This room has been unarchived by %1", mUsername); 0580 } else if (mSystemMessageType == QLatin1String("rtc")) { 0581 qCWarning(RUQOLA_LOG) << "Need to implement : " << mSystemMessageType << " mText " << mText; 0582 return i18n("Unknown action!"); 0583 } else if (mSystemMessageType == QLatin1String("wm")) { 0584 // TODO verify 0585 qCWarning(RUQOLA_LOG) << "Need to implement : " << mSystemMessageType << " mText " << mText; 0586 return i18n("Welcome %1!", mUsername); 0587 } else if (mSystemMessageType == QLatin1String("room_changed_avatar")) { 0588 return i18n("Room avatar changed by %1", mUsername); 0589 } else if (mSystemMessageType == QLatin1String("room_e2e_enabled")) { 0590 return i18n("This room's encryption has been enabled by %1", mUsername); 0591 } else if (mSystemMessageType == QLatin1String("room_e2e_disabled")) { 0592 return i18n("This room's encryption has been disabled by %1", mUsername); 0593 } else if (mSystemMessageType == QLatin1String("room-set-read-only")) { 0594 return i18n("Room set as Read Only by %1", mUsername); 0595 } else if (mSystemMessageType == QLatin1String("room-removed-read-only")) { 0596 return i18n("Room added writing permission by %1", mUsername); 0597 } else if (mSystemMessageType == QLatin1String("added-user-to-team")) { 0598 return i18n("%1 added @%2 to this Team", mUsername, mText); 0599 } else if (mSystemMessageType == QLatin1String("removed-user-from-team")) { 0600 return i18n("%1 removed @%2 from this Team", mUsername, mText); 0601 } else if (mSystemMessageType == QLatin1String("user-converted-to-team")) { 0602 return i18n("%1 converted #%2 to a Team", mUsername, mText); 0603 } else if (mSystemMessageType == QLatin1String("user-converted-to-channel")) { 0604 return i18n("%1 converted #%2 to a Channel", mUsername, mText); 0605 } else if (mSystemMessageType == QLatin1String("user-removed-room-from-team")) { 0606 return i18n("%1 removed #%2 from this Team", mUsername, mText); 0607 } else if (mSystemMessageType == QLatin1String("user-deleted-room-from-team")) { 0608 return i18n("%1 deleted #%2", mUsername, mText); 0609 } else if (mSystemMessageType == QLatin1String("user-added-room-to-team")) { 0610 return i18n("%1 added #%2 to this Team", mUsername, mText); 0611 } else if (mSystemMessageType == QLatin1String("room-allowed-reacting")) { 0612 return i18n("Room allowed reacting by %1", mUsername); 0613 } else if (mSystemMessageType == QLatin1String("room-disallowed-reacting")) { 0614 return i18n("Room disallowed reacting by %1", mUsername); 0615 } else if (mSystemMessageType == QLatin1String("ujt")) { 0616 return i18n("%1 joined this Team", mUsername); 0617 } else if (mSystemMessageType == QLatin1String("user_joined_otr")) { 0618 return i18n("%1 has joined OTR chat.", mUsername); 0619 } else if (mSystemMessageType == QLatin1String("user_key_refreshed_successfully")) { 0620 return i18n("%1 key refreshed successfully", mUsername); 0621 } else if (mSystemMessageType == QLatin1String("user_requested_otr_key_refresh")) { 0622 return i18n("%1 has requested key refresh.", mUsername); 0623 } else if (mSystemMessageType == QLatin1String("room_changed_topic")) { 0624 return i18n("Room topic changed to: %1 by %2", mUsername, mText); // TODO verify 0625 } else if (mSystemMessageType == QLatin1String("videoconf")) { 0626 return i18n("Conference Call"); 0627 } else { 0628 qCWarning(RUQOLA_LOG) << "Unknown type for message: type: " << mSystemMessageType << " mText " << mText; 0629 return i18n("Unknown action!"); 0630 } 0631 } 0632 0633 void Message::setMessageType(MessageType messageType) 0634 { 0635 mMessageType = messageType; 0636 } 0637 0638 QVector<MessageAttachment> Message::attachments() const 0639 { 0640 return mAttachments; 0641 } 0642 0643 void Message::setAttachments(const QVector<MessageAttachment> &attachments) 0644 { 0645 mAttachments = attachments; 0646 } 0647 0648 QVector<MessageUrl> Message::urls() const 0649 { 0650 return mUrls; 0651 } 0652 0653 void Message::setUrls(const QVector<MessageUrl> &urls) 0654 { 0655 mUrls = urls; 0656 } 0657 0658 QString Message::alias() const 0659 { 0660 return mAlias; 0661 } 0662 0663 void Message::setAlias(const QString &alias) 0664 { 0665 mAlias = alias; 0666 } 0667 0668 QString Message::editedByUserId() const 0669 { 0670 return mEditedByUserId; 0671 } 0672 0673 void Message::setEditedByUserId(const QString &editedByUserId) 0674 { 0675 mEditedByUserId = editedByUserId; 0676 } 0677 0678 QString Message::editedByUsername() const 0679 { 0680 return mEditedByUsername; 0681 } 0682 0683 void Message::setEditedByUsername(const QString &editedByUsername) 0684 { 0685 mEditedByUsername = editedByUsername; 0686 } 0687 0688 bool Message::wasEdited() const 0689 { 0690 return !mEditedByUsername.isEmpty(); 0691 } 0692 0693 qint64 Message::editedAt() const 0694 { 0695 return mEditedAt; 0696 } 0697 0698 void Message::setEditedAt(qint64 editedAt) 0699 { 0700 if (mEditedAt != editedAt) { 0701 mEditedAt = editedAt; 0702 QLocale l; 0703 mEditedDisplayTime = l.toString(QDateTime::fromMSecsSinceEpoch(mEditedAt), QLocale::LongFormat); 0704 } 0705 } 0706 0707 qint64 Message::updatedAt() const 0708 { 0709 return mUpdatedAt; 0710 } 0711 0712 void Message::setUpdatedAt(qint64 updatedAt) 0713 { 0714 mUpdatedAt = updatedAt; 0715 } 0716 0717 QString Message::userId() const 0718 { 0719 return mUserId; 0720 } 0721 0722 void Message::setUserId(const QString &userId) 0723 { 0724 mUserId = userId; 0725 } 0726 0727 QString Message::username() const 0728 { 0729 return mUsername; 0730 } 0731 0732 void Message::setUsername(const QString &username) 0733 { 0734 mUsername = username; 0735 } 0736 0737 qint64 Message::timeStamp() const 0738 { 0739 return mTimeStamp; 0740 } 0741 0742 void Message::setTimeStamp(qint64 timeStamp) 0743 { 0744 if (mTimeStamp != timeStamp) { 0745 mTimeStamp = timeStamp; 0746 mDisplayTime = QDateTime::fromMSecsSinceEpoch(mTimeStamp).time().toString(QStringLiteral("hh:mm")); 0747 } 0748 } 0749 0750 QString Message::text() const 0751 { 0752 return mText; 0753 } 0754 0755 void Message::setText(const QString &text) 0756 { 0757 mText = text; 0758 } 0759 0760 QString Message::messageId() const 0761 { 0762 return mMessageId; 0763 } 0764 0765 void Message::setMessageId(const QString &messageId) 0766 { 0767 mMessageId = messageId; 0768 } 0769 0770 QString Message::roomId() const 0771 { 0772 return mRoomId; 0773 } 0774 0775 void Message::setRoomId(const QString &roomId) 0776 { 0777 mRoomId = roomId; 0778 } 0779 0780 QString Message::avatar() const 0781 { 0782 return mAvatar; 0783 } 0784 0785 void Message::setAvatar(const QString &avatar) 0786 { 0787 mAvatar = avatar; 0788 } 0789 0790 bool Message::parseUrls() const 0791 { 0792 return mParseUrls; 0793 } 0794 0795 void Message::setParseUrls(bool parseUrls) 0796 { 0797 mParseUrls = parseUrls; 0798 } 0799 0800 bool Message::groupable() const 0801 { 0802 return mGroupable; 0803 } 0804 0805 void Message::setGroupable(bool groupable) 0806 { 0807 mGroupable = groupable; 0808 } 0809 0810 QString Message::generateUniqueId(const QString &messageId, int index) 0811 { 0812 return QStringLiteral("%1_%2").arg(messageId, QString::number(index)); 0813 } 0814 0815 Utils::AvatarInfo Message::avatarInfo() const 0816 { 0817 Utils::AvatarInfo info; // Optimize ??? 0818 info.avatarType = Utils::AvatarType::User; 0819 info.identifier = mUsername; 0820 return info; 0821 } 0822 0823 Message Message::deserialize(const QJsonObject &o, EmojiManager *emojiManager) 0824 { 0825 Message message(emojiManager); 0826 message.mThreadCount = o[QLatin1String("tcount")].toInt(); 0827 message.mDiscussionCount = o[QLatin1String("dcount")].toInt(); 0828 message.mDiscussionRoomId = o[QLatin1String("drid")].toString(); 0829 message.mThreadMessageId = o[QLatin1String("tmid")].toString(); 0830 0831 if (o.contains(QLatin1String("tlm"))) { 0832 message.mThreadLastMessage = static_cast<qint64>(o[QLatin1String("tlm")].toDouble()); 0833 } 0834 if (o.contains(QLatin1String("dlm"))) { 0835 message.mDiscussionLastMessage = static_cast<qint64>(o[QLatin1String("dlm")].toDouble()); 0836 } 0837 0838 message.mMessageId = o[QLatin1String("messageID")].toString(); 0839 message.mRoomId = o[QLatin1String("roomID")].toString(); 0840 message.mText = o[QLatin1String("message")].toString(); 0841 message.setTimeStamp(static_cast<qint64>(o[QLatin1String("timestamp")].toDouble())); 0842 message.mUsername = o[QLatin1String("username")].toString(); 0843 message.mName = o[QLatin1String("name")].toString(); 0844 message.mUserId = o[QLatin1String("userID")].toString(); 0845 message.mUpdatedAt = static_cast<qint64>(o[QLatin1String("updatedAt")].toDouble()); 0846 message.setEditedAt(static_cast<qint64>(o[QLatin1String("editedAt")].toDouble())); 0847 message.mEditedByUsername = o[QLatin1String("editedByUsername")].toString(); 0848 message.mEditedByUserId = o[QLatin1String("editedByUserID")].toString(); 0849 message.mAlias = o[QLatin1String("alias")].toString(); 0850 message.mAvatar = o[QLatin1String("avatar")].toString(); 0851 message.mGroupable = o[QLatin1String("groupable")].toBool(); 0852 message.mParseUrls = o[QLatin1String("parseUrls")].toBool(); 0853 message.mMessageStarred.setIsStarred(o[QLatin1String("starred")].toBool()); 0854 0855 message.mMessagePinned = MessagePinned::deserialize(o[QLatin1String("pinnedMessage")].toObject()); 0856 message.mRole = o[QLatin1String("role")].toString(); 0857 message.mSystemMessageType = o[QLatin1String("type")].toString(); 0858 message.mEmoji = o[QLatin1String("emoji")].toString(); 0859 message.mMessageType = o[QLatin1String("messageType")].toVariant().value<MessageType>(); 0860 const QJsonArray attachmentsArray = o.value(QLatin1String("attachments")).toArray(); 0861 for (int i = 0; i < attachmentsArray.count(); ++i) { 0862 const QJsonObject attachment = attachmentsArray.at(i).toObject(); 0863 MessageAttachment att = MessageAttachment::deserialize(attachment); 0864 att.setAttachmentId(Message::generateUniqueId(message.messageId(), i)); 0865 if (att.isValid()) { 0866 message.mAttachments.append(std::move(att)); 0867 } 0868 } 0869 const QJsonArray urlsArray = o.value(QLatin1String("urls")).toArray(); 0870 for (int i = 0; i < urlsArray.count(); ++i) { 0871 const QJsonObject urlObj = urlsArray.at(i).toObject(); 0872 MessageUrl url = MessageUrl::deserialize(urlObj); 0873 url.setUrlId(Message::generateUniqueId(message.messageId(), i)); 0874 if (!url.isEmpty()) { 0875 message.mUrls.append(std::move(url)); 0876 } 0877 } 0878 const QJsonObject reactionsArray = o.value(QLatin1String("reactions")).toObject(); 0879 message.setReactions(Reactions::deserialize(reactionsArray, emojiManager)); 0880 0881 const QJsonArray repliesArray = o.value(QLatin1String("replies")).toArray(); 0882 QStringList replies; 0883 replies.reserve(repliesArray.count()); 0884 for (int i = 0, total = repliesArray.count(); i < total; ++i) { 0885 replies.append(repliesArray.at(i).toString()); 0886 } 0887 message.setReplies(replies); 0888 0889 QMap<QString, QString> mentions; 0890 const QJsonArray mentionsArray = o.value(QLatin1String("mentions")).toArray(); 0891 for (int i = 0, total = mentionsArray.count(); i < total; ++i) { 0892 const QJsonObject mention = mentionsArray.at(i).toObject(); 0893 mentions.insert(mention.value(QLatin1String("username")).toString(), mention.value(QLatin1String("_id")).toString()); 0894 } 0895 message.setMentions(mentions); 0896 0897 QMap<QString, QString> channels; 0898 const QJsonArray channelsArray = o.value(QLatin1String("channels")).toArray(); 0899 for (int i = 0, total = channelsArray.count(); i < total; ++i) { 0900 const QJsonObject channel = channelsArray.at(i).toObject(); 0901 channels.insert(channel.value(QLatin1String("channel")).toString(), channel.value(QLatin1String("_id")).toString()); 0902 } 0903 message.setChannels(channels); 0904 0905 const QJsonArray blocksArray = o.value(QLatin1String("blocks")).toArray(); 0906 for (int i = 0, total = blocksArray.count(); i < total; ++i) { 0907 const Block block = Block::deserialize(blocksArray.at(i).toObject()); 0908 message.mBlocks.append(std::move(block)); 0909 } 0910 0911 message.mLocalTranslation = o[QLatin1String("localTransation")].toString(); 0912 0913 message.mMessageTranslation = MessageTranslation::deserialize(o[QLatin1String("messageTranslation")].toArray()); 0914 0915 return message; 0916 } 0917 0918 QByteArray Message::serialize(const Message &message, bool toBinary) 0919 { 0920 QJsonDocument d; 0921 QJsonObject o; 0922 0923 o[QLatin1String("messageID")] = message.mMessageId; 0924 o[QLatin1String("roomID")] = message.mRoomId; 0925 o[QLatin1String("message")] = message.mText; 0926 o[QLatin1String("timestamp")] = message.mTimeStamp; 0927 o[QLatin1String("username")] = message.mUsername; 0928 if (!message.mName.isEmpty()) { 0929 o[QLatin1String("name")] = message.mName; 0930 } 0931 o[QLatin1String("userID")] = message.mUserId; 0932 o[QLatin1String("updatedAt")] = message.mUpdatedAt; 0933 o[QLatin1String("editedAt")] = message.mEditedAt; 0934 if (message.mThreadLastMessage > -1) { 0935 o[QLatin1String("tlm")] = message.mThreadLastMessage; 0936 } 0937 0938 o[QLatin1String("editedByUsername")] = message.mEditedByUsername; 0939 o[QLatin1String("editedByUserID")] = message.mEditedByUserId; 0940 o[QLatin1String("alias")] = message.mAlias; 0941 o[QLatin1String("avatar")] = message.mAvatar; 0942 o[QLatin1String("groupable")] = message.mGroupable; 0943 o[QLatin1String("parseUrls")] = message.mParseUrls; 0944 o[QLatin1String("starred")] = message.mMessageStarred.isStarred(); 0945 0946 o[QLatin1String("pinnedMessage")] = MessagePinned::serialize(message.mMessagePinned); 0947 0948 if (!message.mRole.isEmpty()) { 0949 o[QLatin1String("role")] = message.mRole; 0950 } 0951 if (!message.mEmoji.isEmpty()) { 0952 o[QLatin1String("emoji")] = message.mEmoji; 0953 } 0954 0955 o[QLatin1String("type")] = message.mSystemMessageType; 0956 o[QLatin1String("messageType")] = QJsonValue::fromVariant(QVariant::fromValue<Message::MessageType>(message.mMessageType)); 0957 0958 // Attachments 0959 if (!message.mAttachments.isEmpty()) { 0960 QJsonArray array; 0961 const int nbAttachment = message.mAttachments.count(); 0962 for (int i = 0; i < nbAttachment; ++i) { 0963 array.append(MessageAttachment::serialize(message.mAttachments.at(i))); 0964 } 0965 o[QLatin1String("attachments")] = array; 0966 } 0967 0968 // Mentions 0969 if (!message.mentions().isEmpty()) { 0970 QMapIterator<QString, QString> i(message.mentions()); 0971 QJsonArray array; 0972 while (i.hasNext()) { 0973 i.next(); 0974 QJsonObject mention; 0975 mention.insert(QLatin1String("_id"), i.value()); 0976 mention.insert(QLatin1String("username"), i.key()); 0977 array.append(std::move(mention)); 0978 } 0979 o[QLatin1String("mentions")] = array; 0980 } 0981 0982 // Channels 0983 if (!message.channels().isEmpty()) { 0984 QMapIterator<QString, QString> j(message.channels()); 0985 QJsonArray array; 0986 while (j.hasNext()) { 0987 j.next(); 0988 QJsonObject channel; 0989 channel.insert(QLatin1String("_id"), j.value()); 0990 channel.insert(QLatin1String("channel"), j.key()); 0991 array.append(std::move(channel)); 0992 } 0993 o[QLatin1String("channels")] = array; 0994 } 0995 // Urls 0996 if (!message.mUrls.isEmpty()) { 0997 QJsonArray array; 0998 const int nbUrls = message.mUrls.count(); 0999 for (int i = 0; i < nbUrls; ++i) { 1000 array.append(MessageUrl::serialize(message.mUrls.at(i))); 1001 } 1002 o[QLatin1String("urls")] = array; 1003 } 1004 1005 if (!message.reactions().isEmpty()) { 1006 o[QLatin1String("reactions")] = Reactions::serialize(message.reactions()); 1007 } 1008 1009 if (message.mThreadCount > 0) { 1010 o[QLatin1String("tcount")] = message.mThreadCount; 1011 o[QLatin1String("tlm")] = message.mThreadLastMessage; 1012 } 1013 1014 if (message.mDiscussionCount > 0) { 1015 o[QLatin1String("dcount")] = message.mDiscussionCount; 1016 o[QLatin1String("dlm")] = message.mDiscussionLastMessage; 1017 } 1018 if (!message.mDiscussionRoomId.isEmpty()) { 1019 o[QLatin1String("drid")] = message.mDiscussionRoomId; 1020 } 1021 1022 if (!message.mThreadMessageId.isEmpty()) { 1023 o[QLatin1String("tmid")] = message.mThreadMessageId; 1024 } 1025 if (!message.mReplies.isEmpty()) { 1026 o[QLatin1String("replies")] = QJsonArray::fromStringList(message.mReplies); 1027 } 1028 1029 if (!message.mBlocks.isEmpty()) { 1030 QJsonArray blockArray; 1031 const int nBlocks = message.mBlocks.count(); 1032 for (int i = 0; i < nBlocks; ++i) { 1033 blockArray.append(Block::serialize(message.mBlocks.at(i))); 1034 } 1035 o[QLatin1String("blocks")] = blockArray; 1036 } 1037 if (!message.mLocalTranslation.isEmpty()) { 1038 o[QLatin1String("localTransation")] = message.mLocalTranslation; 1039 } 1040 if (!message.mMessageTranslation.isEmpty()) { 1041 o[QLatin1String("messageTranslation")] = MessageTranslation::serialize(message.mMessageTranslation); 1042 } 1043 1044 if (toBinary) { 1045 return QCborValue::fromJsonValue(o).toCbor(); 1046 } 1047 1048 d.setObject(o); 1049 return d.toJson(QJsonDocument::Indented); 1050 } 1051 1052 QDebug operator<<(QDebug d, const Message &t) 1053 { 1054 d.space() << "mMessageId:" << t.messageId(); 1055 d.space() << "mText:" << t.text(); 1056 d.space() << "mTimeStamp:" << t.timeStamp(); 1057 d.space() << "mUsername:" << t.username(); 1058 d.space() << "mName:" << t.name(); 1059 d.space() << "mUserId:" << t.userId(); 1060 d.space() << "mUpdatedAt:" << t.updatedAt(); 1061 d.space() << "mEditedAt:" << t.editedAt(); 1062 d.space() << "mEditedByUsername:" << t.editedByUsername(); 1063 d.space() << "mEditedByUserId:" << t.editedByUserId(); 1064 d.space() << "mAlias:" << t.alias(); 1065 d.space() << "mSystemMessageType:" << t.systemMessageType(); 1066 d.space() << "mRoomId:" << t.roomId(); 1067 d.space() << "mAvatar:" << t.avatar(); 1068 d.space() << "mGroupable:" << t.groupable(); 1069 d.space() << "mParseUrls:" << t.parseUrls(); 1070 for (int i = 0, total = t.attachments().count(); i < total; ++i) { 1071 d.space() << "Attachment:" << t.attachments().at(i); 1072 } 1073 for (int i = 0, total = t.urls().count(); i < total; ++i) { 1074 d.space() << "Urls:" << t.urls().at(i); 1075 } 1076 d.space() << "Mentions:" << t.mentions(); 1077 d.space() << "mMessageType:" << t.messageType(); 1078 d.space() << "mRole:" << t.role(); 1079 d.space() << "mReaction:" << t.reactions(); 1080 d.space() << "mUnread:" << t.unread(); 1081 d.space() << "starred" << t.messageStarred(); 1082 d.space() << "pinned" << t.messagePinned(); 1083 d.space() << "threadcount" << t.threadCount(); 1084 d.space() << "threadlastmessage" << t.threadLastMessage(); 1085 d.space() << "discussioncount" << t.discussionCount(); 1086 d.space() << "discussionlastmessage" << t.discussionLastMessage(); 1087 d.space() << "discussionRoomId" << t.discussionRoomId(); 1088 d.space() << "threadMessageId" << t.threadMessageId(); 1089 d.space() << "messagetranslation" << t.messageTranslation(); 1090 d.space() << "mShowOriginalMessage" << t.showTranslatedMessage(); 1091 d.space() << "mReplies" << t.replies(); 1092 d.space() << "mEmoji" << t.emoji(); 1093 d.space() << "mPendingMessage" << t.pendingMessage(); 1094 d.space() << "mShowIgnoredMessage" << t.showIgnoredMessage(); 1095 d.space() << "mChannels" << t.channels(); 1096 d.space() << "mLocalTranslation" << t.localTranslation(); 1097 d.space() << "mDiscussionCount" << t.discussionCount(); 1098 d.space() << "mDiscussionLastMessage" << t.discussionLastMessage(); 1099 1100 for (int i = 0, total = t.blocks().count(); i < total; ++i) { 1101 d.space() << "block:" << t.blocks().at(i); 1102 } 1103 1104 return d; 1105 } 1106 1107 QString Message::dateTime() const 1108 { 1109 const QDateTime currentDate = QDateTime::fromMSecsSinceEpoch(timeStamp()); 1110 return currentDate.toString(); 1111 } 1112 1113 #include "moc_message.cpp"