Commit 8f8e40b9 authored by Linus Jahn's avatar Linus Jahn
Browse files

Add VCard-based Avatars via. vcard-temp

This implements XEP-0054: vcard-temp, but only handles the avatar/profile picture.
Avatars (and everything else in the VCard) will currently only be updated on connecting.
For changing this, we need to implement XEP-0153: vCard-Based Avatars, that will send
presences with notices of updated VCards.
parent 6a8ebae5
......@@ -15,5 +15,6 @@ set(KAIDAN_SOURCES
${CURDIR}/Notifications.cpp
${CURDIR}/PresenceHandler.cpp
${CURDIR}/ServiceDiscoveryManager.cpp
${CURDIR}/VCardManager.cpp
${CURDIR}/XmlLogHandler.cpp
)
......@@ -151,16 +151,16 @@ void Database::createNewDatabase()
//
if (!query.exec("CREATE TABLE IF NOT EXISTS 'Roster' ("
"'jid' TEXT NOT NULL,"
"'name' TEXT NOT NULL,"
"'lastExchanged' TEXT NOT NULL,"
"'unreadMessages' INTEGER,"
"'lastMessage' TEXT,"
"'lastOnline' TEXT," // < UNUSED v
"'activity' TEXT,"
"'status' TEXT,"
"'mood' TEXT,"
"'avatarHash' TEXT" // < UNUSED ^
"'jid' TEXT NOT NULL,"
"'name' TEXT NOT NULL,"
"'lastExchanged' TEXT NOT NULL,"
"'unreadMessages' INTEGER,"
"'lastMessage' TEXT,"
"'lastOnline' TEXT," // < UNUSED v
"'activity' TEXT,"
"'status' TEXT,"
"'mood' TEXT," // < UNUSED ^
"'avatarHash' TEXT"
")"))
{
qFatal("Failed to query database: %s", qPrintable(query.lastError().text()));
......
......@@ -34,6 +34,7 @@
#include <gloox/receipt.h>
#include <gloox/forward.h>
#include <gloox/carbons.h>
#include <gloox/vcardmanager.h>
// Kaidan
#include "RosterModel.h"
#include "MessageModel.h"
......@@ -57,6 +58,7 @@ Kaidan::Kaidan(QObject *parent) : QObject(parent)
messageModel = new MessageModel(database->getDatabase());
rosterModel = new RosterModel(database->getDatabase());
xmlLogHandler = new XmlLogHandler();
avatarStorage = new AvatarFileStorage();
// client package fetch timer
packageFetchTimer = new QTimer(this);
......@@ -92,6 +94,7 @@ Kaidan::~Kaidan()
delete rosterModel;
delete messageModel;
delete database;
delete avatarStorage;
delete xmlLogHandler;
delete packageFetchTimer;
delete settings;
......@@ -117,8 +120,11 @@ void Kaidan::mainConnect()
messageSessionHandler = new MessageSessionHandler(client, messageModel, rosterModel);
client->registerMessageSessionHandler(messageSessionHandler);
// VCardManager
vCardManager = new VCardManager(client, avatarStorage, rosterModel);
// Roster
rosterManager = new RosterManager(rosterModel, client);
rosterManager = new RosterManager(client, rosterModel, vCardManager);
// Presence Handler
presenceHandler = new PresenceHandler(client);
......@@ -158,6 +164,7 @@ void Kaidan::clientCleanUp()
delete presenceHandler;
delete rosterManager;
delete messageSessionHandler;
delete vCardManager;
delete client;
}
......@@ -291,6 +298,11 @@ QString Kaidan::getResourcePath(QString name_)
return QString("");
}
QString Kaidan::getAvatarPath(QString hash)
{
return QString("file://") + avatarStorage->getAvatarPath(hash);
}
RosterModel* Kaidan::getRosterModel()
{
return rosterModel;
......
......@@ -36,6 +36,8 @@
#include "MessageSessionHandler.h"
#include "PresenceHandler.h"
#include "ServiceDiscoveryManager.h"
#include "VCardManager.h"
#include "AvatarFileStorage.h"
#include "XmlLogHandler.h"
class Kaidan : public QObject, public gloox::ConnectionListener
......@@ -61,6 +63,7 @@ public:
Q_INVOKABLE void addContact(QString jid, QString nick);
Q_INVOKABLE void removeContact(QString jid);
Q_INVOKABLE QString getResourcePath(QString);
Q_INVOKABLE QString getAvatarPath(QString hash);
Q_INVOKABLE QString getVersionString();
Q_INVOKABLE QString removeNewLinesFromString(QString input);
......@@ -105,6 +108,8 @@ private:
MessageSessionHandler *messageSessionHandler;
PresenceHandler *presenceHandler;
ServiceDiscoveryManager *serviceDiscoveryManager;
VCardManager *vCardManager;
AvatarFileStorage *avatarStorage;
XmlLogHandler *xmlLogHandler;
QSettings *settings;
......
......@@ -19,13 +19,13 @@
#include "RosterManager.h"
RosterManager::RosterManager(RosterModel* rosterModel, gloox::Client *client)
RosterManager::RosterManager(gloox::Client *client, RosterModel* rosterModel, VCardManager *vCardManager)
{
this->rosterModel = rosterModel;
rosterManager = client->rosterManager();
// register the roster updater as roster listener
rosterUpdater = new RosterUpdater(rosterModel, rosterManager);
rosterUpdater = new RosterUpdater(rosterModel, rosterManager, vCardManager);
rosterManager->registerRosterListener(rosterUpdater);
}
......
......@@ -26,11 +26,12 @@
// Kaidan
#include "RosterModel.h"
#include "RosterUpdater.h"
#include "VCardManager.h"
class RosterManager
{
public:
RosterManager(RosterModel *rosterModel, gloox::Client *client);
RosterManager(gloox::Client *client, RosterModel *rosterModel, VCardManager *vCardManager);
~RosterManager();
void addContact(const QString jid_, const QString name_);
......
......@@ -198,3 +198,20 @@ void RosterModel::setLastMessageForJid(const QString *jid, QString *message)
submit();
}
void RosterModel::setAvatarHash(const QString* jid, const QString* hash)
{
QSqlQuery query(*database);
query.prepare(QString("UPDATE Roster SET avatarHash = '%1' WHERE jid = '%2'")
.arg(*hash, *jid));
if (!query.exec()) {
qDebug("Failed to query database: %s", qPrintable(query.lastError().text()));
qDebug() << query.lastQuery();
}
if (!select()) {
qDebug() << "Error on select in RosterModel::setAvatarHash";
}
submit();
}
......@@ -45,6 +45,7 @@ public:
int getUnreadMessageCountOfJid(const QString* jid_);
void setUnreadMessageCountOfJid(const QString* jid_, const int unreadMessageCount);
void setLastMessageForJid(const QString *jid, QString *message);
void setAvatarHash(const QString *jid, const QString *hash);
private:
QSqlDatabase *database;
......
......@@ -28,10 +28,11 @@
#include <QDateTime>
#include <QDebug>
RosterUpdater::RosterUpdater(RosterModel *rosterModel, gloox::RosterManager *rosterManager)
RosterUpdater::RosterUpdater(RosterModel *rosterModel, gloox::RosterManager *rosterManager, VCardManager *vCardManager)
{
this->rosterModel = rosterModel;
this->rosterManager = rosterManager;
this->vCardManager = vCardManager;
}
RosterUpdater::~RosterUpdater()
......@@ -80,6 +81,8 @@ void RosterUpdater::handleRoster(const gloox::Roster &roster)
} else {
rosterModel->insertContact(jid, name);
}
vCardManager->fetchVCard(jid);
}
}
......
......@@ -29,11 +29,12 @@
#include <gloox/rostermanager.h>
// Kaidan
#include "RosterModel.h"
#include "VCardManager.h"
class RosterUpdater : public gloox::RosterListener
{
public:
RosterUpdater(RosterModel* rosterModel, gloox::RosterManager *rosterManager);
RosterUpdater(RosterModel* rosterModel, gloox::RosterManager *rosterManager, VCardManager *vCardManager);
~RosterUpdater();
// gloox::RosterListener
......@@ -55,6 +56,7 @@ public:
private:
RosterModel *rosterModel;
gloox::RosterManager *rosterManager;
VCardManager *vCardManager;
};
#endif // ROSTERUPDATER_H
/*
* 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 "VCardManager.h"
VCardManager::VCardManager(gloox::Client *client, AvatarFileStorage *avatarStorage,
RosterModel *rosterModel)
{
this->client = client;
this->vCardManager = new gloox::VCardManager(client);
this->avatarStorage = avatarStorage;
this->rosterModel = rosterModel;
}
VCardManager::~VCardManager()
{
delete vCardManager;
}
void VCardManager::fetchVCard(QString jid)
{
vCardManager->fetchVCard(gloox::JID(jid.toStdString()), this);
}
void VCardManager::handleVCard(const gloox::JID& jid, const gloox::VCard* vcard)
{
std::string avatarString = vcard->photo().binval;
if (avatarString.length() <= 0)
return;
QByteArray avatarBytes(avatarString.c_str(), avatarString.length());
QString jid_ = QString::fromStdString(jid.bare());
AvatarFileStorage::AddAvatarResult result = avatarStorage->addAvatar(jid_, avatarBytes);
// if the avatar for this jid has been changed, also change it in the DB
if (result.hasChanged)
rosterModel->setAvatarHash(&jid_, &result.hash);
}
void VCardManager::handleVCardResult(VCardContext context, const gloox::JID &jid, gloox::StanzaError stanzaError)
{
}
/*
* 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/>.
*/
#ifndef VCARDMANAGER_H
#define VCARDMANAGER_H
// gloox
#include <gloox/vcardhandler.h>
#include <gloox/vcardmanager.h>
#include <gloox/client.h>
// Kaidan
#include "AvatarFileStorage.h"
#include "RosterModel.h"
class VCardManager : public gloox::VCardHandler
{
public:
VCardManager(gloox::Client *client, AvatarFileStorage *avatarStorage, RosterModel *rosterModel);
~VCardManager();
void fetchVCard(QString jid);
virtual void handleVCard(const gloox::JID &jid, const gloox::VCard *vcard);
virtual void handleVCardResult(VCardContext context, const gloox::JID &jid,
gloox::StanzaError stanzaError = gloox::StanzaErrorUndefined);
private:
gloox::Client *client;
gloox::VCardManager *vCardManager;
AvatarFileStorage *avatarStorage;
RosterModel *rosterModel;
};
#endif // VCARDMANAGER_H
......@@ -42,6 +42,7 @@ Kirigami.ScrollablePage {
name: model.name ? model.name : model.jid
lastMessage: model.lastMessage
unreadMessages: model.unreadMessages
avatarImagePath: model.avatarHash ? kaidan.getAvatarPath(model.avatarHash) : kaidan.getResourcePath("images/fallback-avatar.svg")
onClicked: {
// first push the chat page
......
......@@ -26,6 +26,7 @@ Kirigami.SwipeListItem {
property string name;
property string lastMessage;
property int unreadMessages;
property string avatarImagePath;
id: listItem
topPadding: Kirigami.Units.smallSpacing * 1.5
......@@ -36,7 +37,7 @@ Kirigami.SwipeListItem {
// left side: Avatar
Image {
source: kaidan.getResourcePath("images/fallback-avatar.svg")
source: avatarImagePath
fillMode: Image.PreserveAspectFit
Layout.preferredHeight: parent.height
Layout.preferredWidth: parent.height
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment