From b2699e0087f110e068fedd0998b51d833ce56662 Mon Sep 17 00:00:00 2001 From: blue Date: Tue, 18 Jun 2019 18:08:03 +0300 Subject: [PATCH] better new message handling, subscription with adding new contact, out of roster contacts handling --- core/account.cpp | 31 ++++++++++++++++++++++++++----- core/account.h | 3 +++ ui/CMakeLists.txt | 2 ++ ui/conversation.cpp | 13 +++++-------- ui/conversation.h | 1 + ui/models/contact.cpp | 15 ++++++++++----- ui/models/contact.h | 1 + ui/models/roster.cpp | 10 ++++++++++ ui/models/roster.h | 1 + ui/squawk.cpp | 42 +++++++++++++++++++++++++++++++++++++----- ui/squawk.h | 4 ++++ 11 files changed, 100 insertions(+), 23 deletions(-) diff --git a/core/account.cpp b/core/account.cpp index 6062c10..2be816e 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -18,7 +18,9 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& am(new QXmppMamManager()), contacts(), maxReconnectTimes(0), - reconnectTimes(0) + reconnectTimes(0), + queuedContacts(), + outOfRosterContacts() { config.setUser(p_login); config.setDomain(p_server); @@ -166,6 +168,12 @@ void Core::Account::setReconnectTimes(unsigned int times) void Core::Account::onRosterItemAdded(const QString& bareJid) { addedAccount(bareJid); + std::map::const_iterator itr = queuedContacts.find(bareJid); + if (itr != queuedContacts.end()) { + QXmppRosterManager& rm = client.rosterManager(); + rm.subscribe(bareJid, itr->second); + queuedContacts.erase(itr); + } } void Core::Account::onRosterItemChanged(const QString& bareJid) @@ -447,6 +455,7 @@ bool Core::Account::handleChatMessage(const QXmppMessage& msg, bool outgoing, bo } else { cnt = new Contact(jid, name); contacts.insert(std::make_pair(jid, cnt)); + outOfRosterContacts.insert(jid); cnt->setSubscriptionState(Shared::unknown); emit addContact(jid, "", QMap({ {"state", Shared::unknown} @@ -785,8 +794,14 @@ void Core::Account::unsubscribeFromContact(const QString& jid, const QString& re void Core::Account::removeContactRequest(const QString& jid) { if (state == Shared::connected) { - QXmppRosterManager& rm = client.rosterManager(); - rm.removeItem(jid); + std::set::const_iterator itr = outOfRosterContacts.find(jid); + if (itr != outOfRosterContacts.end()) { + outOfRosterContacts.erase(itr); + onRosterItemRemoved(jid); + } else { + QXmppRosterManager& rm = client.rosterManager(); + rm.removeItem(jid); + } } else { qDebug() << "An attempt to remove contact " << jid << " from account " << name << " but the account is not in the connected state, skipping"; } @@ -796,8 +811,14 @@ void Core::Account::removeContactRequest(const QString& jid) void Core::Account::addContactRequest(const QString& jid, const QString& name, const QSet& groups) { if (state == Shared::connected) { - QXmppRosterManager& rm = client.rosterManager(); - rm.addItem(jid, name, groups); + std::map::const_iterator itr = queuedContacts.find(jid); + if (itr != queuedContacts.end()) { + qDebug() << "An attempt to add contact " << jid << " to account " << name << " but the account is already queued for adding, skipping"; + } else { + queuedContacts.insert(std::make_pair(jid, "")); //TODO need to add reason here; + QXmppRosterManager& rm = client.rosterManager(); + rm.addItem(jid, name, groups); + } } else { qDebug() << "An attempt to add contact " << jid << " to account " << name << " but the account is not in the connected state, skipping"; } diff --git a/core/account.h b/core/account.h index 1bac071..a9a7e85 100644 --- a/core/account.h +++ b/core/account.h @@ -78,6 +78,9 @@ private: unsigned int maxReconnectTimes; unsigned int reconnectTimes; + std::map queuedContacts; + std::set outOfRosterContacts; + private slots: void onClientConnected(); void onClientDisconnected(); diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt index d70e04b..e36a101 100644 --- a/ui/CMakeLists.txt +++ b/ui/CMakeLists.txt @@ -8,6 +8,7 @@ set(CMAKE_AUTOUIC ON) # Find the QtWidgets library find_package(Qt5Widgets CONFIG REQUIRED) +find_package(Qt5DBus CONFIG REQUIRED) set(squawkUI_SRC squawk.cpp @@ -29,6 +30,7 @@ add_library(squawkUI ${squawkUI_SRC}) # Use the Widgets module from Qt 5. target_link_libraries(squawkUI Qt5::Widgets) +target_link_libraries(squawkUI Qt5::DBus) # Install the executable install(TARGETS squawkUI DESTINATION lib) diff --git a/ui/conversation.cpp b/ui/conversation.cpp index a29ea23..fdce53f 100644 --- a/ui/conversation.cpp +++ b/ui/conversation.cpp @@ -39,7 +39,7 @@ Conversation::Conversation(Models::Contact* p_contact, QWidget* parent): m_ui->splitter->setSizes({300, 0}); m_ui->splitter->setStretchFactor(1, 0); - setName(p_contact->getName()); + setName(p_contact->getContactName()); setState(p_contact->getAvailability()); connect(contact, SIGNAL(childChanged(Models::Item*, int, int)), this, SLOT(onContactChanged(Models::Item*, int, int))); @@ -71,12 +71,8 @@ Conversation::~Conversation() void Conversation::setName(const QString& name) { - if (name == "") { - m_ui->nameLabel->setText(getJid()); - } else { - m_ui->nameLabel->setText(name); - line->setPalName(getJid(), name); - } + m_ui->nameLabel->setText(name); + line->setPalName(getJid(), name); } void Conversation::setState(Shared::Availability state) @@ -105,7 +101,7 @@ void Conversation::onContactChanged(Models::Item* item, int row, int col) if (item == contact) { switch (col) { case 0: - setName(contact->getName()); + setName(contact->getContactName()); break; case 3: setState(contact->getAvailability()); @@ -252,6 +248,7 @@ void Conversation::showEvent(QShowEvent* event) requestingHistory = true; emit requestArchive(line->firstMessageId()); } + emit shown(); QWidget::showEvent(event); } diff --git a/ui/conversation.h b/ui/conversation.h index 3f5a315..f91bac3 100644 --- a/ui/conversation.h +++ b/ui/conversation.h @@ -62,6 +62,7 @@ public: signals: void sendMessage(const Shared::Message& message); void requestArchive(const QString& before); + void shown(); protected: void setState(Shared::Availability state); diff --git a/ui/models/contact.cpp b/ui/models/contact.cpp index a37a4eb..a68bd82 100644 --- a/ui/models/contact.cpp +++ b/ui/models/contact.cpp @@ -76,11 +76,7 @@ QVariant Models::Contact::data(int column) const { switch (column) { case 0: - if (name == "") { - return jid; - } else { - return Item::data(column); - } + return getContactName(); case 1: return jid; case 2: @@ -94,6 +90,15 @@ QVariant Models::Contact::data(int column) const } } +QString Models::Contact::getContactName() const +{ + if (name == "") { + return jid; + } else { + return name; + } +} + void Models::Contact::update(const QString& field, const QVariant& value) { if (field == "name") { diff --git a/ui/models/contact.h b/ui/models/contact.h index aad0e9a..40905d2 100644 --- a/ui/models/contact.h +++ b/ui/models/contact.h @@ -36,6 +36,7 @@ public: QString getAccountName() const; QString getAccountJid() const; QString getAccountResource() const; + QString getContactName() const; void addMessage(const Shared::Message& data); unsigned int getMessagesCount() const; diff --git a/ui/models/roster.cpp b/ui/models/roster.cpp index beda4c1..d360a4d 100644 --- a/ui/models/roster.cpp +++ b/ui/models/roster.cpp @@ -556,3 +556,13 @@ void Models::Roster::removeAccount(const QString& account) acc->deleteLater(); } + +QString Models::Roster::getContactName(const QString& account, const QString& jid) +{ + std::multimap::const_iterator cItr = contacts.find({account, jid}); + if (cItr == contacts.end()) { + qDebug() << "An attempt to get a name of non existing contact " << account << ":" << jid << ", skipping"; + return ""; + } + return cItr->second->getContactName(); +} diff --git a/ui/models/roster.h b/ui/models/roster.h index 93ba037..b49cb1e 100644 --- a/ui/models/roster.h +++ b/ui/models/roster.h @@ -35,6 +35,7 @@ public: void removePresence(const QString& account, const QString& jid, const QString& name); void addMessage(const QString& account, const Shared::Message& data); void dropMessages(const QString& account, const QString& jid); + QString getContactName(const QString& account, const QString& jid); QVariant data ( const QModelIndex& index, int role ) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; diff --git a/ui/squawk.cpp b/ui/squawk.cpp index 1d45a27..5cc28f6 100644 --- a/ui/squawk.cpp +++ b/ui/squawk.cpp @@ -9,7 +9,8 @@ Squawk::Squawk(QWidget *parent) : accounts(0), rosterModel(), conversations(), - contextMenu(new QMenu()) + contextMenu(new QMenu()), + dbus("org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", QDBusConnection::sessionBus()) { m_ui->setupUi(this); m_ui->roster->setModel(&rosterModel); @@ -227,9 +228,9 @@ void Squawk::onRosterItemDoubleClicked(const QModelIndex& item) connect(conv, SIGNAL(destroyed(QObject*)), this, SLOT(onConversationClosed(QObject*))); connect(conv, SIGNAL(sendMessage(const Shared::Message&)), this, SLOT(onConversationMessage(const Shared::Message&))); connect(conv, SIGNAL(requestArchive(const QString&)), this, SLOT(onConversationRequestArchive(const QString&))); + connect(conv, SIGNAL(shown()), this, SLOT(onConversationShown())); conversations.insert(std::make_pair(id, conv)); - rosterModel.dropMessages(account, jid); conv->show(); @@ -241,6 +242,12 @@ void Squawk::onRosterItemDoubleClicked(const QModelIndex& item) } } +void Squawk::onConversationShown() +{ + Conversation* conv = static_cast(sender()); + rosterModel.dropMessages(conv->getAccount(), conv->getJid()); +} + void Squawk::onConversationClosed(QObject* parent) { Conversation* conv = static_cast(sender()); @@ -257,14 +264,38 @@ 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()) { - itr->second->addMessage(data); - } else { - if (!data.getForwarded()) { + Conversation* conv = itr->second; + conv->addMessage(data); + QApplication::alert(conv); + if (conv->isMinimized()) { rosterModel.addMessage(account, data); + if (!data.getForwarded()) { + notify(account, data); + } + } + } else { + rosterModel.addMessage(account, data); + if (!data.getForwarded()) { + QApplication::alert(this); + notify(account, data); } } } +void Squawk::notify(const QString& account, const Shared::Message& msg) +{ + QVariantList args; + args << QString(QCoreApplication::applicationName()); + args << QVariant(QVariant::UInt); //TODO some normal id + args << QString("mail-message"); //TODO icon + args << QString(rosterModel.getContactName(account, msg.getPenPalJid())); + args << QString(msg.getBody()); + args << QStringList(); + args << QVariantMap(); + args << 3000; + dbus.callWithArgumentList(QDBus::AutoDetect, "Notify", args); +} + void Squawk::onConversationMessage(const Shared::Message& msg) { Conversation* conv = static_cast(sender()); @@ -299,6 +330,7 @@ void Squawk::removeAccount(const QString& account) disconnect(conv, SIGNAL(destroyed(QObject*)), this, SLOT(onConversationClosed(QObject*))); disconnect(conv, SIGNAL(sendMessage(const Shared::Message&)), this, SLOT(onConversationMessage(const Shared::Message&))); disconnect(conv, SIGNAL(requestArchive(const QString&)), this, SLOT(onConversationRequestArchive(const QString&))); + disconnect(conv, SIGNAL(shown()), this, SLOT(onConversationShown())); conv->close(); conversations.erase(lItr); } else { diff --git a/ui/squawk.h b/ui/squawk.h index 081965d..81f3999 100644 --- a/ui/squawk.h +++ b/ui/squawk.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -65,9 +66,11 @@ private: Models::Roster rosterModel; Conversations conversations; QMenu* contextMenu; + QDBusInterface dbus; protected: void closeEvent(QCloseEvent * event) override; + void notify(const QString& account, const Shared::Message& msg); private slots: void onAccounts(); @@ -81,6 +84,7 @@ private slots: void onConversationMessage(const Shared::Message& msg); void onConversationRequestArchive(const QString& before); void onRosterContextMenu(const QPoint& point); + void onConversationShown(); };