forked from blue/squawk
cant believe it, first ever encrypted messages!
This commit is contained in:
parent
a7d1a28f29
commit
637eb702a8
@ -38,7 +38,7 @@ option(WITH_OMEMO "Build OMEMO support module" ON)
|
||||
# Dependencies
|
||||
## Qt
|
||||
if (NOT DEFINED QT_VERSION_MAJOR)
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets DBus Gui Xml Network Core)
|
||||
find_package(QT NAMES Qt5 REQUIRED COMPONENTS Widgets DBus Gui Xml Network Core)
|
||||
else ()
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets DBus Gui Xml Network Core)
|
||||
endif()
|
||||
|
@ -71,25 +71,11 @@ void Core::MessageHandler::onMessageReceived(const QXmppMessage& msg) {
|
||||
case QXmppMessage::GroupChat:
|
||||
handled = handleGroupMessage(msg);
|
||||
break;
|
||||
case QXmppMessage::Error: {
|
||||
std::tuple<bool, QString, QString> ids = getOriginalPendingMessageId(msg.id());
|
||||
if (std::get<0>(ids)) {
|
||||
QString id = std::get<1>(ids);
|
||||
QString jid = std::get<2>(ids);
|
||||
RosterItem* cnt = acc->rh->getRosterItem(jid);
|
||||
QMap<QString, QVariant> cData = {
|
||||
{"state", static_cast<uint>(Shared::Message::State::error)},
|
||||
{"errorText", msg.error().text()}
|
||||
};
|
||||
if (cnt != nullptr)
|
||||
cnt->changeMessage(id, cData);
|
||||
|
||||
emit acc->changeMessage(jid, id, cData);
|
||||
handled = true;
|
||||
} else {
|
||||
case QXmppMessage::Error:
|
||||
handled = handlePendingMessageError(msg.id(), msg.error().text());
|
||||
if (!handled)
|
||||
qDebug() << "received a message with type \"Error\", not sure what to do with it now, skipping";
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case QXmppMessage::Headline:
|
||||
qDebug() << "received a message with type \"Headline\", not sure what to do with it now, skipping";
|
||||
@ -99,6 +85,27 @@ void Core::MessageHandler::onMessageReceived(const QXmppMessage& msg) {
|
||||
logMessage(msg);
|
||||
}
|
||||
|
||||
bool Core::MessageHandler::handlePendingMessageError(const QString& id, const QString& errorText) {
|
||||
std::tuple<bool, QString, QString> ids = getOriginalPendingMessageId(id);
|
||||
if (std::get<0>(ids)) {
|
||||
QString id = std::get<1>(ids);
|
||||
QString jid = std::get<2>(ids);
|
||||
RosterItem* ri = acc->rh->getRosterItem(jid);
|
||||
QMap<QString, QVariant> cData = {
|
||||
{"state", static_cast<uint>(Shared::Message::State::error)},
|
||||
{"errorText", errorText}
|
||||
};
|
||||
if (ri != nullptr)
|
||||
ri->changeMessage(id, cData);
|
||||
|
||||
emit acc->changeMessage(jid, id, cData);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Core::MessageHandler::handleChatMessage(const QXmppMessage& msg, bool outgoing, bool forwarded, bool guessing) {
|
||||
if (msg.body().size() != 0 || msg.outOfBandUrl().size() > 0) {
|
||||
Shared::Message sMsg(Shared::Message::chat);
|
||||
@ -182,9 +189,9 @@ void Core::MessageHandler::initializeMessage(Shared::Message& target, const QXmp
|
||||
QString id;
|
||||
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 3, 0)
|
||||
id = source.originId();
|
||||
if (id.size() == 0) {
|
||||
if (id.size() == 0)
|
||||
id = source.id();
|
||||
}
|
||||
|
||||
target.setStanzaId(source.stanzaId());
|
||||
qDebug() << "initializing message with originId:" << source.originId() << ", id:" << source.id() << ", stansaId:" << source.stanzaId();
|
||||
#else
|
||||
@ -202,24 +209,19 @@ void Core::MessageHandler::initializeMessage(Shared::Message& target, const QXmp
|
||||
target.setBody(source.body());
|
||||
target.setForwarded(forwarded);
|
||||
|
||||
if (guessing) {
|
||||
if (target.getFromJid() == acc->getBareJid()) {
|
||||
outgoing = true;
|
||||
} else {
|
||||
outgoing = false;
|
||||
}
|
||||
}
|
||||
if (guessing)
|
||||
outgoing = target.getFromJid() == acc->getBareJid();
|
||||
|
||||
target.setOutgoing(outgoing);
|
||||
if (time.isValid()) {
|
||||
if (time.isValid())
|
||||
target.setTime(time);
|
||||
} else {
|
||||
else
|
||||
target.setCurrentTime();
|
||||
}
|
||||
|
||||
QString oob = source.outOfBandUrl();
|
||||
if (oob.size() > 0) {
|
||||
if (oob.size() > 0)
|
||||
target.setAttachPath(acc->network->addMessageAndCheckForPath(oob, acc->getName(), target.getPenPalJid(), messageId));
|
||||
}
|
||||
|
||||
target.setOutOfBandUrl(oob);
|
||||
}
|
||||
|
||||
@ -249,7 +251,7 @@ void Core::MessageHandler::onCarbonMessageSent(const QXmppMessage& msg) {
|
||||
}
|
||||
#endif
|
||||
|
||||
std::tuple<bool, QString, QString> Core::MessageHandler::getOriginalPendingMessageId(const QString& id) {
|
||||
std::tuple<bool, QString, QString> Core::MessageHandler::getOriginalPendingMessageId(const QString& id, bool clear) {
|
||||
std::tuple<bool, QString, QString> result({false, "", ""});
|
||||
std::map<QString, QString>::const_iterator itr = pendingStateMessages.find(id);
|
||||
if (itr != pendingStateMessages.end()) {
|
||||
@ -263,11 +265,13 @@ std::tuple<bool, QString, QString> Core::MessageHandler::getOriginalPendingMessa
|
||||
else
|
||||
std::get<1>(result) = itr->first;
|
||||
|
||||
if (clear)
|
||||
pendingCorrectionMessages.erase(itrC);
|
||||
} else {
|
||||
std::get<1>(result) = itr->first;
|
||||
}
|
||||
|
||||
if (clear)
|
||||
pendingStateMessages.erase(itr);
|
||||
}
|
||||
|
||||
@ -281,9 +285,9 @@ void Core::MessageHandler::onReceiptReceived(const QString& jid, const QString&
|
||||
QMap<QString, QVariant> cData = {{"state", static_cast<uint>(Shared::Message::State::delivered)}};
|
||||
RosterItem* ri = acc->rh->getRosterItem(std::get<2>(ids));
|
||||
|
||||
if (ri != nullptr) {
|
||||
if (ri != nullptr)
|
||||
ri->changeMessage(std::get<1>(ids), cData);
|
||||
}
|
||||
|
||||
emit acc->changeMessage(std::get<2>(ids), std::get<1>(ids), cData);
|
||||
}
|
||||
}
|
||||
@ -302,45 +306,25 @@ void Core::MessageHandler::performSending(Shared::Message data, const QString& o
|
||||
QString id = data.getId();
|
||||
qDebug() << "Sending message with id:" << id;
|
||||
if (originalId.size() > 0)
|
||||
qDebug() << "To replace one with id:" << originalId;
|
||||
qDebug() << "To replace the one with id:" << originalId;
|
||||
|
||||
RosterItem* ri = acc->rh->getRosterItem(jid);
|
||||
bool sent = false;
|
||||
if (newMessage && originalId.size() > 0)
|
||||
newMessage = false;
|
||||
|
||||
QDateTime sendTime = QDateTime::currentDateTimeUtc();
|
||||
if (acc->state == Shared::ConnectionState::connected) {
|
||||
QXmppMessage msg(createPacket(data, sendTime, originalId));
|
||||
|
||||
sent = acc->client.sendPacket(msg);
|
||||
if (sent) {
|
||||
data.setState(Shared::Message::State::sent);
|
||||
} else {
|
||||
data.setState(Shared::Message::State::error);
|
||||
data.setErrorText("Couldn't send message: internal QXMPP library error, probably need to check out the logs");
|
||||
}
|
||||
|
||||
} else {
|
||||
data.setState(Shared::Message::State::error);
|
||||
data.setErrorText("You are is offline or reconnecting");
|
||||
}
|
||||
std::pair<Shared::Message::State, QString> result = scheduleSending(data, sendTime, originalId);
|
||||
data.setState(result.first);
|
||||
data.setErrorText(result.second);
|
||||
|
||||
QMap<QString, QVariant> changes(getChanges(data, sendTime, newMessage, originalId));
|
||||
|
||||
QString realId;
|
||||
if (originalId.size() > 0)
|
||||
realId = originalId;
|
||||
else
|
||||
realId = id;
|
||||
|
||||
if (ri != nullptr) {
|
||||
if (newMessage)
|
||||
ri->appendMessageToArchive(data);
|
||||
else
|
||||
ri->changeMessage(realId, changes);
|
||||
ri->changeMessage(originalId.isEmpty() ? id : originalId, changes);
|
||||
|
||||
if (sent) {
|
||||
if (data.getState() != Shared::Message::State::error) {
|
||||
pendingStateMessages.insert(std::make_pair(id, jid));
|
||||
if (originalId.size() > 0)
|
||||
pendingCorrectionMessages.insert(std::make_pair(id, originalId));
|
||||
@ -350,9 +334,81 @@ void Core::MessageHandler::performSending(Shared::Message data, const QString& o
|
||||
}
|
||||
}
|
||||
|
||||
emit acc->changeMessage(jid, realId, changes);
|
||||
emit acc->changeMessage(jid, originalId.isEmpty() ? id : originalId, changes);
|
||||
}
|
||||
|
||||
std::pair<Shared::Message::State, QString> Core::MessageHandler::scheduleSending(
|
||||
const Shared::Message& message,
|
||||
const QDateTime& sendTime,
|
||||
const QString& originalId
|
||||
) {
|
||||
if (acc->state != Shared::ConnectionState::connected)
|
||||
return {Shared::Message::State::error, "You are is offline or reconnecting"};
|
||||
|
||||
QXmppMessage msg = createPacket(message, sendTime, originalId);
|
||||
QString id = msg.id();
|
||||
#ifdef WITH_OMEMO
|
||||
if (message.getEncryption() == Shared::EncryptionProtocol::omemo2) {
|
||||
QXmppTask<QXmppE2eeExtension::MessageEncryptResult> task = acc->om->encryptMessage(std::move(msg), std::nullopt);
|
||||
if (task.isFinished()) {
|
||||
const QXmppE2eeExtension::MessageEncryptResult& res = task.result();
|
||||
if (std::holds_alternative<std::unique_ptr<QXmppMessage>>(res)) {
|
||||
const std::unique_ptr<QXmppMessage>& encrypted = std::get<std::unique_ptr<QXmppMessage>>(res);
|
||||
bool success = acc->client.sendPacket(*encrypted.get());
|
||||
if (success)
|
||||
return {Shared::Message::State::sent, ""};
|
||||
else
|
||||
return {Shared::Message::State::error, "Error sending successfully encrypted message"};
|
||||
} else if (std::holds_alternative<QXmppError>(res)) {
|
||||
const QXmppError& err = std::get<QXmppError>(res);
|
||||
return {Shared::Message::State::error, err.description};
|
||||
} else {
|
||||
return {Shared::Message::State::error, "Unexpected error ecryptng the message"};
|
||||
}
|
||||
} else {
|
||||
task.then(this, [this, id] (QXmppE2eeExtension::MessageEncryptResult&& result) {
|
||||
if (std::holds_alternative<std::unique_ptr<QXmppMessage>>(result)) {
|
||||
const std::unique_ptr<QXmppMessage>& encrypted = std::get<std::unique_ptr<QXmppMessage>>(result);
|
||||
encrypted->setBody("This message is encrypted with OMEMO 2 but could not be decrypted");
|
||||
bool success = acc->client.sendPacket(*encrypted.get());
|
||||
if (success) {
|
||||
std::tuple<bool, QString, QString> ids = getOriginalPendingMessageId(id, false);
|
||||
if (std::get<0>(ids)) {
|
||||
QString id = std::get<1>(ids);
|
||||
QString jid = std::get<2>(ids);
|
||||
RosterItem* ri = acc->rh->getRosterItem(jid);
|
||||
QMap<QString, QVariant> cData = {{"state", static_cast<uint>(Shared::Message::State::sent)}};
|
||||
if (ri != nullptr)
|
||||
ri->changeMessage(id, cData);
|
||||
|
||||
emit acc->changeMessage(jid, id, cData);
|
||||
} else {
|
||||
qDebug() << "Encrypted message has been successfully sent, but it couldn't be found to update the sate";
|
||||
}
|
||||
} else {
|
||||
handlePendingMessageError(id, "Error sending successfully encrypted message");
|
||||
}
|
||||
} else if (std::holds_alternative<QXmppError>(result)) {
|
||||
const QXmppError& err = std::get<QXmppError>(result);
|
||||
handlePendingMessageError(id, err.description);
|
||||
} else {
|
||||
handlePendingMessageError(id, "Unexpected error ecryptng the message");
|
||||
}
|
||||
});
|
||||
return {Shared::Message::State::pending, ""};
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
bool success = acc->client.sendPacket(msg);
|
||||
if (success)
|
||||
return {Shared::Message::State::sent, ""};
|
||||
else
|
||||
return {Shared::Message::State::error, "Error sending message, internal QXMPP error"};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QMap<QString, QVariant> Core::MessageHandler::getChanges(Shared::Message& data, const QDateTime& time, bool newMessage, const QString& originalId) const {
|
||||
QMap<QString, QVariant> changes;
|
||||
|
||||
|
@ -23,9 +23,13 @@
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
|
||||
#include <QXmppMessage.h>
|
||||
#include <QXmppHttpUploadIq.h>
|
||||
#ifdef WITH_OMEMO
|
||||
#include <QXmppE2eeExtension.h>
|
||||
#endif
|
||||
|
||||
#include <shared/message.h>
|
||||
#include <shared/messageinfo.h>
|
||||
@ -74,7 +78,9 @@ private:
|
||||
void handleUploadError(const QString& jid, const QString& messageId, const QString& errorText);
|
||||
QXmppMessage createPacket(const Shared::Message& data, const QDateTime& time, const QString& originalId) const;
|
||||
QMap<QString, QVariant> getChanges(Shared::Message& data, const QDateTime& time, bool newMessage, const QString& originalId) const;
|
||||
std::tuple<bool, QString, QString> getOriginalPendingMessageId(const QString& id);
|
||||
std::tuple<bool, QString, QString> getOriginalPendingMessageId(const QString& id, bool clear = true);
|
||||
bool handlePendingMessageError(const QString& id, const QString& errorText);
|
||||
std::pair<Shared::Message::State, QString> scheduleSending(const Shared::Message& message, const QDateTime& sendTime, const QString& originalId);
|
||||
|
||||
private:
|
||||
Account* acc;
|
||||
|
@ -247,6 +247,19 @@ void Shared::Message::setEdited(bool p_edited) {
|
||||
edited = p_edited;
|
||||
}
|
||||
|
||||
Shared::EncryptionProtocol Shared::Message::getEncryption() const {
|
||||
return encryption;
|
||||
}
|
||||
|
||||
void Shared::Message::setEncryption(EncryptionProtocol encryption) {
|
||||
Shared::Message::encryption = encryption;
|
||||
}
|
||||
|
||||
void Shared::Message::setError(const QString& text) {
|
||||
state = State::error;
|
||||
errorText = text;
|
||||
}
|
||||
|
||||
QDataStream& operator<<(QDataStream& out, const Shared::Message& info) {
|
||||
out << info.jFrom;
|
||||
out << info.rFrom;
|
||||
@ -271,6 +284,7 @@ QDataStream& operator<<(QDataStream& out, const Shared::Message& info) {
|
||||
}
|
||||
out << info.stanzaId;
|
||||
out << info.attachPath;
|
||||
out << (quint8)info.encryption;
|
||||
|
||||
return out;
|
||||
}
|
||||
@ -303,6 +317,9 @@ QDataStream & operator>>(QDataStream& in, Shared::Message& info) {
|
||||
}
|
||||
in >> info.stanzaId;
|
||||
in >> info.attachPath;
|
||||
quint8 e;
|
||||
in >> e;
|
||||
info.encryption = static_cast<Shared::EncryptionProtocol>(e);
|
||||
|
||||
return in;
|
||||
}
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include <QMap>
|
||||
#include <QDataStream>
|
||||
|
||||
#include "enums.h"
|
||||
|
||||
namespace Shared {
|
||||
class Message;
|
||||
}
|
||||
@ -94,6 +96,9 @@ public:
|
||||
bool change(const QMap<QString, QVariant>& data);
|
||||
void setStanzaId(const QString& sid);
|
||||
void setAttachPath(const QString& path);
|
||||
void setEncryption(EncryptionProtocol encryption);
|
||||
|
||||
void setError(const QString& text);
|
||||
|
||||
QString getFrom() const;
|
||||
QString getFromJid() const;
|
||||
@ -123,6 +128,7 @@ public:
|
||||
QString getOriginalBody() const;
|
||||
QString getStanzaId() const;
|
||||
QString getAttachPath() const;
|
||||
EncryptionProtocol getEncryption() const;
|
||||
|
||||
private:
|
||||
QString jFrom;
|
||||
@ -144,6 +150,7 @@ private:
|
||||
QDateTime lastModified;
|
||||
QString stanzaId;
|
||||
QString attachPath;
|
||||
EncryptionProtocol encryption;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -31,10 +31,12 @@ Chat::Chat(Models::Account* acc, Models::Contact* p_contact, QWidget* parent):
|
||||
setAvatar(p_contact->getAvatarPath());
|
||||
|
||||
connect(contact, &Models::Contact::childChanged, this, &Chat::onContactChanged);
|
||||
#ifdef WITH_OMEMO
|
||||
if (p_contact->hasKeys(Shared::EncryptionProtocol::omemo2)) {
|
||||
m_ui->encryptionButton->setVisible(true);
|
||||
//if ()
|
||||
updateEncryptionState();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Chat::~Chat()
|
||||
@ -56,9 +58,14 @@ void Chat::onContactChanged(Models::Item* item, int row, int col) {
|
||||
case 7:
|
||||
setAvatar(contact->getAvatarPath());
|
||||
break;
|
||||
#ifdef WITH_OMEMO
|
||||
case 8:
|
||||
m_ui->encryptionButton->setVisible(contact->hasKeys(Shared::EncryptionProtocol::omemo2));
|
||||
break;
|
||||
case 9:
|
||||
updateEncryptionState();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -69,12 +76,25 @@ void Chat::updateState() {
|
||||
statusIcon->setToolTip(Shared::Global::getName(av));
|
||||
}
|
||||
|
||||
void Chat::updateEncryptionState() {
|
||||
m_ui->encryptionButton->setEnabled(true);
|
||||
if (contact->getEncryption() == Shared::EncryptionProtocol::omemo2)
|
||||
m_ui->encryptionButton->setIcon(Shared::icon("lock"));
|
||||
else
|
||||
m_ui->encryptionButton->setIcon(Shared::icon("unlock"));
|
||||
}
|
||||
|
||||
|
||||
Shared::Message Chat::createMessage() const {
|
||||
Shared::Message msg = Conversation::createMessage();
|
||||
msg.setType(Shared::Message::chat);
|
||||
msg.setFrom(account->getFullJid());
|
||||
msg.setToJid(palJid);
|
||||
msg.setToResource(activePalResource);
|
||||
#ifdef WITH_OMEMO
|
||||
if (contact->getEncryption() == Shared::EncryptionProtocol::omemo2)
|
||||
msg.setEncryption(Shared::EncryptionProtocol::omemo2);
|
||||
#endif
|
||||
return msg;
|
||||
}
|
||||
|
||||
@ -87,3 +107,11 @@ void Chat::onMessage(const Shared::Message& data){
|
||||
setPalResource(res);
|
||||
}
|
||||
}
|
||||
|
||||
void Chat::onEncryptionButtonClicked() {
|
||||
m_ui->encryptionButton->setEnabled(false);
|
||||
if (contact->getEncryption() == Shared::EncryptionProtocol::omemo2)
|
||||
emit setEncryption(Shared::EncryptionProtocol::none);
|
||||
else
|
||||
emit setEncryption(Shared::EncryptionProtocol::omemo2);
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ public:
|
||||
|
||||
protected slots:
|
||||
void onContactChanged(Models::Item* item, int row, int col);
|
||||
void onEncryptionButtonClicked() override;
|
||||
|
||||
protected:
|
||||
Shared::Message createMessage() const override;
|
||||
@ -44,6 +45,7 @@ protected:
|
||||
|
||||
private:
|
||||
void updateState();
|
||||
void updateEncryptionState();
|
||||
|
||||
private:
|
||||
Models::Contact* contact;
|
||||
|
@ -91,6 +91,7 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
|
||||
connect(m_ui->clearButton, &QPushButton::clicked, this, &Conversation::clear);
|
||||
connect(m_ui->messageEditor->document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged,
|
||||
this, &Conversation::onTextEditDocSizeChanged);
|
||||
connect(m_ui->encryptionButton, &QPushButton::clicked, this, &Conversation::onEncryptionButtonClicked);
|
||||
|
||||
m_ui->messageEditor->installEventFilter(&ker);
|
||||
|
||||
@ -345,6 +346,8 @@ void Conversation::clear() {
|
||||
m_ui->messageEditor->clear();
|
||||
}
|
||||
|
||||
void Conversation::onEncryptionButtonClicked() {}
|
||||
|
||||
void Conversation::setAvatar(const QString& path) {
|
||||
QPixmap pixmap;
|
||||
if (path.size() == 0) {
|
||||
|
@ -119,6 +119,7 @@ protected slots:
|
||||
void onFeedContext(const QPoint &pos);
|
||||
void onMessageEditorContext(const QPoint &pos);
|
||||
void onMessageEditRequested(const QString& id);
|
||||
virtual void onEncryptionButtonClicked();
|
||||
|
||||
public:
|
||||
const bool isMuc;
|
||||
|
@ -230,6 +230,7 @@ std::set<Models::MessageFeed::MessageRoles> Models::MessageFeed::detectChanges(c
|
||||
}
|
||||
|
||||
void Models::MessageFeed::removeMessage(const QString& id) {
|
||||
SHARED_UNUSED(id);
|
||||
//todo;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user