From 87426ee20f2e15c24c6a6c0f1a798452d5dac806 Mon Sep 17 00:00:00 2001 From: blue Date: Mon, 15 Jun 2020 00:23:43 +0300 Subject: [PATCH] account refactoring --- core/CMakeLists.txt | 1 + core/account.cpp | 709 +++------------------------ core/account.h | 51 +- core/handlers/messagehandler.cpp | 29 +- core/handlers/messagehandler.h | 2 +- core/handlers/rosterhandler.cpp | 583 ++++++++++++++++++++++ core/handlers/rosterhandler.h | 115 +++++ external/simpleCrypt/simplecrypt.cpp | 8 +- external/simpleCrypt/simplecrypt.h | 1 + 9 files changed, 797 insertions(+), 702 deletions(-) create mode 100644 core/handlers/rosterhandler.cpp create mode 100644 core/handlers/rosterhandler.h diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 64319c2..b74a055 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -19,6 +19,7 @@ set(squawkCORE_SRC networkaccess.cpp adapterFuctions.cpp handlers/messagehandler.cpp + handlers/rosterhandler.cpp ) add_subdirectory(passwordStorageEngines) diff --git a/core/account.cpp b/core/account.cpp index 2d70876..59a05fd 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -30,7 +30,6 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& config(), presence(), state(Shared::ConnectionState::disconnected), - groups(), cm(new QXmppCarbonManager()), am(new QXmppMamManager()), mm(new QXmppMucManager()), @@ -40,20 +39,15 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& um(new QXmppUploadRequestManager()), dm(client.findExtension()), rcpm(new QXmppMessageReceiptManager()), - contacts(), - conferences(), reconnectScheduled(false), reconnectTimer(new QTimer), - queuedContacts(), - outOfRosterContacts(), - pendingMessages(), - uploadingSlotsQueue(), avatarHash(), avatarType(), ownVCardRequestInProgress(false), network(p_net), passwordType(Shared::AccountPassword::plain), - mh(new MessageHandler(this)) + mh(new MessageHandler(this)), + rh(new RosterHandler(this)) { config.setUser(p_login); config.setDomain(p_server); @@ -66,12 +60,6 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& QObject::connect(&client, &QXmppClient::messageReceived, mh, &MessageHandler::onMessageReceived); QObject::connect(&client, &QXmppClient::error, this, &Account::onClientError); - QObject::connect(rm, &QXmppRosterManager::rosterReceived, this, &Account::onRosterReceived); - QObject::connect(rm, &QXmppRosterManager::itemAdded, this, &Account::onRosterItemAdded); - QObject::connect(rm, &QXmppRosterManager::itemRemoved, this, &Account::onRosterItemRemoved); - QObject::connect(rm, &QXmppRosterManager::itemChanged, this, &Account::onRosterItemChanged); - //QObject::connect(&rm, &QXmppRosterManager::presenceChanged, this, &Account::onRosterPresenceChanged); - client.addExtension(cm); QObject::connect(cm, &QXmppCarbonManager::messageReceived, mh, &MessageHandler::onCarbonMessageReceived); @@ -84,10 +72,7 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& QObject::connect(am, &QXmppMamManager::resultsRecieved, this, &Account::onMamResultsReceived); client.addExtension(mm); - QObject::connect(mm, &QXmppMucManager::roomAdded, this, &Account::onMucRoomAdded); - client.addExtension(bm); - QObject::connect(bm, &QXmppBookmarkManager::bookmarksReceived, this, &Account::bookmarksReceived); QObject::connect(vm, &QXmppVCardManager::vCardReceived, this, &Account::onVCardReceived); //QObject::connect(&vm, &QXmppVCardManager::clientVCardReceived, this, &Account::onOwnVCardReceived); //for some reason it doesn't work, launching from common handler @@ -173,13 +158,8 @@ Account::~Account() QObject::disconnect(network, &NetworkAccess::uploadFileComplete, mh, &MessageHandler::onFileUploaded); QObject::disconnect(network, &NetworkAccess::uploadFileError, mh, &MessageHandler::onFileUploadError); - for (std::map::const_iterator itr = contacts.begin(), end = contacts.end(); itr != end; ++itr) { - delete itr->second; - } - - for (std::map::const_iterator itr = conferences.begin(), end = conferences.end(); itr != end; ++itr) { - delete itr->second; - } + delete mh; + delete rh; delete reconnectTimer; delete rcpm; @@ -213,7 +193,7 @@ void Core::Account::disconnect() reconnectTimer->stop(); } if (state != Shared::ConnectionState::disconnected) { - clearConferences(); + rh->clearConferences(); client.disconnectFromServer(); } } @@ -271,176 +251,58 @@ void Core::Account::reconnect() } } -QString Core::Account::getName() const -{ - return name; -} +QString Core::Account::getName() const { + return name;} -QString Core::Account::getLogin() const -{ - return config.user(); -} +QString Core::Account::getLogin() const { + return config.user();} -QString Core::Account::getPassword() const -{ - return config.password(); -} +QString Core::Account::getPassword() const { + return config.password();} -QString Core::Account::getServer() const -{ - return config.domain(); -} +QString Core::Account::getServer() const { + return config.domain();} -Shared::AccountPassword Core::Account::getPasswordType() const -{ - return passwordType; -} +Shared::AccountPassword Core::Account::getPasswordType() const { + return passwordType;} -void Core::Account::onRosterReceived() -{ - vm->requestClientVCard(); //TODO need to make sure server actually supports vCards - ownVCardRequestInProgress = true; - - QStringList bj = rm->getRosterBareJids(); - for (int i = 0; i < bj.size(); ++i) { - const QString& jid = bj[i]; - addedAccount(jid); - } -} +void Core::Account::setPasswordType(Shared::AccountPassword pt) { + passwordType = pt; } -void Core::Account::onRosterItemAdded(const QString& bareJid) -{ - addedAccount(bareJid); - std::map::const_iterator itr = queuedContacts.find(bareJid); - if (itr != queuedContacts.end()) { - rm->subscribe(bareJid, itr->second); - queuedContacts.erase(itr); - } -} +void Core::Account::setLogin(const QString& p_login) { + config.setUser(p_login);} -void Core::Account::setPasswordType(Shared::AccountPassword pt) -{ - passwordType = pt; -} +void Core::Account::setName(const QString& p_name) { + name = p_name;} -void Core::Account::onRosterItemChanged(const QString& bareJid) -{ - std::map::const_iterator itr = contacts.find(bareJid); - if (itr == contacts.end()) { - qDebug() << "An attempt to change non existing contact" << bareJid << "from account" << name << ", skipping"; - return; - } - Contact* contact = itr->second; - QXmppRosterIq::Item re = rm->getRosterEntry(bareJid); - - Shared::SubscriptionState state = castSubscriptionState(re.subscriptionType()); +void Core::Account::setPassword(const QString& p_password) { + config.setPassword(p_password);} - contact->setGroups(re.groups()); - contact->setSubscriptionState(state); - contact->setName(re.name()); -} +void Core::Account::setServer(const QString& p_server) { + config.setDomain(p_server);} -void Core::Account::onRosterItemRemoved(const QString& bareJid) +Shared::Availability Core::Account::getAvailability() const { - std::map::const_iterator itr = contacts.find(bareJid); - if (itr == contacts.end()) { - qDebug() << "An attempt to remove non existing contact" << bareJid << "from account" << name << ", skipping"; - return; - } - Contact* contact = itr->second; - contacts.erase(itr); - QSet cGroups = contact->getGroups(); - for (QSet::const_iterator itr = cGroups.begin(), end = cGroups.end(); itr != end; ++itr) { - removeFromGroup(bareJid, *itr); - } - emit removeContact(bareJid); - - contact->deleteLater(); -} - -void Core::Account::addedAccount(const QString& jid) -{ - std::map::const_iterator itr = contacts.find(jid); - QXmppRosterIq::Item re = rm->getRosterEntry(jid); - Contact* contact; - bool newContact = false; - if (itr == contacts.end()) { - newContact = true; - contact = new Contact(jid, name); - contacts.insert(std::make_pair(jid, contact)); - + if (state == Shared::ConnectionState::connected) { + QXmppPresence::AvailableStatusType pres = presence.availableStatusType(); + return static_cast(pres); //they are compatible; } else { - contact = itr->second; - } - - QSet gr = re.groups(); - Shared::SubscriptionState state = castSubscriptionState(re.subscriptionType()); - contact->setGroups(gr); - contact->setSubscriptionState(state); - contact->setName(re.name()); - - if (newContact) { - QMap cData({ - {"name", re.name()}, - {"state", QVariant::fromValue(state)} - }); - - Archive::AvatarInfo info; - bool hasAvatar = contact->readAvatarInfo(info); - if (hasAvatar) { - if (info.autogenerated) { - cData.insert("avatarState", static_cast(Shared::Avatar::valid)); - } else { - cData.insert("avatarState", static_cast(Shared::Avatar::autocreated)); - } - cData.insert("avatarPath", contact->avatarPath() + "." + info.type); - } else { - cData.insert("avatarState", static_cast(Shared::Avatar::empty)); - cData.insert("avatarPath", ""); - requestVCard(jid); - } - int grCount = 0; - for (QSet::const_iterator itr = gr.begin(), end = gr.end(); itr != end; ++itr) { - const QString& groupName = *itr; - addToGroup(jid, groupName); - emit addContact(jid, groupName, cData); - grCount++; - } - - if (grCount == 0) { - emit addContact(jid, "", cData); - } - handleNewContact(contact); + return Shared::Availability::offline; } } -void Core::Account::handleNewRosterItem(Core::RosterItem* contact) +void Core::Account::setAvailability(Shared::Availability avail) { - QObject::connect(contact, &RosterItem::needHistory, this, &Account::onContactNeedHistory); - QObject::connect(contact, &RosterItem::historyResponse, this, &Account::onContactHistoryResponse); - QObject::connect(contact, &RosterItem::nameChanged, this, &Account::onContactNameChanged); - QObject::connect(contact, &RosterItem::avatarChanged, this, &Account::onContactAvatarChanged); - QObject::connect(contact, &RosterItem::requestVCard, this, &Account::requestVCard); -} - -void Core::Account::handleNewContact(Core::Contact* contact) -{ - handleNewRosterItem(contact); - QObject::connect(contact, &Contact::groupAdded, this, &Account::onContactGroupAdded); - QObject::connect(contact, &Contact::groupRemoved, this, &Account::onContactGroupRemoved); - QObject::connect(contact, &Contact::subscriptionStateChanged, this, &Account::onContactSubscriptionStateChanged); -} - -void Core::Account::handleNewConference(Core::Conference* contact) -{ - handleNewRosterItem(contact); - QObject::connect(contact, &Conference::nickChanged, this, &Account::onMucNickNameChanged); - QObject::connect(contact, &Conference::subjectChanged, this, &Account::onMucSubjectChanged); - QObject::connect(contact, &Conference::joinedChanged, this, &Account::onMucJoinedChanged); - QObject::connect(contact, &Conference::autoJoinChanged, this, &Account::onMucAutoJoinChanged); - QObject::connect(contact, &Conference::addParticipant, this, &Account::onMucAddParticipant); - QObject::connect(contact, &Conference::changeParticipant, this, &Account::onMucChangeParticipant); - QObject::connect(contact, &Conference::removeParticipant, this, &Account::onMucRemoveParticipant); + if (avail == Shared::Availability::offline) { + disconnect(); //TODO not sure how to do here - changing state may cause connection or disconnection + } else { + QXmppPresence::AvailableStatusType pres = static_cast(avail); + + presence.setAvailableStatusType(pres); + if (state != Shared::ConnectionState::disconnected) { + client.setClientPresence(presence); + } + } } void Core::Account::onPresenceReceived(const QXmppPresence& p_presence) @@ -478,11 +340,9 @@ void Core::Account::onPresenceReceived(const QXmppPresence& p_presence) } } } else { - if (pendingVCardRequests.find(jid) == pendingVCardRequests.end()) { - std::map::const_iterator itr = contacts.find(jid); - if (itr != contacts.end()) { - itr->second->handlePresence(p_presence); - } + RosterItem* item = rh->getRosterItem(jid); + if (item != 0) { + item->handlePresence(p_presence); } } @@ -501,7 +361,7 @@ void Core::Account::onPresenceReceived(const QXmppPresence& p_presence) {"status", p_presence.statusText()} }); } - break; + break; case QXmppPresence::Unavailable: emit removePresence(jid, resource); break; @@ -519,81 +379,20 @@ void Core::Account::onPresenceReceived(const QXmppPresence& p_presence) } } -void Core::Account::onRosterPresenceChanged(const QString& bareJid, const QString& resource) -{ - //not used for now; - qDebug() << "presence changed for " << bareJid << " resource " << resource; - const QXmppPresence& presence = rm->getPresence(bareJid, resource); -} +QString Core::Account::getResource() const { + return config.resource();} -void Core::Account::setLogin(const QString& p_login) -{ - config.setUser(p_login); -} +void Core::Account::setResource(const QString& p_resource) { + config.setResource(p_resource);} -void Core::Account::setName(const QString& p_name) -{ - name = p_name; -} +QString Core::Account::getFullJid() const { + return getLogin() + "@" + getServer() + "/" + getResource();} -void Core::Account::setPassword(const QString& p_password) -{ - config.setPassword(p_password); -} +void Core::Account::sendMessage(const Shared::Message& data) { + mh->sendMessage(data);} -void Core::Account::setServer(const QString& p_server) -{ - config.setDomain(p_server); -} - -Shared::Availability Core::Account::getAvailability() const -{ - if (state == Shared::ConnectionState::connected) { - QXmppPresence::AvailableStatusType pres = presence.availableStatusType(); - return static_cast(pres); //they are compatible; - } else { - return Shared::Availability::offline; - } -} - -void Core::Account::setAvailability(Shared::Availability avail) -{ - if (avail == Shared::Availability::offline) { - disconnect(); //TODO not sure how to do here - changing state may cause connection or disconnection - } else { - QXmppPresence::AvailableStatusType pres = static_cast(avail); - - presence.setAvailableStatusType(pres); - if (state != Shared::ConnectionState::disconnected) { - client.setClientPresence(presence); - } - } -} - -QString Core::Account::getResource() const -{ - return config.resource(); -} - -void Core::Account::setResource(const QString& p_resource) -{ - config.setResource(p_resource); -} - -QString Core::Account::getFullJid() const -{ - return getLogin() + "@" + getServer() + "/" + getResource(); -} - -void Core::Account::sendMessage(const Shared::Message& data) -{ - mh->sendMessage(data); -} - -void Core::Account::sendMessage(const Shared::Message& data, const QString& path) -{ - mh->sendMessage(data, path); -} +void Core::Account::sendMessage(const Shared::Message& data, const QString& path) { + mh->sendMessage(data, path);} void Core::Account::onMamMessageReceived(const QString& queryId, const QXmppMessage& msg) { @@ -601,7 +400,7 @@ void Core::Account::onMamMessageReceived(const QString& queryId, const QXmppMess std::map::const_iterator itr = achiveQueries.find(queryId); if (itr != achiveQueries.end()) { QString jid = itr->second; - RosterItem* item = getRosterItem(jid); + RosterItem* item = rh->getRosterItem(jid); Shared::Message sMsg(static_cast(msg.type())); mh->initializeMessage(sMsg, msg, false, true, true); @@ -614,31 +413,13 @@ void Core::Account::onMamMessageReceived(const QString& queryId, const QXmppMess item->addMessageToArchive(sMsg); } } - } - - //handleChatMessage(msg, false, true, true); -} - -Core::RosterItem * Core::Account::getRosterItem(const QString& jid) -{ - 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; - } } - - return item; } void Core::Account::requestArchive(const QString& jid, int count, const QString& before) { qDebug() << "An archive request for " << jid << ", before " << before; - RosterItem* contact = getRosterItem(jid); + RosterItem* contact = rh->getRosterItem(jid); if (contact == 0) { qDebug() << "An attempt to request archive for" << jid << "in account" << name << ", but the contact with such id wasn't found, skipping"; @@ -687,12 +468,10 @@ void Core::Account::onContactNeedHistory(const QString& before, const QString& a with = contact->jid; } - QString q = am->retrieveArchivedMessages(to, "", with, start, QDateTime(), query); achiveQueries.insert(std::make_pair(q, contact->jid)); } - void Core::Account::onMamResultsReceived(const QString& queryId, const QXmppResultSetReply& resultSetReply, bool complete) { std::map::const_iterator itr = achiveQueries.find(queryId); @@ -700,7 +479,7 @@ void Core::Account::onMamResultsReceived(const QString& queryId, const QXmppResu QString jid = itr->second; achiveQueries.erase(itr); - RosterItem* ri = getRosterItem(jid); + RosterItem* ri = rh->getRosterItem(jid); if (ri != 0) { qDebug() << "Flushing messages for" << jid << ", complete:" << complete; @@ -715,98 +494,6 @@ void Core::Account::onMamLog(QXmppLogger::MessageType type, const QString& msg) qDebug() << msg; } -void Core::Account::onContactGroupAdded(const QString& group) -{ - Contact* contact = static_cast(sender()); - if (contact->groupsCount() == 1) { - // not sure i need to handle it here, the situation with grouped and ungrouped contacts handled on the client anyway - } - - QMap cData({ - {"name", contact->getName()}, - {"state", QVariant::fromValue(contact->getSubscriptionState())} - }); - addToGroup(contact->jid, group); - emit addContact(contact->jid, group, cData); -} - -void Core::Account::onContactGroupRemoved(const QString& group) -{ - Contact* contact = static_cast(sender()); - if (contact->groupsCount() == 0) { - // not sure i need to handle it here, the situation with grouped and ungrouped contacts handled on the client anyway - } - - emit removeContact(contact->jid, group); - removeFromGroup(contact->jid, group); -} - -void Core::Account::onContactNameChanged(const QString& cname) -{ - Contact* contact = static_cast(sender()); - QMap cData({ - {"name", cname}, - }); - emit changeContact(contact->jid, cData); -} - -void Core::Account::onContactSubscriptionStateChanged(Shared::SubscriptionState cstate) -{ - Contact* contact = static_cast(sender()); - QMap cData({ - {"state", QVariant::fromValue(cstate)}, - }); - emit changeContact(contact->jid, cData); -} - -void Core::Account::addToGroup(const QString& jid, const QString& group) -{ - std::map>::iterator gItr = groups.find(group); - if (gItr == groups.end()) { - gItr = groups.insert(std::make_pair(group, std::set())).first; - emit addGroup(group); - } - gItr->second.insert(jid); -} - -void Core::Account::removeFromGroup(const QString& jid, const QString& group) -{ - QSet toRemove; - std::map>::iterator itr = groups.find(group); - if (itr == groups.end()) { - qDebug() << "An attempt to remove contact" << jid << "of account" << name << "from non existing group" << group << ", skipping"; - return; - } - std::set contacts = itr->second; - std::set::const_iterator cItr = contacts.find(jid); - if (cItr != contacts.end()) { - contacts.erase(cItr); - if (contacts.size() == 0) { - emit removeGroup(group); - groups.erase(group); - } - } -} - -Shared::SubscriptionState Core::Account::castSubscriptionState(QXmppRosterIq::Item::SubscriptionType qs) const -{ - Shared::SubscriptionState state; - if (qs == QXmppRosterIq::Item::NotSet) { - state = Shared::SubscriptionState::unknown; - } else { - state = static_cast(qs); - } - return state; -} - -void Core::Account::onContactHistoryResponse(const std::list& list) -{ - RosterItem* contact = static_cast(sender()); - - qDebug() << "Collected history for contact " << contact->jid << list.size() << "elements"; - emit responseArchive(contact->jid, list); -} - void Core::Account::onClientError(QXmppClient::Error err) { qDebug() << "Error"; @@ -909,7 +596,6 @@ void Core::Account::onClientError(QXmppClient::Error err) emit error(errorText); } - void Core::Account::subscribeToContact(const QString& jid, const QString& reason) { if (state == Shared::ConnectionState::connected) { @@ -928,269 +614,50 @@ void Core::Account::unsubscribeFromContact(const QString& jid, const QString& re } } -void Core::Account::removeContactRequest(const QString& jid) -{ - if (state == Shared::ConnectionState::connected) { - std::set::const_iterator itr = outOfRosterContacts.find(jid); - if (itr != outOfRosterContacts.end()) { - outOfRosterContacts.erase(itr); - onRosterItemRemoved(jid); - } else { - rm->removeItem(jid); - } - } else { - qDebug() << "An attempt to remove contact " << jid << " from account " << name << " but the account is not in the connected state, skipping"; - } -} +void Core::Account::removeContactRequest(const QString& jid) { + rh->removeContactRequest(jid);} - -void Core::Account::addContactRequest(const QString& jid, const QString& name, const QSet& groups) -{ - if (state == Shared::ConnectionState::connected) { - 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; - 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"; - } -} - -void Core::Account::onMucRoomAdded(QXmppMucRoom* room) -{ - qDebug() << "room" << room->jid() << "added with name" << room->name() << ", account" << getName() << "joined:" << room->isJoined(); -} - -void Core::Account::bookmarksReceived(const QXmppBookmarkSet& bookmarks) -{ - 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::map::const_iterator cItr = conferences.find(jid); - if (cItr == conferences.end()) { - addNewRoom(jid, c.nickName(), c.name(), c.autoJoin()); - } else { - qDebug() << "Received a bookmark to a MUC " << jid << " which is already booked by another bookmark, skipping"; - } - } -} - -void Core::Account::onMucJoinedChanged(bool joined) -{ - Conference* room = static_cast(sender()); - emit changeRoom(room->jid, { - {"joined", joined} - }); -} - -void Core::Account::onMucAutoJoinChanged(bool autoJoin) -{ - storeConferences(); - Conference* room = static_cast(sender()); - emit changeRoom(room->jid, { - {"autoJoin", autoJoin} - }); -} - -void Core::Account::onMucNickNameChanged(const QString& nickName) -{ - storeConferences(); - Conference* room = static_cast(sender()); - emit changeRoom(room->jid, { - {"nick", nickName} - }); -} +void Core::Account::addContactRequest(const QString& jid, const QString& name, const QSet& groups) { + rh->addContactRequest(jid, name, groups);} void Core::Account::setRoomAutoJoin(const QString& jid, bool joined) { - std::map::const_iterator cItr = conferences.find(jid); - if (cItr == conferences.end()) { + Conference* conf = rh->getConference(jid); + if (conf == 0) { qDebug() << "An attempt to set auto join to the non existing room" << jid << "of the account" << getName() << ", skipping"; return; } - cItr->second->setAutoJoin(joined); + conf->setAutoJoin(joined); } void Core::Account::setRoomJoined(const QString& jid, bool joined) { - std::map::const_iterator cItr = conferences.find(jid); - if (cItr == conferences.end()) { + Conference* conf = rh->getConference(jid); + if (conf == 0) { qDebug() << "An attempt to set joined to the non existing room" << jid << "of the account" << getName() << ", skipping"; return; } - cItr->second->setJoined(joined); + conf->setJoined(joined); } -void Core::Account::onMucAddParticipant(const QString& nickName, const QMap& data) -{ - Conference* room = static_cast(sender()); - emit addRoomParticipant(room->jid, nickName, data); -} +void Core::Account::removeRoomRequest(const QString& jid){ + rh->removeRoomRequest(jid);} -void Core::Account::onMucChangeParticipant(const QString& nickName, const QMap& data) -{ - Conference* room = static_cast(sender()); - emit changeRoomParticipant(room->jid, nickName, data); -} +void Core::Account::addRoomRequest(const QString& jid, const QString& nick, const QString& password, bool autoJoin) { + rh->addRoomRequest(jid, nick, password, autoJoin);} -void Core::Account::onMucRemoveParticipant(const QString& nickName) -{ - Conference* room = static_cast(sender()); - emit removeRoomParticipant(room->jid, nickName); -} +void Core::Account::addContactToGroupRequest(const QString& jid, const QString& groupName) { + rh->addContactToGroupRequest(jid, groupName);} -void Core::Account::onMucSubjectChanged(const QString& subject) -{ - Conference* room = static_cast(sender()); - emit changeRoom(room->jid, { - {"subject", subject} - }); -} - -void Core::Account::storeConferences() -{ - QXmppBookmarkSet bms = bm->bookmarks(); - QList confs; - for (std::map::const_iterator itr = conferences.begin(), end = conferences.end(); itr != end; ++itr) { - Conference* conference = itr->second; - QXmppBookmarkConference conf; - conf.setJid(conference->jid); - conf.setName(conference->getName()); - conf.setNickName(conference->getNick()); - conf.setAutoJoin(conference->getAutoJoin()); - confs.push_back(conf); - } - bms.setConferences(confs); - bm->setBookmarks(bms); -} - -void Core::Account::clearConferences() -{ - for (std::map::const_iterator itr = conferences.begin(), end = conferences.end(); itr != end; itr++) { - itr->second->deleteLater(); - emit removeRoom(itr->first); - } - conferences.clear(); -} - -void Core::Account::removeRoomRequest(const QString& jid) -{ - std::map::const_iterator itr = conferences.find(jid); - if (itr == conferences.end()) { - qDebug() << "An attempt to remove non existing room" << jid << "from account" << name << ", skipping"; - } - itr->second->deleteLater(); - conferences.erase(itr); - emit removeRoom(jid); - storeConferences(); -} - -void Core::Account::addRoomRequest(const QString& jid, const QString& nick, const QString& password, bool autoJoin) -{ - std::map::const_iterator cItr = conferences.find(jid); - if (cItr == conferences.end()) { - addNewRoom(jid, nick, "", autoJoin); - storeConferences(); - } else { - qDebug() << "An attempt to add a MUC " << jid << " which is already present in the rester, skipping"; - } -} - -void Core::Account::addNewRoom(const QString& jid, const QString& nick, const QString& roomName, bool autoJoin) -{ - QXmppMucRoom* room = mm->addRoom(jid); - QString lNick = nick; - if (lNick.size() == 0) { - lNick = getName(); - } - Conference* conf = new Conference(jid, getName(), autoJoin, roomName, lNick, room); - conferences.insert(std::make_pair(jid, conf)); - - handleNewConference(conf); - - QMap cData = { - {"autoJoin", conf->getAutoJoin()}, - {"joined", conf->getJoined()}, - {"nick", conf->getNick()}, - {"name", conf->getName()}, - {"avatars", conf->getAllAvatars()} - }; - - - Archive::AvatarInfo info; - bool hasAvatar = conf->readAvatarInfo(info); - if (hasAvatar) { - if (info.autogenerated) { - cData.insert("avatarState", QVariant::fromValue(Shared::Avatar::autocreated)); - } else { - cData.insert("avatarState", QVariant::fromValue(Shared::Avatar::valid)); - } - cData.insert("avatarPath", conf->avatarPath() + "." + info.type); - } else { - cData.insert("avatarState", QVariant::fromValue(Shared::Avatar::empty)); - cData.insert("avatarPath", ""); - requestVCard(jid); - } - - emit addRoom(jid, cData); -} - -void Core::Account::addContactToGroupRequest(const QString& jid, const QString& groupName) -{ - std::map::const_iterator itr = contacts.find(jid); - if (itr == contacts.end()) { - qDebug() << "An attempt to add non existing contact" << jid << "of account" << name << "to the group" << groupName << ", skipping"; - } else { - QXmppRosterIq::Item item = rm->getRosterEntry(jid); - QSet groups = item.groups(); - if (groups.find(groupName) == groups.end()) { //TODO need to change it, I guess that sort of code is better in qxmpp lib - groups.insert(groupName); - item.setGroups(groups); - - QXmppRosterIq iq; - iq.setType(QXmppIq::Set); - iq.addItem(item); - client.sendPacket(iq); - } else { - qDebug() << "An attempt to add contact" << jid << "of account" << name << "to the group" << groupName << "but it's already in that group, skipping"; - } - } -} - -void Core::Account::removeContactFromGroupRequest(const QString& jid, const QString& groupName) -{ - std::map::const_iterator itr = contacts.find(jid); - if (itr == contacts.end()) { - qDebug() << "An attempt to remove non existing contact" << jid << "of account" << name << "from the group" << groupName << ", skipping"; - } else { - QXmppRosterIq::Item item = rm->getRosterEntry(jid); - QSet groups = item.groups(); - QSet::const_iterator gItr = groups.find(groupName); - if (gItr != groups.end()) { - groups.erase(gItr); - item.setGroups(groups); - - QXmppRosterIq iq; - iq.setType(QXmppIq::Set); - iq.addItem(item); - client.sendPacket(iq); - } else { - qDebug() << "An attempt to remove contact" << jid << "of account" << name << "from the group" << groupName << "but it's not in that group, skipping"; - } - } -} +void Core::Account::removeContactFromGroupRequest(const QString& jid, const QString& groupName) { + rh->removeContactFromGroupRequest(jid, groupName);} void Core::Account::renameContactRequest(const QString& jid, const QString& newName) { - std::map::const_iterator itr = contacts.find(jid); - if (itr == contacts.end()) { + Contact* cnt = rh->getContact(jid); + if (cnt == 0) { qDebug() << "An attempt to rename non existing contact" << jid << "of account" << name << ", skipping"; } else { rm->renameItem(jid, newName); @@ -1207,7 +674,7 @@ void Core::Account::onVCardReceived(const QXmppVCardIq& card) resource = comps.back(); } pendingVCardRequests.erase(id); - RosterItem* item = getRosterItem(jid); + RosterItem* item = rh->getRosterItem(jid); if (item == 0) { if (jid == getLogin() + "@" + getServer()) { @@ -1327,17 +794,6 @@ QString Core::Account::getAvatarPath() const } } -void Core::Account::onContactAvatarChanged(Shared::Avatar type, const QString& path) -{ - RosterItem* item = static_cast(sender()); - QMap cData({ - {"avatarState", static_cast(type)}, - {"avatarPath", path} - }); - - emit changeContact(item->jid, cData); -} - void Core::Account::requestVCard(const QString& jid) { if (pendingVCardRequests.find(jid) == pendingVCardRequests.end()) { @@ -1426,12 +882,7 @@ void Core::Account::onDiscoveryInfoReceived(const QXmppDiscoveryIq& info) void Core::Account::cancelHistoryRequests() { - for (const std::pair& pair : conferences) { - pair.second->clearArchiveRequests(); - } - for (const std::pair& pair : contacts) { - pair.second->clearArchiveRequests(); - } + rh->cancelHistoryRequests(); achiveQueries.clear(); } diff --git a/core/account.h b/core/account.h index d31d066..9af4d7b 100644 --- a/core/account.h +++ b/core/account.h @@ -49,6 +49,7 @@ #include "networkaccess.h" #include "handlers/messagehandler.h" +#include "handlers/rosterhandler.h" namespace Core { @@ -57,6 +58,7 @@ class Account : public QObject { Q_OBJECT friend class MessageHandler; + friend class RosterHandler; public: Account( const QString& p_login, @@ -141,7 +143,6 @@ private: QXmppConfiguration config; QXmppPresence presence; Shared::ConnectionState state; - std::map> groups; QXmppCarbonManager* cm; QXmppMamManager* am; QXmppMucManager* mm; @@ -151,16 +152,10 @@ private: QXmppUploadRequestManager* um; QXmppDiscoveryManager* dm; QXmppMessageReceiptManager* rcpm; - std::map contacts; - std::map conferences; bool reconnectScheduled; QTimer* reconnectTimer; - std::map queuedContacts; - std::set outOfRosterContacts; std::set pendingVCardRequests; - std::map pendingMessages; - std::deque> uploadingSlotsQueue; QString avatarHash; QString avatarType; @@ -169,41 +164,18 @@ private: Shared::AccountPassword passwordType; MessageHandler* mh; + RosterHandler* rh; private slots: void onClientStateChange(QXmppClient::State state); void onClientError(QXmppClient::Error err); - void onRosterReceived(); - void onRosterItemAdded(const QString& bareJid); - void onRosterItemChanged(const QString& bareJid); - void onRosterItemRemoved(const QString& bareJid); - void onRosterPresenceChanged(const QString& bareJid, const QString& resource); - void onPresenceReceived(const QXmppPresence& presence); - + void onContactNeedHistory(const QString& before, const QString& after, const QDateTime& at); + void onMamMessageReceived(const QString& bareJid, const QXmppMessage& message); void onMamResultsReceived(const QString &queryId, const QXmppResultSetReply &resultSetReply, bool complete); - - void onMucRoomAdded(QXmppMucRoom* room); - void onMucJoinedChanged(bool joined); - void onMucAutoJoinChanged(bool autoJoin); - void onMucNickNameChanged(const QString& nickName); - void onMucSubjectChanged(const QString& subject); - void onMucAddParticipant(const QString& nickName, const QMap& data); - void onMucChangeParticipant(const QString& nickName, const QMap& data); - void onMucRemoveParticipant(const QString& nickName); - - void bookmarksReceived(const QXmppBookmarkSet& bookmarks); - - void onContactGroupAdded(const QString& group); - void onContactGroupRemoved(const QString& group); - void onContactNameChanged(const QString& name); - void onContactSubscriptionStateChanged(Shared::SubscriptionState state); - void onContactHistoryResponse(const std::list& list); - void onContactNeedHistory(const QString& before, const QString& after, const QDateTime& at); - void onContactAvatarChanged(Shared::Avatar, const QString& path); - + void onMamLog(QXmppLogger::MessageType type, const QString &msg); void onVCardReceived(const QXmppVCardIq& card); @@ -213,18 +185,7 @@ private slots: void onDiscoveryInfoReceived (const QXmppDiscoveryIq& info); private: - void addedAccount(const QString &bareJid); - void handleNewContact(Contact* contact); - void handleNewRosterItem(RosterItem* contact); - void handleNewConference(Conference* contact); - void addNewRoom(const QString& jid, const QString& nick, const QString& roomName, bool autoJoin); - void addToGroup(const QString& jid, const QString& group); - void removeFromGroup(const QString& jid, const QString& group); - Shared::SubscriptionState castSubscriptionState(QXmppRosterIq::Item::SubscriptionType qs) const; - void storeConferences(); - void clearConferences(); void cancelHistoryRequests(); - RosterItem* getRosterItem(const QString& jid); }; void initializeVCard(Shared::VCard& vCard, const QXmppVCardIq& card); diff --git a/core/handlers/messagehandler.cpp b/core/handlers/messagehandler.cpp index ae06694..0f0e09d 100644 --- a/core/handlers/messagehandler.cpp +++ b/core/handlers/messagehandler.cpp @@ -46,7 +46,7 @@ void Core::MessageHandler::onMessageReceived(const QXmppMessage& msg) std::map::const_iterator itr = pendingStateMessages.find(id); if (itr != pendingStateMessages.end()) { QString jid = itr->second; - RosterItem* cnt = acc->getRosterItem(jid); + RosterItem* cnt = acc->rh->getRosterItem(jid); QMap cData = { {"state", static_cast(Shared::Message::State::error)}, {"errorText", msg.error().text()} @@ -79,19 +79,9 @@ bool Core::MessageHandler::handleChatMessage(const QXmppMessage& msg, bool outgo Shared::Message sMsg(Shared::Message::chat); initializeMessage(sMsg, msg, outgoing, forwarded, guessing); QString jid = sMsg.getPenPalJid(); - std::map::const_iterator itr = acc->contacts.find(jid); - Contact* cnt; - if (itr != acc->contacts.end()) { - cnt = itr->second; - } else { - cnt = new Contact(jid, acc->name); - acc->contacts.insert(std::make_pair(jid, cnt)); - acc->outOfRosterContacts.insert(jid); - cnt->setSubscriptionState(Shared::SubscriptionState::unknown); - emit acc->addContact(jid, "", QMap({ - {"state", QVariant::fromValue(Shared::SubscriptionState::unknown)} - })); - acc->handleNewContact(cnt); + Contact* cnt = acc->rh->getContact(jid); + if (cnt == 0) { + cnt = acc->rh->addOutOfRosterContact(jid); } if (outgoing) { if (forwarded) { @@ -127,11 +117,8 @@ bool Core::MessageHandler::handleGroupMessage(const QXmppMessage& msg, bool outg Shared::Message sMsg(Shared::Message::groupChat); initializeMessage(sMsg, msg, outgoing, forwarded, guessing); QString jid = sMsg.getPenPalJid(); - std::map::const_iterator itr = acc->conferences.find(jid); - Conference* cnt; - if (itr != acc->conferences.end()) { - cnt = itr->second; - } else { + Conference* cnt = acc->rh->getConference(jid); + if (cnt == 0) { return false; } @@ -236,7 +223,7 @@ void Core::MessageHandler::onReceiptReceived(const QString& jid, const QString& std::map::const_iterator itr = pendingStateMessages.find(id); if (itr != pendingStateMessages.end()) { QMap cData = {{"state", static_cast(Shared::Message::State::delivered)}}; - RosterItem* ri = acc->getRosterItem(itr->second); + RosterItem* ri = acc->rh->getRosterItem(itr->second); if (ri != 0) { ri->changeMessage(id, cData); } @@ -249,7 +236,7 @@ void Core::MessageHandler::sendMessage(Shared::Message data) { QString jid = data.getPenPalJid(); QString id = data.getId(); - RosterItem* ri = acc->getRosterItem(jid); + RosterItem* ri = acc->rh->getRosterItem(jid); if (acc->state == Shared::ConnectionState::connected) { QXmppMessage msg(acc->getFullJid(), data.getTo(), data.getBody(), data.getThread()); diff --git a/core/handlers/messagehandler.h b/core/handlers/messagehandler.h index 54b8331..be1545f 100644 --- a/core/handlers/messagehandler.h +++ b/core/handlers/messagehandler.h @@ -27,7 +27,7 @@ #include #include -#include "shared/message.h" +#include namespace Core { diff --git a/core/handlers/rosterhandler.cpp b/core/handlers/rosterhandler.cpp new file mode 100644 index 0000000..ea1812d --- /dev/null +++ b/core/handlers/rosterhandler.cpp @@ -0,0 +1,583 @@ +/* + * 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 "rosterhandler.h" +#include "core/account.h" + +Core::RosterHandler::RosterHandler(Core::Account* account): + QObject(), + acc(account), + contacts(), + conferences(), + groups(), + queuedContacts(), + outOfRosterContacts() +{ + connect(acc->rm, &QXmppRosterManager::rosterReceived, this, &RosterHandler::onRosterReceived); + connect(acc->rm, &QXmppRosterManager::itemAdded, this, &RosterHandler::onRosterItemAdded); + connect(acc->rm, &QXmppRosterManager::itemRemoved, this, &RosterHandler::onRosterItemRemoved); + connect(acc->rm, &QXmppRosterManager::itemChanged, this, &RosterHandler::onRosterItemChanged); + + + connect(acc->mm, &QXmppMucManager::roomAdded, this, &RosterHandler::onMucRoomAdded); + connect(acc->bm, &QXmppBookmarkManager::bookmarksReceived, this, &RosterHandler::bookmarksReceived); +} + +Core::RosterHandler::~RosterHandler() +{ + for (std::map::const_iterator itr = contacts.begin(), end = contacts.end(); itr != end; ++itr) { + delete itr->second; + } + + for (std::map::const_iterator itr = conferences.begin(), end = conferences.end(); itr != end; ++itr) { + delete itr->second; + } +} + +void Core::RosterHandler::onRosterReceived() +{ + acc->vm->requestClientVCard(); //TODO need to make sure server actually supports vCards + acc->ownVCardRequestInProgress = true; + + QStringList bj = acc->rm->getRosterBareJids(); + for (int i = 0; i < bj.size(); ++i) { + const QString& jid = bj[i]; + addedAccount(jid); + } +} + +void Core::RosterHandler::onRosterItemAdded(const QString& bareJid) +{ + addedAccount(bareJid); + std::map::const_iterator itr = queuedContacts.find(bareJid); + if (itr != queuedContacts.end()) { + acc->rm->subscribe(bareJid, itr->second); + queuedContacts.erase(itr); + } +} + +void Core::RosterHandler::addedAccount(const QString& jid) +{ + std::map::const_iterator itr = contacts.find(jid); + QXmppRosterIq::Item re = acc->rm->getRosterEntry(jid); + Contact* contact; + bool newContact = false; + if (itr == contacts.end()) { + newContact = true; + contact = new Contact(jid, acc->name); + contacts.insert(std::make_pair(jid, contact)); + + } else { + contact = itr->second; + } + + QSet gr = re.groups(); + Shared::SubscriptionState state = castSubscriptionState(re.subscriptionType()); + contact->setGroups(gr); + contact->setSubscriptionState(state); + contact->setName(re.name()); + + if (newContact) { + QMap cData({ + {"name", re.name()}, + {"state", QVariant::fromValue(state)} + }); + + careAboutAvatar(contact, cData); + int grCount = 0; + for (QSet::const_iterator itr = gr.begin(), end = gr.end(); itr != end; ++itr) { + const QString& groupName = *itr; + addToGroup(jid, groupName); + emit acc->addContact(jid, groupName, cData); + grCount++; + } + + if (grCount == 0) { + emit acc->addContact(jid, "", cData); + } + handleNewContact(contact); + } +} + +void Core::RosterHandler::addNewRoom(const QString& jid, const QString& nick, const QString& roomName, bool autoJoin) +{ + QXmppMucRoom* room = acc->mm->addRoom(jid); + QString lNick = nick; + if (lNick.size() == 0) { + lNick = acc->getName(); + } + Conference* conf = new Conference(jid, acc->getName(), autoJoin, roomName, lNick, room); + conferences.insert(std::make_pair(jid, conf)); + + handleNewConference(conf); + + QMap cData = { + {"autoJoin", conf->getAutoJoin()}, + {"joined", conf->getJoined()}, + {"nick", conf->getNick()}, + {"name", conf->getName()}, + {"avatars", conf->getAllAvatars()} + }; + careAboutAvatar(conf, cData); + emit acc->addRoom(jid, cData); +} + +void Core::RosterHandler::careAboutAvatar(Core::RosterItem* item, QMap& data) +{ + Archive::AvatarInfo info; + bool hasAvatar = item->readAvatarInfo(info); + if (hasAvatar) { + if (info.autogenerated) { + data.insert("avatarState", QVariant::fromValue(Shared::Avatar::autocreated)); + } else { + data.insert("avatarState", QVariant::fromValue(Shared::Avatar::valid)); + } + data.insert("avatarPath", item->avatarPath() + "." + info.type); + } else { + data.insert("avatarState", QVariant::fromValue(Shared::Avatar::empty)); + data.insert("avatarPath", ""); + acc->requestVCard(item->jid); + } +} + +void Core::RosterHandler::addContactRequest(const QString& jid, const QString& name, const QSet& groups) +{ + if (acc->state == Shared::ConnectionState::connected) { + std::map::const_iterator itr = queuedContacts.find(jid); + if (itr != queuedContacts.end()) { + qDebug() << "An attempt to add contact " << jid << " to account " << acc->name << " but the account is already queued for adding, skipping"; + } else { + queuedContacts.insert(std::make_pair(jid, "")); //TODO need to add reason here; + acc->rm->addItem(jid, name, groups); + } + } else { + qDebug() << "An attempt to add contact " << jid << " to account " << acc->name << " but the account is not in the connected state, skipping"; + } +} + +void Core::RosterHandler::removeContactRequest(const QString& jid) +{ + if (acc->state == Shared::ConnectionState::connected) { + std::set::const_iterator itr = outOfRosterContacts.find(jid); + if (itr != outOfRosterContacts.end()) { + outOfRosterContacts.erase(itr); + onRosterItemRemoved(jid); + } else { + acc->rm->removeItem(jid); + } + } else { + qDebug() << "An attempt to remove contact " << jid << " from account " << acc->name << " but the account is not in the connected state, skipping"; + } +} + +void Core::RosterHandler::handleNewRosterItem(Core::RosterItem* contact) +{ + connect(contact, &RosterItem::needHistory, this->acc, &Account::onContactNeedHistory); + connect(contact, &RosterItem::historyResponse, this, &RosterHandler::onContactHistoryResponse); + connect(contact, &RosterItem::nameChanged, this, &RosterHandler::onContactNameChanged); + connect(contact, &RosterItem::avatarChanged, this, &RosterHandler::onContactAvatarChanged); + connect(contact, &RosterItem::requestVCard, this->acc, &Account::requestVCard); +} + +void Core::RosterHandler::handleNewContact(Core::Contact* contact) +{ + handleNewRosterItem(contact); + connect(contact, &Contact::groupAdded, this, &RosterHandler::onContactGroupAdded); + connect(contact, &Contact::groupRemoved, this, &RosterHandler::onContactGroupRemoved); + connect(contact, &Contact::subscriptionStateChanged, this, &RosterHandler::onContactSubscriptionStateChanged); +} + +void Core::RosterHandler::handleNewConference(Core::Conference* contact) +{ + handleNewRosterItem(contact); + connect(contact, &Conference::nickChanged, this, &RosterHandler::onMucNickNameChanged); + connect(contact, &Conference::subjectChanged, this, &RosterHandler::onMucSubjectChanged); + connect(contact, &Conference::joinedChanged, this, &RosterHandler::onMucJoinedChanged); + connect(contact, &Conference::autoJoinChanged, this, &RosterHandler::onMucAutoJoinChanged); + connect(contact, &Conference::addParticipant, this, &RosterHandler::onMucAddParticipant); + connect(contact, &Conference::changeParticipant, this, &RosterHandler::onMucChangeParticipant); + connect(contact, &Conference::removeParticipant, this, &RosterHandler::onMucRemoveParticipant); +} + +void Core::RosterHandler::onMucAddParticipant(const QString& nickName, const QMap& data) +{ + Conference* room = static_cast(sender()); + emit acc->addRoomParticipant(room->jid, nickName, data); +} + +void Core::RosterHandler::onMucChangeParticipant(const QString& nickName, const QMap& data) +{ + Conference* room = static_cast(sender()); + emit acc->changeRoomParticipant(room->jid, nickName, data); +} + +void Core::RosterHandler::onMucRemoveParticipant(const QString& nickName) +{ + Conference* room = static_cast(sender()); + emit acc->removeRoomParticipant(room->jid, nickName); +} + +void Core::RosterHandler::onMucSubjectChanged(const QString& subject) +{ + Conference* room = static_cast(sender()); + emit acc->changeRoom(room->jid, { + {"subject", subject} + }); +} + +void Core::RosterHandler::onContactGroupAdded(const QString& group) +{ + Contact* contact = static_cast(sender()); + if (contact->groupsCount() == 1) { + // not sure i need to handle it here, the situation with grouped and ungrouped contacts handled on the client anyway + } + + QMap cData({ + {"name", contact->getName()}, + {"state", QVariant::fromValue(contact->getSubscriptionState())} + }); + addToGroup(contact->jid, group); + emit acc->addContact(contact->jid, group, cData); +} + +void Core::RosterHandler::onContactGroupRemoved(const QString& group) +{ + Contact* contact = static_cast(sender()); + if (contact->groupsCount() == 0) { + // not sure i need to handle it here, the situation with grouped and ungrouped contacts handled on the client anyway + } + + emit acc->removeContact(contact->jid, group); + removeFromGroup(contact->jid, group); +} + +void Core::RosterHandler::onContactNameChanged(const QString& cname) +{ + Contact* contact = static_cast(sender()); + QMap cData({ + {"name", cname}, + }); + emit acc->changeContact(contact->jid, cData); +} + +void Core::RosterHandler::onContactSubscriptionStateChanged(Shared::SubscriptionState cstate) +{ + Contact* contact = static_cast(sender()); + QMap cData({ + {"state", QVariant::fromValue(cstate)}, + }); + emit acc->changeContact(contact->jid, cData); +} + +void Core::RosterHandler::addToGroup(const QString& jid, const QString& group) +{ + std::map>::iterator gItr = groups.find(group); + if (gItr == groups.end()) { + gItr = groups.insert(std::make_pair(group, std::set())).first; + emit acc->addGroup(group); + } + gItr->second.insert(jid); +} + +void Core::RosterHandler::removeFromGroup(const QString& jid, const QString& group) +{ + QSet toRemove; + std::map>::iterator itr = groups.find(group); + if (itr == groups.end()) { + qDebug() << "An attempt to remove contact" << jid << "of account" << acc->name << "from non existing group" << group << ", skipping"; + return; + } + std::set contacts = itr->second; + std::set::const_iterator cItr = contacts.find(jid); + if (cItr != contacts.end()) { + contacts.erase(cItr); + if (contacts.size() == 0) { + emit acc->removeGroup(group); + groups.erase(group); + } + } +} + +void Core::RosterHandler::onContactHistoryResponse(const std::list& list) +{ + RosterItem* contact = static_cast(sender()); + + qDebug() << "Collected history for contact " << contact->jid << list.size() << "elements"; + emit acc->responseArchive(contact->jid, list); +} + +Core::RosterItem * Core::RosterHandler::getRosterItem(const QString& jid) +{ + 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; + } + } + return item; +} + +Core::Conference * Core::RosterHandler::getConference(const QString& jid) +{ + Conference* item = 0; + std::map::const_iterator coitr = conferences.find(jid); + if (coitr != conferences.end()) { + item = coitr->second; + } + return item; +} + +Core::Contact * Core::RosterHandler::getContact(const QString& jid) +{ + Contact* item = 0; + std::map::const_iterator citr = contacts.find(jid); + if (citr != contacts.end()) { + item = citr->second; + } + return item; +} + +Core::Contact * Core::RosterHandler::addOutOfRosterContact(const QString& jid) +{ + Contact* cnt = new Contact(jid, acc->name); + contacts.insert(std::make_pair(jid, cnt)); + outOfRosterContacts.insert(jid); + cnt->setSubscriptionState(Shared::SubscriptionState::unknown); + emit acc->addContact(jid, "", QMap({ + {"state", QVariant::fromValue(Shared::SubscriptionState::unknown)} + })); + handleNewContact(cnt); + return cnt; +} + +void Core::RosterHandler::onRosterItemChanged(const QString& bareJid) +{ + std::map::const_iterator itr = contacts.find(bareJid); + if (itr == contacts.end()) { + qDebug() << "An attempt to change non existing contact" << bareJid << "from account" << acc->name << ", skipping"; + return; + } + Contact* contact = itr->second; + QXmppRosterIq::Item re = acc->rm->getRosterEntry(bareJid); + + Shared::SubscriptionState state = castSubscriptionState(re.subscriptionType()); + + contact->setGroups(re.groups()); + contact->setSubscriptionState(state); + contact->setName(re.name()); +} + +void Core::RosterHandler::onRosterItemRemoved(const QString& bareJid) +{ + std::map::const_iterator itr = contacts.find(bareJid); + if (itr == contacts.end()) { + qDebug() << "An attempt to remove non existing contact" << bareJid << "from account" << acc->name << ", skipping"; + return; + } + Contact* contact = itr->second; + contacts.erase(itr); + QSet cGroups = contact->getGroups(); + for (QSet::const_iterator itr = cGroups.begin(), end = cGroups.end(); itr != end; ++itr) { + removeFromGroup(bareJid, *itr); + } + emit acc->removeContact(bareJid); + + contact->deleteLater(); +} + +void Core::RosterHandler::onMucRoomAdded(QXmppMucRoom* room) +{ + qDebug() << "room" << room->jid() << "added with name" << room->name() + << ", account" << acc->getName() << "joined:" << room->isJoined(); +} + +void Core::RosterHandler::bookmarksReceived(const QXmppBookmarkSet& bookmarks) +{ + 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::map::const_iterator cItr = conferences.find(jid); + if (cItr == conferences.end()) { + addNewRoom(jid, c.nickName(), c.name(), c.autoJoin()); + } else { + qDebug() << "Received a bookmark to a MUC " << jid << " which is already booked by another bookmark, skipping"; + } + } +} + +void Core::RosterHandler::onMucJoinedChanged(bool joined) +{ + Conference* room = static_cast(sender()); + emit acc->changeRoom(room->jid, { + {"joined", joined} + }); +} + +void Core::RosterHandler::onMucAutoJoinChanged(bool autoJoin) +{ + storeConferences(); + Conference* room = static_cast(sender()); + emit acc->changeRoom(room->jid, { + {"autoJoin", autoJoin} + }); +} + +void Core::RosterHandler::onMucNickNameChanged(const QString& nickName) +{ + storeConferences(); + Conference* room = static_cast(sender()); + emit acc->changeRoom(room->jid, { + {"nick", nickName} + }); +} + +Shared::SubscriptionState Core::RosterHandler::castSubscriptionState(QXmppRosterIq::Item::SubscriptionType qs) +{ + Shared::SubscriptionState state; + if (qs == QXmppRosterIq::Item::NotSet) { + state = Shared::SubscriptionState::unknown; + } else { + state = static_cast(qs); + } + return state; +} + +void Core::RosterHandler::storeConferences() +{ + QXmppBookmarkSet bms = acc->bm->bookmarks(); + QList confs; + for (std::map::const_iterator itr = conferences.begin(), end = conferences.end(); itr != end; ++itr) { + Conference* conference = itr->second; + QXmppBookmarkConference conf; + conf.setJid(conference->jid); + conf.setName(conference->getName()); + conf.setNickName(conference->getNick()); + conf.setAutoJoin(conference->getAutoJoin()); + confs.push_back(conf); + } + bms.setConferences(confs); + acc->bm->setBookmarks(bms); +} + +void Core::RosterHandler::clearConferences() +{ + for (std::map::const_iterator itr = conferences.begin(), end = conferences.end(); itr != end; itr++) { + itr->second->deleteLater(); + emit acc->removeRoom(itr->first); + } + conferences.clear(); +} + +void Core::RosterHandler::removeRoomRequest(const QString& jid) +{ + std::map::const_iterator itr = conferences.find(jid); + if (itr == conferences.end()) { + qDebug() << "An attempt to remove non existing room" << jid << "from account" << acc->name << ", skipping"; + } + itr->second->deleteLater(); + conferences.erase(itr); + emit acc->removeRoom(jid); + storeConferences(); +} + +void Core::RosterHandler::addRoomRequest(const QString& jid, const QString& nick, const QString& password, bool autoJoin) +{ + std::map::const_iterator cItr = conferences.find(jid); + if (cItr == conferences.end()) { + addNewRoom(jid, nick, "", autoJoin); + storeConferences(); + } else { + qDebug() << "An attempt to add a MUC " << jid << " which is already present in the rester, skipping"; + } +} + +void Core::RosterHandler::addContactToGroupRequest(const QString& jid, const QString& groupName) +{ + std::map::const_iterator itr = contacts.find(jid); + if (itr == contacts.end()) { + qDebug() << "An attempt to add non existing contact" << jid << "of account" + << acc->name << "to the group" << groupName << ", skipping"; + } else { + QXmppRosterIq::Item item = acc->rm->getRosterEntry(jid); + QSet groups = item.groups(); + if (groups.find(groupName) == groups.end()) { //TODO need to change it, I guess that sort of code is better in qxmpp lib + groups.insert(groupName); + item.setGroups(groups); + + QXmppRosterIq iq; + iq.setType(QXmppIq::Set); + iq.addItem(item); + acc->client.sendPacket(iq); + } else { + qDebug() << "An attempt to add contact" << jid << "of account" + << acc->name << "to the group" << groupName << "but it's already in that group, skipping"; + } + } +} + +void Core::RosterHandler::removeContactFromGroupRequest(const QString& jid, const QString& groupName) +{ + std::map::const_iterator itr = contacts.find(jid); + if (itr == contacts.end()) { + qDebug() << "An attempt to remove non existing contact" << jid << "of account" + << acc->name << "from the group" << groupName << ", skipping"; + } else { + QXmppRosterIq::Item item = acc->rm->getRosterEntry(jid); + QSet groups = item.groups(); + QSet::const_iterator gItr = groups.find(groupName); + if (gItr != groups.end()) { + groups.erase(gItr); + item.setGroups(groups); + + QXmppRosterIq iq; + iq.setType(QXmppIq::Set); + iq.addItem(item); + acc->client.sendPacket(iq); + } else { + qDebug() << "An attempt to remove contact" << jid << "of account" + << acc->name << "from the group" << groupName << "but it's not in that group, skipping"; + } + } +} + +void Core::RosterHandler::onContactAvatarChanged(Shared::Avatar type, const QString& path) +{ + RosterItem* item = static_cast(sender()); + QMap cData({ + {"avatarState", static_cast(type)}, + {"avatarPath", path} + }); + + emit acc->changeContact(item->jid, cData); +} + +void Core::RosterHandler::cancelHistoryRequests() +{ + for (const std::pair& pair : conferences) { + pair.second->clearArchiveRequests(); + } + for (const std::pair& pair : contacts) { + pair.second->clearArchiveRequests(); + } +} diff --git a/core/handlers/rosterhandler.h b/core/handlers/rosterhandler.h new file mode 100644 index 0000000..c8eeafa --- /dev/null +++ b/core/handlers/rosterhandler.h @@ -0,0 +1,115 @@ +/* + * 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_ROSTERHANDLER_H +#define CORE_ROSTERHANDLER_H + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace Core { + + +class Account; + +class RosterHandler : public QObject +{ + Q_OBJECT +public: + RosterHandler(Account* account); + ~RosterHandler(); + + void addContactRequest(const QString& jid, const QString& name, const QSet& groups); + void removeContactRequest(const QString& jid); + void addContactToGroupRequest(const QString& jid, const QString& groupName); + void removeContactFromGroupRequest(const QString& jid, const QString& groupName); + + void removeRoomRequest(const QString& jid); + void addRoomRequest(const QString& jid, const QString& nick, const QString& password, bool autoJoin); + void cancelHistoryRequests(); + + Core::Contact* getContact(const QString& jid); + Core::Conference* getConference(const QString& jid); + Core::RosterItem* getRosterItem(const QString& jid); + Core::Contact* addOutOfRosterContact(const QString& jid); + + void storeConferences(); + void clearConferences(); + +private slots: + void onRosterReceived(); + void onRosterItemAdded(const QString& bareJid); + void onRosterItemChanged(const QString& bareJid); + void onRosterItemRemoved(const QString& bareJid); + + void onMucRoomAdded(QXmppMucRoom* room); + void onMucJoinedChanged(bool joined); + void onMucAutoJoinChanged(bool autoJoin); + void onMucNickNameChanged(const QString& nickName); + void onMucSubjectChanged(const QString& subject); + void onMucAddParticipant(const QString& nickName, const QMap& data); + void onMucChangeParticipant(const QString& nickName, const QMap& data); + void onMucRemoveParticipant(const QString& nickName); + + void bookmarksReceived(const QXmppBookmarkSet& bookmarks); + + void onContactGroupAdded(const QString& group); + void onContactGroupRemoved(const QString& group); + void onContactNameChanged(const QString& name); + void onContactSubscriptionStateChanged(Shared::SubscriptionState state); + void onContactHistoryResponse(const std::list& list); + void onContactAvatarChanged(Shared::Avatar, const QString& path); + +private: + void addNewRoom(const QString& jid, const QString& nick, const QString& roomName, bool autoJoin); + void addToGroup(const QString& jid, const QString& group); + void removeFromGroup(const QString& jid, const QString& group); + void addedAccount(const QString &bareJid); + void handleNewRosterItem(Core::RosterItem* contact); + void handleNewContact(Core::Contact* contact); + void handleNewConference(Core::Conference* contact); + void careAboutAvatar(Core::RosterItem* item, QMap& data); + + static Shared::SubscriptionState castSubscriptionState(QXmppRosterIq::Item::SubscriptionType qs); + +private: + Account* acc; + std::map contacts; + std::map conferences; + std::map> groups; + std::map queuedContacts; + std::set outOfRosterContacts; +}; + +} + +#endif // CORE_ROSTERHANDLER_H diff --git a/external/simpleCrypt/simplecrypt.cpp b/external/simpleCrypt/simplecrypt.cpp index 9bbec90..19a96be 100644 --- a/external/simpleCrypt/simplecrypt.cpp +++ b/external/simpleCrypt/simplecrypt.cpp @@ -36,10 +36,7 @@ SimpleCrypt::SimpleCrypt(): m_key(0), m_compressionMode(CompressionAuto), m_protectionMode(ProtectionChecksum), -m_lastError(ErrorNoError) -{ - qsrand(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF)); -} +m_lastError(ErrorNoError) {} SimpleCrypt::SimpleCrypt(quint64 key): m_key(key), @@ -47,7 +44,6 @@ m_compressionMode(CompressionAuto), m_protectionMode(ProtectionChecksum), m_lastError(ErrorNoError) { - qsrand(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF)); splitKey(); } @@ -113,7 +109,7 @@ QByteArray SimpleCrypt::encryptToByteArray(QByteArray plaintext) } //prepend a random char to the string - char randomChar = char(qrand() & 0xFF); + char randomChar = char(QRandomGenerator::global()->generate() & 0xFF); ba = randomChar + integrityProtection + ba; int pos(0); diff --git a/external/simpleCrypt/simplecrypt.h b/external/simpleCrypt/simplecrypt.h index 2a5906a..d75bdc2 100644 --- a/external/simpleCrypt/simplecrypt.h +++ b/external/simpleCrypt/simplecrypt.h @@ -30,6 +30,7 @@ #include #include #include +#include /** @ short Simple encrypt*ion and decryption of strings and byte arrays