From 48e735b0e961f9288400c23cb8a6b71ff912ed8e Mon Sep 17 00:00:00 2001 From: blue Date: Fri, 12 Apr 2019 18:22:10 +0300 Subject: [PATCH] Carbon copies basic support --- CMakeLists.txt | 1 + core/account.cpp | 87 +++++++++++++++++++++++++++++---------------- core/account.h | 6 ++++ global.cpp | 48 +++++++++++++++++++++++-- global.h | 9 +++++ ui/conversation.cpp | 57 +++++++++++++++++++++++------ ui/conversation.h | 5 +++ ui/messageline.cpp | 31 +++++++++++++--- ui/messageline.h | 7 +++- ui/squawk.cpp | 16 +++++++-- 10 files changed, 215 insertions(+), 52 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f51811..a638787 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ add_subdirectory(core) target_link_libraries(squawk squawkUI) target_link_libraries(squawk squawkCORE) +target_link_libraries(squawk uuid) # Install the executable install(TARGETS squawk DESTINATION bin) diff --git a/core/account.cpp b/core/account.cpp index 94ede01..33623a2 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -1,5 +1,4 @@ #include "account.h" -#include #include #include @@ -12,7 +11,8 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& config(), presence(), state(Shared::disconnected), - groups() + groups(), + cm(new QXmppCarbonManager()) { config.setUser(p_login); config.setDomain(p_server); @@ -30,6 +30,11 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& QObject::connect(&rm, SIGNAL(itemRemoved(const QString&)), this, SLOT(onRosterItemRemoved(const QString&))); QObject::connect(&rm, SIGNAL(itemChanged(const QString&)), this, SLOT(onRosterItemChanged(const QString&))); //QObject::connect(&rm, SIGNAL(presenceChanged(const QString&, const QString&)), this, SLOT(onRosterPresenceChanged(const QString&, const QString&))); + + client.addExtension(cm); + + QObject::connect(cm, SIGNAL(messageReceived(const QXmppMessage&)), this, SLOT(onCarbonMessageReceived(const QXmppMessage&))); + QObject::connect(cm, SIGNAL(messageSent(const QXmppMessage&)), this, SLOT(onCarbonMessageSent(const QXmppMessage&))); } Account::~Account() @@ -65,6 +70,7 @@ void Core::Account::onClientConnected() { if (state == Shared::connecting) { state = Shared::connected; + cm->setCarbonsEnabled(true); emit connectionStateChanged(state); } else { qDebug("Something weird had happened - xmpp client reported about successful connection but account wasn't in connecting state"); @@ -335,36 +341,13 @@ void Core::Account::setResource(const QString& p_resource) void Core::Account::onMessageReceived(const QXmppMessage& msg) { - QString from = msg.from(); - QString to = msg.to(); bool handled = false; switch (msg.type()) { case QXmppMessage::Normal: qDebug() << "received a message with type \"Normal\", not sure what to do with it now, skipping"; break; - case QXmppMessage::Chat:{ - QString body(msg.body()); - if (body.size() != 0) { - QString id(msg.id()); - QDateTime time(msg.stamp()); - Shared::Message sMsg(Shared::Message::chat); - sMsg.setId(id); - sMsg.setFrom(from); - sMsg.setTo(to); - sMsg.setBody(body); - if (time.isValid()) { - sMsg.setTime(time); - } - emit message(sMsg); - - if (msg.isReceiptRequested() && id.size() > 0) { - QXmppMessage receipt(getFullJid(), from, ""); - receipt.setReceiptId(id); - client.sendPacket(receipt); - handled = true; - } - } - } + case QXmppMessage::Chat: + handled = handleChatMessage(msg); break; case QXmppMessage::GroupChat: qDebug() << "received a message with type \"GroupChat\", not sure what to do with it now, skipping"; @@ -377,10 +360,9 @@ void Core::Account::onMessageReceived(const QXmppMessage& msg) break; } if (!handled) { - qDebug() << "Message wasn't handled: "; - qDebug() << "- from: " << from; - qDebug() << "- to: " << to; + qDebug() << "- from: " << msg.from(); + qDebug() << "- to: " << msg.to(); qDebug() << "- body: " << msg.body(); qDebug() << "- type: " << msg.type(); qDebug() << "- state: " << msg.state(); @@ -404,9 +386,52 @@ QString Core::Account::getFullJid() const void Core::Account::sendMessage(const Shared::Message& data) { if (state == Shared::connected) { - client.sendMessage(data.getTo(), data.getBody()); + QXmppMessage msg(data.getFrom(), data.getTo(), data.getBody(), data.getThread()); + msg.setId(data.getId()); + msg.setType(static_cast(data.getType())); //it is safe here, my type is compatible + client.sendPacket(msg); } else { qDebug() << "An attempt to send message with not connected account " << name << ", skipping"; } } +void Core::Account::onCarbonMessageReceived(const QXmppMessage& msg) +{ + handleChatMessage(msg, false, true); +} + +void Core::Account::onCarbonMessageSent(const QXmppMessage& msg) +{ + handleChatMessage(msg, true, true); +} + +bool Core::Account::handleChatMessage(const QXmppMessage& msg, bool outgoing, bool forwarded) +{ + QString body(msg.body()); + if (body.size() != 0) { + QString id(msg.id()); + QDateTime time(msg.stamp()); + Shared::Message sMsg(Shared::Message::chat); + sMsg.setId(id); + sMsg.setFrom(msg.from()); + sMsg.setTo(msg.to()); + sMsg.setBody(body); + sMsg.setForwarded(forwarded); + sMsg.setOutgoing(outgoing); + if (time.isValid()) { + sMsg.setTime(time); + } + emit message(sMsg); + + if (!forwarded && !outgoing) { + if (msg.isReceiptRequested() && id.size() > 0) { + QXmppMessage receipt(getFullJid(), msg.from(), ""); + receipt.setReceiptId(id); + client.sendPacket(receipt); + } + } + + return true; + } + return false; +} diff --git a/core/account.h b/core/account.h index 322c351..d15d382 100644 --- a/core/account.h +++ b/core/account.h @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include "../global.h" @@ -58,6 +60,7 @@ private: QXmppPresence presence; Shared::ConnectionState state; std::map> groups; + QXmppCarbonManager* cm; private slots: void onClientConnected(); @@ -69,9 +72,12 @@ private slots: void onRosterPresenceChanged(const QString& bareJid, const QString& resource); void onPresenceReceived(const QXmppPresence& presence); void onMessageReceived(const QXmppMessage& message); + void onCarbonMessageReceived(const QXmppMessage& message); + void onCarbonMessageSent(const QXmppMessage& message); private: void addedAccount(const QString &bareJid); + bool handleChatMessage(const QXmppMessage& msg, bool outgoing = false, bool forwarded = false); }; } diff --git a/global.cpp b/global.cpp index 3cd8bdb..4520b4d 100644 --- a/global.cpp +++ b/global.cpp @@ -1,4 +1,5 @@ #include "global.h" +#include Shared::Message::Message(Shared::Message::Type p_type): jFrom(), @@ -8,8 +9,10 @@ Shared::Message::Message(Shared::Message::Type p_type): id(), body(), time(), + thread(), type(p_type), - outgoing(false) + outgoing(false), + forwarded(false) { } @@ -21,8 +24,10 @@ Shared::Message::Message(): id(), body(), time(), + thread(), type(Message::normal), - outgoing(false) + outgoing(false), + forwarded(false) { } @@ -164,3 +169,42 @@ void Shared::Message::setOutgoing(bool og) outgoing = og; } +bool Shared::Message::getForwarded() const +{ + return forwarded; +} + +void Shared::Message::generateRandomId() +{ + uuid_t uuid; + uuid_generate(uuid); + + char uuid_str[37]; + uuid_unparse_lower(uuid, uuid_str); + id = uuid_str; +} + +QString Shared::Message::getThread() const +{ + return thread; +} + +void Shared::Message::setForwarded(bool fwd) +{ + forwarded = fwd; +} + +void Shared::Message::setThread(const QString& p_body) +{ + thread = p_body; +} + +Shared::Message::Type Shared::Message::getType() const +{ + return type; +} + +void Shared::Message::setType(Shared::Message::Type t) +{ + type = t; +} diff --git a/global.h b/global.h index 2af5cce..e4fa761 100644 --- a/global.h +++ b/global.h @@ -73,7 +73,10 @@ public: void setTime(const QDateTime& p_time); void setId(const QString& p_id); void setBody(const QString& p_body); + void setThread(const QString& p_body); void setOutgoing(bool og); + void setForwarded(bool fwd); + void setType(Type t); QString getFrom() const; QString getFromJid() const; @@ -84,10 +87,14 @@ public: QDateTime getTime() const; QString getId() const; QString getBody() const; + QString getThread() const; bool getOutgoing() const; + bool getForwarded() const; + Type getType() const; QString getPenPalJid() const; QString getPenPalResource() const; + void generateRandomId(); private: QString jFrom; @@ -97,8 +104,10 @@ private: QString id; QString body; QDateTime time; + QString thread; Type type; bool outgoing; + bool forwarded; }; }; diff --git a/ui/conversation.cpp b/ui/conversation.cpp index d7e4246..a0e945b 100644 --- a/ui/conversation.cpp +++ b/ui/conversation.cpp @@ -19,13 +19,16 @@ #include "conversation.h" #include "ui_conversation.h" #include +#include Conversation::Conversation(Models::Contact* p_contact, QWidget* parent): QWidget(parent), contact(p_contact), m_ui(new Ui::Conversation), line(new MessageLine()), - ker() + ker(), + activePalResource(), + thread() { m_ui->setupUi(this); m_ui->splitter->setSizes({300, 0}); @@ -47,7 +50,10 @@ Conversation::Conversation(Models::Contact* p_contact, QWidget* parent): addMessage(*itr); } + line->setMyName(p_contact->getAccountName()); + m_ui->scrollArea->setWidget(line); + m_ui->scrollArea->verticalScrollBar()->setBackgroundRole(QPalette::Base); } Conversation::~Conversation() @@ -61,6 +67,7 @@ void Conversation::setName(const QString& name) m_ui->nameLabel->setText(getJid()); } else { m_ui->nameLabel->setText(name); + line->setPalName(getJid(), name); } } @@ -101,7 +108,19 @@ void Conversation::onContactChanged(Models::Item* item, int row, int col) void Conversation::addMessage(const Shared::Message& data) { + int pos = m_ui->scrollArea->verticalScrollBar()->sliderPosition(); + int max = m_ui->scrollArea->verticalScrollBar()->maximum(); line->message(data); + + if (pos == max) { + m_ui->scrollArea->verticalScrollBar()->setSliderPosition(m_ui->scrollArea->verticalScrollBar()->maximum()); + } + if (!data.getOutgoing()) { + const QString& res = data.getPenPalResource(); + if (res.size() > 0) { + setPalResource(res); + } + } } KeyEnterReceiver::KeyEnterReceiver(QObject* parent): QObject(parent), ownEvent(false) {} @@ -133,17 +152,33 @@ bool KeyEnterReceiver::eventFilter(QObject* obj, QEvent* event) return QObject::eventFilter(obj, event); } +QString Conversation::getPalResource() const +{ + return activePalResource; +} + +void Conversation::setPalResource(const QString& res) +{ + activePalResource = res; +} + void Conversation::onEnterPressed() { QString body(m_ui->messageEditor->toPlainText()); - const QString& aJid = contact->getAccountJid(); - m_ui->messageEditor->clear(); - Shared::Message msg(Shared::Message::chat); - msg.setFromJid(aJid); - msg.setFromResource(contact->getAccountResource()); - msg.setTo(contact->getJid()); - msg.setBody(body); - msg.setOutgoing(true); - line->message(msg); - emit sendMessage(msg); + + if (body.size() > 0) { + const QString& aJid = contact->getAccountJid(); + m_ui->messageEditor->clear(); + Shared::Message msg(Shared::Message::chat); + msg.setFromJid(aJid); + msg.setFromResource(contact->getAccountResource()); + qDebug() << "sending message from " << contact->getAccountResource(); + msg.setToJid(contact->getJid()); + msg.setToResource(activePalResource); + msg.setBody(body); + msg.setOutgoing(true); + msg.generateRandomId(); + line->message(msg); + emit sendMessage(msg); + } } diff --git a/ui/conversation.h b/ui/conversation.h index 4c74d19..99e6c26 100644 --- a/ui/conversation.h +++ b/ui/conversation.h @@ -52,8 +52,11 @@ public: QString getJid() const; QString getAccount() const; + QString getPalResource() const; void addMessage(const Shared::Message& data); + void setPalResource(const QString& res); + signals: void sendMessage(const Shared::Message& message); @@ -71,6 +74,8 @@ private: MessageLine* line; QScopedPointer m_ui; KeyEnterReceiver ker; + QString activePalResource; + QString thread; }; #endif // CONVERSATION_H diff --git a/ui/messageline.cpp b/ui/messageline.cpp index ac4450f..c73d6e4 100644 --- a/ui/messageline.cpp +++ b/ui/messageline.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (C) 2019 Юрий Губич + * Copyright (C) 2019 Yury Gubich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,7 +22,9 @@ MessageLine::MessageLine(QWidget* parent): QWidget(parent), messageIndex(), messageOrder(), - layout(new QVBoxLayout()) + layout(new QVBoxLayout()), + myName(), + palNames() { setLayout(layout); setBackgroundRole(QPalette::Base); @@ -39,12 +41,11 @@ void MessageLine::message(const Shared::Message& msg) QHBoxLayout* hBox = new QHBoxLayout(); QWidget* message = new QWidget(); message->setLayout(vBox); - //message->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); message->setBackgroundRole(QPalette::AlternateBase); message->setAutoFillBackground(true);; QLabel* body = new QLabel(msg.getBody()); - QLabel* sender = new QLabel(msg.getFrom()); + QLabel* sender = new QLabel(); QFont f; f.setBold(true); sender->setFont(f); @@ -57,9 +58,17 @@ void MessageLine::message(const Shared::Message& msg) if (msg.getOutgoing()) { body->setAlignment(Qt::AlignRight); sender->setAlignment(Qt::AlignRight); + sender->setText(myName); hBox->addStretch(); hBox->addWidget(message); } else { + QString jid = msg.getFromJid(); + std::map::iterator itr = palNames.find(jid); + if (itr != palNames.end()) { + sender->setText(itr->second); + } else { + sender->setText(jid); + } hBox->addWidget(message); hBox->addStretch(); } @@ -67,3 +76,17 @@ void MessageLine::message(const Shared::Message& msg) layout->addLayout(hBox); } +void MessageLine::setMyName(const QString& name) +{ + myName = name; +} + +void MessageLine::setPalName(const QString& jid, const QString& name) +{ + std::map::iterator itr = palNames.find(jid); + if (itr == palNames.end()) { + palNames.insert(std::make_pair(jid, name)); + } else { + itr->second = name; + } +} diff --git a/ui/messageline.h b/ui/messageline.h index cd7af16..021f60d 100644 --- a/ui/messageline.h +++ b/ui/messageline.h @@ -1,6 +1,6 @@ /* * - * Copyright (C) 2019 Юрий Губич + * Copyright (C) 2019 Yury Gubich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,12 +34,17 @@ public: ~MessageLine(); void message(const Shared::Message& msg); + void setMyName(const QString& name); + void setPalName(const QString& jid, const QString& name); private: typedef W::Order Order; std::map messageIndex; Order messageOrder; QVBoxLayout* layout; + + QString myName; + std::map palNames; }; #endif // MESSAGELINE_H diff --git a/ui/squawk.cpp b/ui/squawk.cpp index fedeeea..da9f551 100644 --- a/ui/squawk.cpp +++ b/ui/squawk.cpp @@ -156,12 +156,14 @@ void Squawk::onRosterItemDoubleClicked(const QModelIndex& item) if (item.isValid()) { Models::Item* node = static_cast(item.internalPointer()); Models::Contact* contact = 0; + QString res; switch (node->type) { case Models::Item::contact: contact = static_cast(node); break; case Models::Item::presence: contact = static_cast(node->parentItem()); + res = node->getName(); break; default: m_ui->roster->expand(item); @@ -177,6 +179,10 @@ void Squawk::onRosterItemDoubleClicked(const QModelIndex& item) itr->second->show(); itr->second->raise(); itr->second->activateWindow(); + + if (res.size() > 0) { + itr->second->setPalResource(res); + } } else { Conversation* conv = new Conversation(contact); @@ -188,6 +194,10 @@ void Squawk::onRosterItemDoubleClicked(const QModelIndex& item) rosterModel.dropMessages(account, jid); conv->show(); + + if (res.size() > 0) { + itr->second->setPalResource(res); + } } } } @@ -209,11 +219,11 @@ void Squawk::accountMessage(const QString& account, const Shared::Message& data) const QString& from = data.getPenPalJid(); Conversations::iterator itr = conversations.find({account, from}); if (itr != conversations.end()) { - qDebug() << "adding message"; itr->second->addMessage(data); } else { - qDebug() << "pending message"; - rosterModel.addMessage(account, data); + if (!data.getForwarded()) { + rosterModel.addMessage(account, data); + } } }