Commit e2892d03 authored by Linus Jahn's avatar Linus Jahn
Browse files

Rewrite RosterController -> RosterManager, RosterUpdater using gloox

parent ca4cb7fa
......@@ -5,8 +5,9 @@ set(KAIDAN_SOURCES
${CURDIR}/main.cpp
${CURDIR}/Kaidan.cpp
${CURDIR}/Database.cpp
${CURDIR}/RosterController.cpp
${CURDIR}/RosterModel.cpp
${CURDIR}/RosterManager.cpp
${CURDIR}/RosterUpdater.cpp
${CURDIR}/MessageHandler.cpp
${CURDIR}/MessageSessionHandler.cpp
${CURDIR}/MessageModel.cpp
......
......@@ -35,8 +35,10 @@
#include <Swiften/Client/MemoryStorages.h>
#include <Swiften/Crypto/PlatformCryptoProvider.h>
#include <Swiften/Queries/Responders/SoftwareVersionResponder.h>
// gloox
#include <gloox/rostermanager.h>
// Kaidan
#include "RosterController.h"
#include "RosterModel.h"
#include "PresenceController.h"
#include "MessageSessionHandler.h"
#include "MessageModel.h"
......@@ -57,7 +59,6 @@ Kaidan::Kaidan(Swift::NetworkFactories *networkFactories, QObject *parent) :
// setup components
storages = new Swift::MemoryStorages(Swift::PlatformCryptoProvider::create());
messageModel = new MessageModel(database->getDatabase());
rosterController = new RosterController(database->getDatabase());
presenceController = new PresenceController();
vCardController = new VCardController();
serviceDiscoveryManager = new ServiceDiscoveryManager();
......@@ -94,7 +95,7 @@ Kaidan::~Kaidan()
}
delete messageSessionHandler;
delete rosterController;
delete rosterManager;
delete presenceController;
delete vCardController;
delete settings;
......@@ -110,9 +111,15 @@ void Kaidan::mainConnect()
// set the JID resource
client_->setResource(jidResource.toStdString());
// Message receiving/sending
messageSessionHandler = new MessageSessionHandler(client_, messageModel);
client_->registerMessageSessionHandler((gloox::MessageSessionHandler*) messageSessionHandler);
// Roster
rosterManager = new RosterManager(rosterModel, client_);
//client_->connect();
client = new Swift::Client(jid.toStdString(), password.toStdString(), netFactories, storages);
......@@ -133,7 +140,6 @@ void Kaidan::mainConnect()
softwareVersionResponder->start();
// set client in message, roster and presence controller
rosterController->setClient(client);
presenceController->setClient(client);
vCardController->setClient(client);
serviceDiscoveryManager->setClient(client);
......@@ -143,8 +149,6 @@ void Kaidan::mainConnect()
// .. and connect!
client->connect(options);
client_->connect();
}
// we don't want to close client without disconnection
......@@ -221,17 +225,34 @@ void Kaidan::setChatPartner(QString chatPartner)
// set the new chat partner
this->chatPartner = chatPartner;
// update message controller
// filter message for this chat partner
messageModel->applyRecipientFilter(&chatPartner, &jid);
rosterController->setChatPartner(&chatPartner);
rosterManager->setChatPartner(&chatPartner);
emit chatPartnerChanged();
}
void Kaidan::sendMessage(QString jid, QString message)
{
messageSessionHandler->getMessageHandler()->sendMessage(&(this->jid), &jid, &message);
rosterController->handleNewMessageSent(&jid, &message);
if (connected) {
messageSessionHandler->getMessageHandler()->sendMessage(&(this->jid), &jid, &message);
rosterManager->handleMessageSent(&jid, &message);
}
}
void Kaidan::addContact(QString jid, QString nick)
{
if (connected) {
rosterManager->addContact(jid, nick);
}
}
void Kaidan::removeContact(QString jid)
{
if (connected) {
rosterManager->removeContact(jid);
}
}
QString Kaidan::getResourcePath(QString name_)
......@@ -256,9 +277,9 @@ QString Kaidan::getResourcePath(QString name_)
return QString("");
}
RosterController* Kaidan::getRosterController()
RosterModel* Kaidan::getRosterModel()
{
return rosterController;
return rosterModel;
}
MessageModel* Kaidan::getMessageModel()
......
......@@ -34,7 +34,7 @@
#include <gloox/client.h>
// Kaidan
#include "Database.h"
#include "RosterController.h"
#include "RosterManager.h"
#include "MessageSessionHandler.h"
#include "PresenceController.h"
#include "VCardController.h"
......@@ -44,7 +44,7 @@ class Kaidan : public QObject
{
Q_OBJECT
Q_PROPERTY(RosterController* rosterController READ getRosterController NOTIFY rosterControllerChanged)
Q_PROPERTY(RosterModel* rosterModel READ getRosterModel NOTIFY rosterModelChanged)
Q_PROPERTY(MessageModel* messageModel READ getMessageModel NOTIFY messageModelChanged)
Q_PROPERTY(VCardController* vCardController READ getVCardController NOTIFY vCardControllerChanged)
Q_PROPERTY(bool connectionState READ getConnectionState NOTIFY connectionStateConnected NOTIFY connectionStateDisconnected)
......@@ -71,16 +71,18 @@ public:
QString getChatPartner();
void setChatPartner(QString);
RosterController* getRosterController();
RosterModel* getRosterModel();
MessageModel* getMessageModel();
VCardController* getVCardController();
Q_INVOKABLE void sendMessage(QString jid, QString message);
Q_INVOKABLE void addContact(QString jid, QString nick);
Q_INVOKABLE void removeContact(QString jid);
Q_INVOKABLE QString getResourcePath(QString);
Q_INVOKABLE QString getVersionString();
signals:
void rosterControllerChanged();
void rosterModelChanged();
void messageModelChanged();
void vCardControllerChanged();
void connectionStateConnected();
......@@ -104,7 +106,8 @@ private:
Swift::MemoryStorages *storages;
Database *database;
RosterController *rosterController;
RosterModel *rosterModel;
RosterManager *rosterManager;
MessageModel *messageModel;
MessageSessionHandler *messageSessionHandler;
PresenceController *presenceController;
......
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2017 LNJ <git@lnj.li>
* Copyright (C) 2016 geobra <s.g.b@gmx.de>
*
* Kaidan 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.
*
* Kaidan 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 Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
// RosterController
#include "RosterController.h"
// Std
#include <iostream>
#include <string.h>
// Qt 5
#include <QDateTime>
#include <QDebug>
// Kaidan
#include "RosterModel.h"
// Swiften
#include <Swiften/Base/IDGenerator.h>
#include <Swiften/Client/Client.h>
#include <Swiften/Elements/ErrorPayload.h>
#include <Swiften/JID/JID.h>
#include <Swiften/Roster/GetRosterRequest.h>
#include <Swiften/Roster/XMPPRoster.h>
#include <Swiften/Queries/IQRouter.h>
// Boost
#include <boost/bind.hpp>
#include <boost/optional.hpp>
RosterController::RosterController(QSqlDatabase* database, QObject *parent) :
QObject(parent)
{
rosterModel = new RosterModel(database);
chatPartner = QString("");
}
RosterController::~RosterController()
{
delete rosterModel;
}
void RosterController::setClient(Swift::Client *client_)
{
client = client_;
iqRouter = client->getIQRouter();
client->onConnected.connect(
boost::bind(&RosterController::requestRosterFromClient, this));
client->onMessageReceived.connect(
boost::bind(&RosterController::handleMessageReceived, this, _1));
xmppRoster = client->getRoster();
xmppRoster->onInitialRosterPopulated.connect(
boost::bind(&RosterController::handleInitialRosterPopulated, this));
}
RosterModel* RosterController::getRosterModel()
{
return rosterModel;
}
void RosterController::setChatPartner(QString *chatPartner)
{
this->chatPartner = *chatPartner;
// reset the unread message counter for this contact
resetUnreadMessagesForJid(chatPartner);
}
void RosterController::requestRosterFromClient()
{
client->requestRoster();
Swift::GetRosterRequest::ref rosterRequest = Swift::GetRosterRequest::create(client->getIQRouter());
rosterRequest->onResponse.connect(bind(&RosterController::handleRosterReceived, this, _2));
rosterRequest->send();
}
void RosterController::handleRosterReceived(Swift::ErrorPayload::ref error_)
{
if (error_) {
std::cerr << "RosterController: Error receiving roster. Continuing anyway.\n";
} else {
// create a vector containing all roster items
std::vector<Swift::XMPPRosterItem> rosterItems = xmppRoster->getItems();
// create an iterator for it
std::vector<Swift::XMPPRosterItem>::iterator it;
//
// Find out which/if JIDs have been removed
//
// list of JIDs from server
QStringList newJids;
for (it = rosterItems.begin(); it < rosterItems.end(); it++)
newJids << QString::fromStdString((*it).getJID().toBare().toString());
// list of the JIDs from the DB
QStringList currentJids = rosterModel->getJidList();
// a new list with all JIDs to delete
QStringList jidsToDelete;
// add all JIDs to the delete list that are in the original list
// but not in the new from the server
for (int i = 0; i < currentJids.length(); i++) {
QString jidAtI = currentJids.at(i);
if (!newJids.contains(jidAtI)) {
jidsToDelete << jidAtI;
}
}
// remove the JIDs from the DB
rosterModel->removeListOfJids(&jidsToDelete);
//
// Update the roster
//
for (it = rosterItems.begin(); it < rosterItems.end(); it++) {
QString jid = QString::fromStdString((*it).getJID().toBare().toString());
QString name = QString::fromStdString((*it).getName());
if (currentJids.contains(jid)) {
rosterModel->updateContactName(jid, name);
} else {
rosterModel->insertContact(jid, name);
}
}
}
}
void RosterController::handleInitialRosterPopulated()
{
// all contacts from the roster were added to the db (handleRosterReceived was already called)
// for all later changes we connect these bindings:
xmppRoster->onJIDAdded.connect(boost::bind(&RosterController::handleJidAdded, this, _1));
xmppRoster->onJIDRemoved.connect(boost::bind(&RosterController::handleJidRemoved, this, _1));
xmppRoster->onJIDUpdated.connect(boost::bind(&RosterController::handleJidUpdated, this, _1, _2, _3));
xmppRoster->onRosterCleared.connect(boost::bind(&RosterController::handleRosterCleared, this));
}
void RosterController::handleJidAdded(const Swift::JID &jid_)
{
rosterModel->insertContact(
QString::fromStdString(jid_.toBare().toString()),
QString::fromStdString(xmppRoster->getNameForJID(jid_))
);
rosterModel->submitAll();
}
void RosterController::handleJidRemoved(const Swift::JID &jid_)
{
rosterModel->removeContactByJid(
QString::fromStdString(jid_.toBare().toString())
);
}
void RosterController::handleJidUpdated(const Swift::JID &jid_, const std::string &name_,
const std::vector<std::string>&)
{
rosterModel->updateContactName(
QString::fromStdString(jid_.toBare().toString()),
QString::fromStdString(name_)
);
}
void RosterController::handleRosterCleared()
{
// remove all contacts
rosterModel->clearData();
}
void RosterController::addContact(const QString jid_, const QString name_)
{
// the contact will be added to the model via. handleJidAdded
// generate a new ID for the subscription request
Swift::IDGenerator idGenerator;
std::string iqId = idGenerator.generateID();
// create a new roster item payload
Swift::RosterItemPayload addItemPayload;
addItemPayload.setJID(jid_.toStdString());
addItemPayload.setName(name_.toStdString());
addItemPayload.setSubscription(Swift::RosterItemPayload::None);
// add the new roster item payload to a new roster payload
boost::shared_ptr<Swift::RosterPayload> rosterPayload(new Swift::RosterPayload);
rosterPayload->addItem(addItemPayload);
// sent the request
iqRouter->sendIQ(
Swift::IQ::createRequest(Swift::IQ::Set, Swift::JID(), iqId, rosterPayload)
);
}
void RosterController::removeContact(const QString jid_)
{
// the contact will be removed from the model via. handleJidRemoved
// generate new id for the request
Swift::IDGenerator idGenerator;
std::string iqId = idGenerator.generateID();
// create new roster payload, add roster item removal
boost::shared_ptr<Swift::RosterPayload> rosterPayload(new Swift::RosterPayload);
rosterPayload->addItem(Swift::RosterItemPayload(
Swift::JID(jid_.toStdString()), "",
Swift::RosterItemPayload::Remove
));
// send the remove request
iqRouter->sendIQ(
Swift::IQ::createRequest(Swift::IQ::Set, Swift::JID(), iqId, rosterPayload)
);
}
void RosterController::handleMessageReceived(Swift::Message::ref message)
{
//
// Update last exchanged and unread message count
//
boost::optional<std::string> optionalMessageBody = message->getBody();
if (optionalMessageBody) {
QString msgAuthor = QString::fromStdString(message->getFrom()
.toBare().toString());
QString message = QString::fromStdString(optionalMessageBody.get());
// update the last message for this contact
rosterModel->setLastMessageForJid(&msgAuthor, &message);
updateLastExchangedOfJid(&msgAuthor);
if (msgAuthor != chatPartner) {
newUnreadMessageForJid(msgAuthor);
}
}
}
void RosterController::handleNewMessageSent(QString *jid, QString *message)
{
// update the last message for this contact
rosterModel->setLastMessageForJid(jid, message);
// update the last exchanged date
updateLastExchangedOfJid(jid);
}
void RosterController::updateLastExchangedOfJid(QString *jid_)
{
QString dateTime = QDateTime::currentDateTime().toString(Qt::ISODate);
rosterModel->setLastExchangedOfJid(jid_, &dateTime);
}
void RosterController::newUnreadMessageForJid(const QString jid_)
{
// get the current unread message count
int msgCount = rosterModel->getUnreadMessageCountOfJid(&jid_);
// increase it by one
msgCount++;
// set the new increased count
rosterModel->setUnreadMessageCountOfJid(&jid_, msgCount);
}
void RosterController::resetUnreadMessagesForJid(QString *jid)
{
rosterModel->setUnreadMessageCountOfJid(jid, 0);
}
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2017 LNJ <git@lnj.li>
*
* Kaidan 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.
*
* Kaidan 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 Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#include "RosterManager.h"
RosterManager::RosterManager(RosterModel* rosterModel, gloox::Client *client)
{
this->rosterModel = rosterModel;
rosterManager = client->rosterManager();
// register the roster updater as roster listener
rosterUpdater = new RosterUpdater(rosterModel, rosterManager);
rosterManager->registerRosterListener(rosterUpdater);
}
RosterManager::~RosterManager()
{
rosterManager->removeRosterListener();
delete rosterUpdater;
}
void RosterManager::addContact(const QString jid, const QString nick)
{
// don't set any groups
gloox::StringList groups;
rosterManager->add(jid.toStdString(), nick.toStdString(), groups);
}
void RosterManager::removeContact(const QString jid)
{
// cancel possible subscriptions
rosterManager->cancel(jid.toStdString()); // don't send our presence anymore
rosterManager->unsubscribe(jid.toStdString()); // don't receive the JID's presence anymore
// remove contact from roster
rosterManager->remove(jid.toStdString());
}
void RosterManager::setChatPartner(QString* jid)
{
rosterUpdater->setChatPartner(jid);
}
void RosterManager::handleMessageSent(QString* jid, QString* message)
{
rosterUpdater->handleMessageSent(jid, message);
}
/*
* Kaidan - A user-friendly XMPP client for every device!
*
*
* Copyright (C) 2017 LNJ <git@lnj.li>
* Copyright (C) 2016 geobra <s.g.b@gmx.de>
*
*
* Kaidan 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.
*
*
* Kaidan 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 Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ROSTERCONTROLLER_H
#define ROSTERCONTROLLER_H
#ifndef ROSTERMANAGER_H
#define ROSTERMANAGER_H
// Qt
#include <QObject>
#include <QSqlTableModel>
// Swiften
#include <Swiften/Client/Client.h>
#include <Swiften/Elements/ErrorPayload.h>
#include <Swiften/Elements/Message.h>
// gloox
#include <gloox/client.h>
#include <gloox/rostermanager.h>
// Kaidan
#include "RosterModel.h"
#include "RosterUpdater.h"
class RosterController : public QObject
class RosterManager
{
Q_OBJECT
Q_PROPERTY(RosterModel* rosterModel READ getRosterModel NOTIFY rosterModelChanged)
public:
RosterController(QSqlDatabase* database, QObject *parent = 0);
~RosterController();
RosterManager(RosterModel *rosterModel, gloox::Client *client);
~RosterManager();
void setClient(Swift::Client *client_);
void requestRosterFromClient();
RosterModel* getRosterModel();
void setChatPartner(QString *chatPartner);
void handleNewMessageSent(QString*, QString*);
void updateLastExchangedOfJid(QString *jid_);
void newUnreadMessageForJid(const QString jid_);
void resetUnreadMessagesForJid(QString *jid_);
Q_INVOKABLE void addContact(const QString jid_, const QString name_);
Q_INVOKABLE void removeContact(const QString);
void addContact(const QString jid_, const QString name_);
void removeContact(const QString);
signals:
void rosterModelChanged();
void setChatPartner(QString *jid);
void handleMessageSent(QString *jid, QString *message);
private:
void handleMessageReceived(Swift::Message::ref message);
void handleRosterReceived(Swift::ErrorPayload::ref error);
void handleInitialRosterPopulated();
void handleJidAdded(const Swift::JID &jid_);
void handleJidRemoved(const Swift::JID &jid_);
void handleJidUpdated(const Swift::JID &jid_, const std::string &name_, const std::vector<std::string>&);
void handleRosterCleared();
Swift::Client *client;
Swift::IQRouter *iqRouter;
Swift::XMPPRoster *xmppRoster;
RosterModel *rosterModel;
QString chatPartner;
RosterUpdater *rosterUpdater;
gloox::RosterManager *rosterManager;
};
#endif // ROSTERCONTROLLER_H
#endif // ROSTERMANAGER_H
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2017 LNJ <git@lnj.li>
* Copyright (C) 2016 geobra <s.g.b@gmx.de>
*
* Kaidan 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.
*
* Kaidan 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.