diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 1880166..f35f5b9 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -14,6 +14,7 @@ set(squawkCORE_SRC archive.cpp rosteritem.cpp contact.cpp + conference.cpp ) # Tell CMake to create the helloworld executable diff --git a/core/account.cpp b/core/account.cpp index 9e87484..9e8dfec 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -1,6 +1,6 @@ /* * Squawk messenger. - * Copyright (C) 2019 Yury Gubich + * 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 @@ -37,11 +37,11 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& mm(new QXmppMucManager()), bm(new QXmppBookmarkManager()), contacts(), + conferences(), maxReconnectTimes(0), reconnectTimes(0), queuedContacts(), - outOfRosterContacts(), - mucInfo() + outOfRosterContacts() { config.setUser(p_login); config.setDomain(p_server); @@ -87,6 +87,10 @@ Account::~Account() delete itr->second; } + for (std::map::const_iterator itr = conferences.begin(), end = conferences.end(); itr != end; ++itr) { + delete itr->second; + } + delete bm; delete mm; delete am; @@ -288,15 +292,29 @@ void Core::Account::addedAccount(const QString& jid) } } -void Core::Account::handleNewContact(Core::Contact* contact) +void Core::Account::handleNewRosterItem(Core::RosterItem* contact) { - QObject::connect(contact, SIGNAL(groupAdded(const QString&)), this, SLOT(onContactGroupAdded(const QString&))); - QObject::connect(contact, SIGNAL(groupRemoved(const QString&)), this, SLOT(onContactGroupRemoved(const QString&))); - QObject::connect(contact, SIGNAL(nameChanged(const QString&)), this, SLOT(onContactNameChanged(const QString&))); - QObject::connect(contact, SIGNAL(subscriptionStateChanged(Shared::SubscriptionState)), - this, SLOT(onContactSubscriptionStateChanged(Shared::SubscriptionState))); + QObject::connect(contact, SIGNAL(needHistory(const QString&, const QString&, const QDateTime&)), this, SLOT(onContactNeedHistory(const QString&, const QString&, const QDateTime&))); QObject::connect(contact, SIGNAL(historyResponse(const std::list&)), this, SLOT(onContactHistoryResponse(const std::list&))); + QObject::connect(contact, SIGNAL(nameChanged(const QString&)), this, SLOT(onContactNameChanged(const QString&))); +} + +void Core::Account::handleNewContact(Core::Contact* contact) +{ + handleNewRosterItem(contact); + QObject::connect(contact, SIGNAL(groupAdded(const QString&)), this, SLOT(onContactGroupAdded(const QString&))); + QObject::connect(contact, SIGNAL(groupRemoved(const QString&)), this, SLOT(onContactGroupRemoved(const QString&))); + QObject::connect(contact, SIGNAL(subscriptionStateChanged(Shared::SubscriptionState)), + this, SLOT(onContactSubscriptionStateChanged(Shared::SubscriptionState))); +} + +void Core::Account::handleNewConference(Core::Conference* contact) +{ + handleNewRosterItem(contact); + QObject::connect(contact, SIGNAL(nickChanged(const QString&)), this, SLOT(onMucNickNameChanged(const QString&))); + QObject::connect(contact, SIGNAL(joinedChanged(bool)), this, SLOT(onMucJoinedChanged(bool))); + QObject::connect(contact, SIGNAL(autoJoinChanged(bool)), this, SLOT(onMucAutoJoinChanged(bool))); } @@ -548,32 +566,48 @@ void Core::Account::initializeMessage(Shared::Message& target, const QXmppMessag void Core::Account::onMamMessageReceived(const QString& queryId, const QXmppMessage& msg) { - std::map::const_iterator itr = achiveQueries.find(queryId); - QString jid = itr->second; - std::map::const_iterator citr = contacts.find(jid); - - if (citr != contacts.end()) { - Contact* cnt = citr->second; - if (msg.id().size() > 0 && msg.body().size() > 0) { - Shared::Message sMsg(Shared::Message::chat); - initializeMessage(sMsg, msg, false, true, true); - - cnt->addMessageToArchive(sMsg); + if (msg.id().size() > 0 && msg.body().size() > 0) { + std::map::const_iterator itr = achiveQueries.find(queryId); + QString jid = itr->second; + RosterItem* item = 0; + std::map::const_iterator citr = contacts.find(jid); + + if (citr != contacts.end()) { + item = citr->second; + } else { + std::map::const_iterator coitr = conferences.find(jid); + if (coitr != conferences.end()) { + item = coitr->second; + } } - } + Shared::Message sMsg(Shared::Message::chat); + initializeMessage(sMsg, msg, false, true, true); + + item->addMessageToArchive(sMsg); + } + //handleChatMessage(msg, false, true, true); } void Core::Account::requestArchive(const QString& jid, int count, const QString& before) { qDebug() << "An archive request for " << jid << ", before " << before; + RosterItem* contact = 0; std::map::const_iterator itr = contacts.find(jid); - if (itr == contacts.end()) { + if (itr != contacts.end()) { + contact = itr->second; + } else { + std::map::const_iterator citr = conferences.find(jid); + if (citr != conferences.end()) { + contact = citr->second; + } + } + + if (contact == 0) { qDebug() << "An attempt to request archive for" << jid << "in account" << name << ", but the contact with such id wasn't found, skipping"; return; } - RosterItem* contact = itr->second; if (contact->getArchiveState() == RosterItem::empty && before.size() == 0) { QXmppMessage msg(getFullJid(), jid, "", ""); @@ -623,14 +657,22 @@ void Core::Account::onMamResultsReceived(const QString& queryId, const QXmppResu { std::map::const_iterator itr = achiveQueries.find(queryId); QString jid = itr->second; + RosterItem* ri = 0; achiveQueries.erase(itr); std::map::const_iterator citr = contacts.find(jid); if (citr != contacts.end()) { - Contact* cnt = citr->second; - + ri = citr->second; + } else { + std::map::const_iterator coitr = conferences.find(jid); + if (coitr != conferences.end()) { + ri = coitr->second; + } + } + + if (ri != 0) { qDebug() << "Flushing messages for" << jid; - cnt->flushMessagesToArchive(complete, resultSetReply.first(), resultSetReply.last()); + ri->flushMessagesToArchive(complete, resultSetReply.first(), resultSetReply.last()); } } @@ -887,106 +929,51 @@ void Core::Account::onMucRoomAdded(QXmppMucRoom* room) void Core::Account::bookmarksReceived(const QXmppBookmarkSet& bookmarks) { - QList conferences = bookmarks.conferences(); - for (QList::const_iterator itr = conferences.begin(), end = conferences.end(); itr != end; ++itr) { + QList confs = bookmarks.conferences(); + for (QList::const_iterator itr = confs.begin(), end = confs.end(); itr != end; ++itr) { const QXmppBookmarkConference& c = *itr; QString jid = c.jid(); - std::pair::iterator, bool> mi = mucInfo.insert(std::make_pair(jid, MucInfo(c.autoJoin(), false, jid, c.name(), c.nickName()))); - if (mi.second) { - const MucInfo& info = mi.first->second; + std::map::const_iterator cItr = conferences.find(jid); + if (cItr == conferences.end()) { QXmppMucRoom* room = mm->addRoom(jid); + QString nick = c.nickName(); + Conference* conf = new Conference(jid, getName(), c.autoJoin(), c.name(), nick == "" ? getName() : nick, room); - QObject::connect(room, SIGNAL(joined()), this, SLOT(onMucJoined())); - QObject::connect(room, SIGNAL(left()), this, SLOT(onMucLeft())); - QObject::connect(room, SIGNAL(nameChanged(const QString&)), this, SLOT(onMucNameChanged(const QString&))); - QObject::connect(room, SIGNAL(nickNameChanged(const QString&)), this, SLOT(onMucNickNameChanged(const QString&))); - QObject::connect(room, SIGNAL(error(const QXmppStanza::Error&)), this, SLOT(onMucError(const QXmppStanza::Error&))); - QObject::connect(room, SIGNAL(messageReceived(const QXmppMessage&)), this, SLOT(onMucMessage(const QXmppMessage&))); + handleNewConference(conf); emit addRoom(jid, { - {"autoJoin", info.autoJoin}, - {"joined", false}, - {"nick", info.nick}, - {"name", info.name} + {"autoJoin", conf->getAutoJoin()}, + {"joined", conf->getJoined()}, + {"nick", conf->getNick()}, + {"name", conf->getName()} }); - - room->setNickName(info.nick == "" ? getName() : info.nick); - if (info.autoJoin) { - room->join(); - } } else { qDebug() << "Received a bookmark to a MUC " << jid << " which is already booked by another bookmark, skipping"; } } } -void Core::Account::onMucJoined() +void Core::Account::onMucJoinedChanged(bool joined) { - QXmppMucRoom* room = static_cast(sender()); - QString jid = room->jid(); - std::map::iterator itr = mucInfo.find(jid); - if (itr != mucInfo.end()) { - itr->second.joined = true; - emit changeRoom(jid, { - {"joined", true} + Conference* room = static_cast(sender()); + emit changeRoom(room->jid, { + {"joined", joined} }); - } else { - qDebug() << "Seems like account" << getName() << "joined room" << jid << ", but the info about that room wasn't found, skipping"; - } } -void Core::Account::onMucLeft() +void Core::Account::onMucAutoJoinChanged(bool autoJoin) { - QXmppMucRoom* room = static_cast(sender()); - QString jid = room->jid(); - std::map::iterator itr = mucInfo.find(jid); - if (itr != mucInfo.end()) { - itr->second.joined = false; - emit changeRoom(jid, { - {"joined", false} + Conference* room = static_cast(sender()); + emit changeRoom(room->jid, { + {"autoJoin", autoJoin} }); - } else { - qDebug() << "Seems like account" << getName() << "left room" << jid << ", but the info about that room wasn't found, skipping"; - } -} - -void Core::Account::onMucNameChanged(const QString& roomName) -{ - QXmppMucRoom* room = static_cast(sender()); - QString jid = room->jid(); - std::map::iterator itr = mucInfo.find(jid); - if (itr != mucInfo.end()) { - itr->second.name = roomName; - emit changeRoom(jid, { - {"name", roomName} - }); - } else { - qDebug() << "Account" << getName() << "received an event about room" << jid << "name change, but the info about that room wasn't found, skipping"; - } } void Core::Account::onMucNickNameChanged(const QString& nickName) { - QXmppMucRoom* room = static_cast(sender()); - QString jid = room->jid(); - std::map::iterator itr = mucInfo.find(jid); - if (itr != mucInfo.end()) { - itr->second.nick = nickName; - emit changeRoom(jid, { + Conference* room = static_cast(sender()); + emit changeRoom(room->jid, { {"nick", nickName} }); - } else { - qDebug() << "Account" << getName() << "received an event about his nick name change in room" << jid << ", but the info about that room wasn't found, skipping"; - } -} - -void Core::Account::onMucError(const QXmppStanza::Error& error) -{ - qDebug() << "MUC error"; -} - -void Core::Account::onMucMessage(const QXmppMessage& message) -{ - qDebug() << "Muc message"; } diff --git a/core/account.h b/core/account.h index 6798a94..650bf64 100644 --- a/core/account.h +++ b/core/account.h @@ -32,6 +32,7 @@ #include #include "../global.h" #include "contact.h" +#include "conference.h" namespace Core { @@ -39,7 +40,6 @@ namespace Core class Account : public QObject { Q_OBJECT - class MucInfo; public: Account(const QString& p_login, const QString& p_server, const QString& p_password, const QString& p_name, QObject* parent = 0); ~Account(); @@ -102,12 +102,12 @@ private: QXmppMucManager* mm; QXmppBookmarkManager* bm; std::map contacts; + std::map conferences; unsigned int maxReconnectTimes; unsigned int reconnectTimes; std::map queuedContacts; std::set outOfRosterContacts; - std::map mucInfo; private slots: void onClientConnected(); @@ -130,12 +130,9 @@ private slots: void onMamResultsReceived(const QString &queryId, const QXmppResultSetReply &resultSetReply, bool complete); void onMucRoomAdded(QXmppMucRoom* room); - void onMucJoined(); - void onMucLeft(); - void onMucNameChanged(const QString& roomName); + void onMucJoinedChanged(bool joined); + void onMucAutoJoinChanged(bool autoJoin); void onMucNickNameChanged(const QString& nickName); - void onMucError(const QXmppStanza::Error& error); - void onMucMessage(const QXmppMessage& message); void bookmarksReceived(const QXmppBookmarkSet& bookmarks); @@ -151,6 +148,8 @@ private slots: private: void addedAccount(const QString &bareJid); void handleNewContact(Contact* contact); + void handleNewRosterItem(RosterItem* contact); + void handleNewConference(Conference* contact); bool handleChatMessage(const QXmppMessage& msg, bool outgoing = false, bool forwarded = false, bool guessing = false); void addToGroup(const QString& jid, const QString& group); void removeFromGroup(const QString& jid, const QString& group); @@ -158,24 +157,6 @@ private: Shared::SubscriptionState castSubscriptionState(QXmppRosterIq::Item::SubscriptionType qs) const; void logMessage(const QXmppMessage& msg, const QString& reason = "Message wasn't handled: "); - -class MucInfo { -public: - MucInfo(bool p_al, bool p_jo, const QString& p_jid, const QString& p_name, const QString& p_nick): - autoJoin(p_al), - joined(p_jo), - jid(p_jid), - name(p_name), - nick(p_nick), - removed(false) {} - - bool autoJoin; - bool joined; - QString jid; - QString name; - QString nick; - bool removed; -}; }; } diff --git a/core/conference.cpp b/core/conference.cpp new file mode 100644 index 0000000..9daa228 --- /dev/null +++ b/core/conference.cpp @@ -0,0 +1,122 @@ +/* + * Squawk messenger. + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "conference.h" + +#include + +Core::Conference::Conference(const QString& p_jid, const QString& p_account, bool p_autoJoin, const QString& p_name, const QString& p_nick, QXmppMucRoom* p_room): + RosterItem(p_jid, p_account), + nick(p_nick), + room(p_room), + joined(false), + autoJoin(p_autoJoin) +{ + name = p_name; + + connect(room, SIGNAL(joined()), this, SLOT(onRoomJoined())); + connect(room, SIGNAL(left()), this, SLOT(onRoomLeft())); + connect(room, SIGNAL(nameChanged(const QString&)), this, SLOT(onRoomNameChanged(const QString&))); + connect(room, SIGNAL(nickNameChanged(const QString&)), this, SLOT(onRoomNickNameChanged(const QString&))); + connect(room, SIGNAL(error(const QXmppStanza::Error&)), this, SLOT(onRoomError(const QXmppStanza::Error&))); + + room->setNickName(nick); + if (autoJoin) { + room->join(); + } +} + +Core::Conference::~Conference() +{ +} + +QString Core::Conference::getNick() const +{ + return nick; +} + +bool Core::Conference::getAutoJoin() +{ + return autoJoin; +} + +bool Core::Conference::getJoined() const +{ + return joined; +} + +void Core::Conference::setJoined(bool p_joined) +{ + if (joined != p_joined) { + if (joined) { + room->join(); + } else { + room->leave(); + } + } +} + +void Core::Conference::setAutoJoin(bool p_autoJoin) +{ + if (autoJoin != p_autoJoin) { + autoJoin = p_autoJoin; + emit autoJoinChanged(autoJoin); + } +} + +void Core::Conference::setNick(const QString& p_nick) +{ + if (nick != p_nick) { + if (joined) { + room->setNickName(p_nick); + } else { + nick = p_nick; + emit nickChanged(nick); + } + } +} + +void Core::Conference::onRoomJoined() +{ + joined = true; + emit joinedChanged(joined); +} + +void Core::Conference::onRoomLeft() +{ + joined = false; + emit joinedChanged(joined); +} + +void Core::Conference::onRoomNameChanged(const QString& p_name) +{ + setName(p_name); +} + +void Core::Conference::onRoomNickNameChanged(const QString& p_nick) +{ + if (p_nick != nick) { + nick = p_nick; + emit nickChanged(nick); + } +} + +void Core::Conference::onRoomError(const QXmppStanza::Error& err) +{ + qDebug() << "MUC error"; +} diff --git a/core/conference.h b/core/conference.h new file mode 100644 index 0000000..739faa2 --- /dev/null +++ b/core/conference.h @@ -0,0 +1,69 @@ +/* + * Squawk messenger. + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CORE_CONFERENCE_H +#define CORE_CONFERENCE_H + +#include "rosteritem.h" +#include + +namespace Core +{ + +/** + * @todo write docs + */ +class Conference : public RosterItem +{ + Q_OBJECT +public: + Conference(const QString& p_jid, const QString& p_account, bool p_autoJoin, const QString& p_name, const QString& p_nick, QXmppMucRoom* p_room); + ~Conference(); + + QString getNick() const; + void setNick(const QString& p_nick); + + bool getJoined() const; + void setJoined(bool p_joined); + + bool getAutoJoin(); + void setAutoJoin(bool p_autoJoin); + +signals: + void nickChanged(const QString& nick); + void joinedChanged(bool joined); + void autoJoinChanged(bool autoJoin); + +private: + QString nick; + QXmppMucRoom* room; + bool joined; + bool autoJoin; + +private slots: + void onRoomJoined(); + void onRoomLeft(); + void onRoomNameChanged(const QString& p_name); + void onRoomNickNameChanged(const QString& p_nick); + void onRoomError(const QXmppStanza::Error& err); + +}; + +} + +#endif // CORE_CONFERENCE_H diff --git a/core/contact.cpp b/core/contact.cpp index 9b4ea8a..ba0737e 100644 --- a/core/contact.cpp +++ b/core/contact.cpp @@ -21,7 +21,8 @@ Core::Contact::Contact(const QString& pJid, const QString& account, QObject* parent): RosterItem(pJid, account, parent), - groups() + groups(), + subscriptionState(Shared::unknown) { } @@ -54,3 +55,16 @@ void Core::Contact::setGroups(const QSet& set) emit groupAdded(*itr); } } + +Shared::SubscriptionState Core::Contact::getSubscriptionState() const +{ + return subscriptionState; +} + +void Core::Contact::setSubscriptionState(Shared::SubscriptionState state) +{ + if (subscriptionState != state) { + subscriptionState = state; + emit subscriptionStateChanged(subscriptionState); + } +} diff --git a/core/contact.h b/core/contact.h index 9dce71a..d4eb4a1 100644 --- a/core/contact.h +++ b/core/contact.h @@ -35,13 +35,18 @@ public: QSet getGroups() const; void setGroups(const QSet& set); unsigned int groupsCount() const; + + void setSubscriptionState(Shared::SubscriptionState state); + Shared::SubscriptionState getSubscriptionState() const; signals: void groupAdded(const QString& name); void groupRemoved(const QString& name); + void subscriptionStateChanged(Shared::SubscriptionState state); private: QSet groups; + Shared::SubscriptionState subscriptionState; }; } diff --git a/core/rosteritem.cpp b/core/rosteritem.cpp index 6b5851c..1e4d7a0 100644 --- a/core/rosteritem.cpp +++ b/core/rosteritem.cpp @@ -26,7 +26,6 @@ Core::RosterItem::RosterItem(const QString& pJid, const QString& account, QObjec name(), archiveState(empty), archive(new Archive(jid)), - subscriptionState(Shared::unknown), syncronizing(false), requestedCount(0), requestedBefore(), @@ -55,24 +54,11 @@ Core::RosterItem::ArchiveState Core::RosterItem::getArchiveState() const return archiveState; } -Shared::SubscriptionState Core::RosterItem::getSubscriptionState() const -{ - return subscriptionState; -} - QString Core::RosterItem::getName() const { return name; } -void Core::RosterItem::setSubscriptionState(Shared::SubscriptionState state) -{ - if (subscriptionState != state) { - subscriptionState = state; - emit subscriptionStateChanged(subscriptionState); - } -} - void Core::RosterItem::setName(const QString& n) { if (name != n) { diff --git a/core/rosteritem.h b/core/rosteritem.h index ae38e3f..3e15b9c 100644 --- a/core/rosteritem.h +++ b/core/rosteritem.h @@ -50,8 +50,6 @@ public: ArchiveState getArchiveState() const; QString getName() const; void setName(const QString& n); - void setSubscriptionState(Shared::SubscriptionState state); - Shared::SubscriptionState getSubscriptionState() const; void addMessageToArchive(const Shared::Message& msg); void appendMessageToArchive(const Shared::Message& msg); @@ -72,7 +70,6 @@ protected: QString name; ArchiveState archiveState; Archive* archive; - Shared::SubscriptionState subscriptionState; bool syncronizing; int requestedCount; diff --git a/ui/models/roster.cpp b/ui/models/roster.cpp index 7ce8690..6309920 100644 --- a/ui/models/roster.cpp +++ b/ui/models/roster.cpp @@ -461,6 +461,13 @@ void Models::Roster::changeContact(const QString& account, const QString& jid, c cBeg->second->update(itr.key(), itr.value());; } } + + std::map::iterator rItr = rooms.find(id); + if (rItr != rooms.end()) { + for (QMap::const_iterator itr = data.begin(), end = data.end(); itr != end; ++itr) { + rItr->second->update(itr.key(), itr.value());; + } + } } void Models::Roster::removeContact(const QString& account, const QString& jid)