diff --git a/core/account.cpp b/core/account.cpp index 6e7d782..724bfa1 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -716,7 +716,6 @@ bool Core::Account::handleChatMessage(const QXmppMessage& msg, bool outgoing, bo { const QString& body(msg.body()); if (body.size() != 0) { - const QString& id(msg.id()); Shared::Message sMsg(Shared::Message::chat); initializeMessage(sMsg, msg, outgoing, forwarded, guessing); QString jid = sMsg.getPenPalJid(); @@ -741,9 +740,18 @@ bool Core::Account::handleChatMessage(const QXmppMessage& msg, bool outgoing, bo } else { sMsg.setState(Shared::Message::State::delivered); } - cnt->appendMessageToArchive(sMsg); - - emit message(sMsg); + QString oId = msg.replaceId(); + if (oId.size() > 0) { + QMap cData = { + {"body", sMsg.getBody()}, + {"stamp", sMsg.getTime()} + }; + cnt->correctMessageInArchive(oId, sMsg); + emit changeMessage(jid, oId, cData); + } else { + cnt->appendMessageToArchive(sMsg); + emit message(sMsg); + } return true; } @@ -773,12 +781,22 @@ bool Core::Account::handleGroupMessage(const QXmppMessage& msg, bool outgoing, b pendingStateMessages.erase(pItr); emit changeMessage(jid, id, cData); } else { - cnt->appendMessageToArchive(sMsg); - QDateTime minAgo = QDateTime::currentDateTime().addSecs(-60); - if (sMsg.getTime() > minAgo) { //otherwise it's considered a delayed delivery, most probably MUC history receipt - emit message(sMsg); + QString oId = msg.replaceId(); + if (oId.size() > 0) { + QMap cData = { + {"body", sMsg.getBody()}, + {"stamp", sMsg.getTime()} + }; + cnt->correctMessageInArchive(oId, sMsg); + emit changeMessage(jid, oId, cData); } else { - //qDebug() << "Delayed delivery: "; + cnt->appendMessageToArchive(sMsg); + QDateTime minAgo = QDateTime::currentDateTime().addSecs(-60); + if (sMsg.getTime() > minAgo) { //otherwise it's considered a delayed delivery, most probably MUC history receipt + emit message(sMsg); + } else { + //qDebug() << "Delayed delivery: "; + } } } @@ -824,10 +842,16 @@ void Core::Account::onMamMessageReceived(const QString& queryId, const QXmppMess QString jid = itr->second; RosterItem* item = getRosterItem(jid); - Shared::Message sMsg(Shared::Message::chat); + Shared::Message sMsg(static_cast(msg.type())); initializeMessage(sMsg, msg, false, true, true); + sMsg.setState(Shared::Message::State::sent); - item->addMessageToArchive(sMsg); + QString oId = msg.replaceId(); + if (oId.size() > 0) { + item->correctMessageInArchive(oId, sMsg); + } else { + item->addMessageToArchive(sMsg); + } } //handleChatMessage(msg, false, true, true); diff --git a/core/archive.cpp b/core/archive.cpp index 3afd706..bd159ca 100644 --- a/core/archive.cpp +++ b/core/archive.cpp @@ -267,8 +267,7 @@ void Core::Archive::changeMessage(const QString& id, const QMapmv_data, value->mv_size); + + try { + msg = getMessage(sId, txn); + if (msg.serverStored()) { + break; + } else { + rc = mdb_cursor_get(cursor, key, value, op); + } + } catch (...) { + break; + } + } + + return msg; } unsigned int Core::Archive::addElements(const std::list& messages) diff --git a/core/archive.h b/core/archive.h index 15c91b9..4d61f95 100644 --- a/core/archive.h +++ b/core/archive.h @@ -183,6 +183,8 @@ private: void printKeys(); bool dropAvatar(const std::string& resource); Shared::Message getMessage(const std::string& id, MDB_txn* txn); + Shared::Message getStoredMessage(MDB_txn *txn, MDB_cursor* cursor, MDB_cursor_op op, MDB_val* key, MDB_val* value, int& rc); + Shared::Message edge(bool end); }; } diff --git a/core/rosteritem.cpp b/core/rosteritem.cpp index 4d1cca2..59aa4a7 100644 --- a/core/rosteritem.cpp +++ b/core/rosteritem.cpp @@ -35,6 +35,7 @@ Core::RosterItem::RosterItem(const QString& pJid, const QString& pAccount, QObje appendCache(), responseCache(), requestCache(), + toCorrect(), muc(false) { archive->open(account); @@ -75,6 +76,36 @@ void Core::RosterItem::addMessageToArchive(const Shared::Message& msg) { if (msg.storable()) { hisoryCache.push_back(msg); + std::map::iterator itr = toCorrect.find(msg.getId()); + if (itr != toCorrect.end()) { + hisoryCache.back().change({ + {"body", itr->second.getBody()}, + {"stamp", itr->second.getTime()} + }); + toCorrect.erase(itr); + } + } +} + +void Core::RosterItem::correctMessageInArchive(const QString& originalId, const Shared::Message& msg) +{ + if (msg.storable()) { + QDateTime thisTime = msg.getTime(); + std::map::iterator itr = toCorrect.find(originalId); + if (itr != toCorrect.end()) { + if (itr->second.getTime() < thisTime) { + itr->second = msg; + } + return; + } + + bool found = changeMessage(originalId, { + {"body", msg.getBody()}, + {"stamp", thisTime} + }); + if (!found) { + toCorrect.insert(std::make_pair(originalId, msg)); + } } } @@ -221,7 +252,7 @@ void Core::RosterItem::appendMessageToArchive(const Shared::Message& msg) } } -void Core::RosterItem::changeMessage(const QString& id, const QMap& data) +bool Core::RosterItem::changeMessage(const QString& id, const QMap& data) { bool found = false; for (Shared::Message& msg : appendCache) { @@ -259,6 +290,8 @@ void Core::RosterItem::changeMessage(const QString& id, const QMap& data); + bool changeMessage(const QString& id, const QMap& data); signals: void nameChanged(const QString& name); @@ -98,6 +99,7 @@ protected: std::list appendCache; std::list responseCache; std::list> requestCache; + std::map toCorrect; bool muc; private: diff --git a/global.cpp b/global.cpp index 4cdfa8d..ed75abc 100644 --- a/global.cpp +++ b/global.cpp @@ -53,7 +53,10 @@ Shared::Message::Message(): outgoing(false), forwarded(false), state(State::delivered), - edited(false) + edited(false), + errorText(), + originalMessage(), + lastModified() { } @@ -242,6 +245,16 @@ void Shared::Message::setThread(const QString& p_body) thread = p_body; } +QDateTime Shared::Message::getLastModified() const +{ + return lastModified; +} + +QString Shared::Message::getOriginalBody() const +{ + return originalMessage; +} + Shared::Message::Type Shared::Message::getType() const { return type; @@ -261,6 +274,11 @@ void Shared::Message::setState(Shared::Message::State p_state) } } +bool Shared::Message::serverStored() const +{ + return state == State::delivered || state == State::sent; +} + void Shared::Message::setEdited(bool p_edited) { edited = p_edited; @@ -285,6 +303,10 @@ void Shared::Message::serialize(QDataStream& data) const if (state == State::error) { data << errorText; } + if (edited) { + data << originalMessage; + data << lastModified; + } } void Shared::Message::deserialize(QDataStream& data) @@ -310,6 +332,10 @@ void Shared::Message::deserialize(QDataStream& data) if (state == State::error) { data >> errorText; } + if (edited) { + data >> originalMessage; + data >> lastModified; + } } bool Shared::Message::change(const QMap& data) @@ -337,8 +363,19 @@ bool Shared::Message::change(const QMap& data) } itr = data.find("body"); if (itr != data.end()) { - setBody(itr.value().toString()); - setEdited(true); + QMap::const_iterator dItr = data.find("stamp"); + QDateTime correctionDate; + if (dItr != data.end()) { + correctionDate = dItr.value().toDateTime(); + } else { + correctionDate = QDateTime::currentDateTime(); //in case there is no information about time of this correction it's applied + } + if (!edited || lastModified < correctionDate) { + originalMessage = body; + lastModified = correctionDate; + setBody(itr.value().toString()); + setEdited(true); + } } return idChanged; diff --git a/global.h b/global.h index e0a0796..aa5911a 100644 --- a/global.h +++ b/global.h @@ -216,6 +216,9 @@ public: QString getPenPalJid() const; QString getPenPalResource() const; void generateRandomId(); + bool serverStored() const; + QDateTime getLastModified() const; + QString getOriginalBody() const; void serialize(QDataStream& data) const; void deserialize(QDataStream& data); @@ -236,6 +239,8 @@ private: State state; bool edited; QString errorText; + QString originalMessage; + QDateTime lastModified; }; class VCard { diff --git a/ui/utils/message.cpp b/ui/utils/message.cpp index 26fbd99..eb69ca0 100644 --- a/ui/utils/message.cpp +++ b/ui/utils/message.cpp @@ -121,6 +121,9 @@ Message::Message(const Shared::Message& source, bool p_outgoing, const QString& layout->addStretch(); statusLay->addWidget(date); } + if (msg.getEdited()) { + setEdited(); + } bodyLayout->addWidget(statusBar); layout->setAlignment(avatar, Qt::AlignTop); @@ -315,20 +318,7 @@ bool Message::change(const QMap& data) text->hide(); } if (msg.getEdited()) { - if (!hasEditedLabel) { - editedLabel = new QLabel(); - QFont eFont = editedLabel->font(); - eFont.setItalic(true); - eFont.setPointSize(eFont.pointSize() - 2); - editedLabel->setFont(eFont); - hasEditedLabel = true; - QHBoxLayout* statusLay = static_cast(statusBar->layout()); - if (hasStatusIcon) { - statusLay->insertWidget(1, editedLabel); - } else { - statusLay->insertWidget(0, editedLabel); - } - } + setEdited(); } if (hasStatusIcon) { setState(); @@ -338,6 +328,20 @@ bool Message::change(const QMap& data) return idChanged; } +void Message::setEdited() +{ + if (!hasEditedLabel) { + editedLabel = new QLabel(); + hasEditedLabel = true; + QIcon q(Shared::icon("edit-rename")); + editedLabel->setPixmap(q.pixmap(12, 12)); + QHBoxLayout* statusLay = static_cast(statusBar->layout()); + statusLay->insertWidget(1, editedLabel); + } + editedLabel->setToolTip("Last time edited: " + msg.getLastModified().toLocalTime().toString() + + "\nOriginal message: " + msg.getOriginalBody()); +} + void Message::setState() { Shared::Message::State state = msg.getState(); diff --git a/ui/utils/message.h b/ui/utils/message.h index baac728..a885d5b 100644 --- a/ui/utils/message.h +++ b/ui/utils/message.h @@ -94,6 +94,7 @@ private: void hideProgress(); void hideFile(); void setState(); + void setEdited(); }; #endif // MESSAGE_H