feat/tray_pictogram #70
@ -6,7 +6,8 @@ endif(WIN32)
|
|||||||
target_sources(squawk PRIVATE
|
target_sources(squawk PRIVATE
|
||||||
account.cpp
|
account.cpp
|
||||||
account.h
|
account.h
|
||||||
adapterFuctions.cpp
|
adapterfunctions.cpp
|
||||||
|
adapterfunctions.h
|
||||||
archive.cpp
|
archive.cpp
|
||||||
archive.h
|
archive.h
|
||||||
conference.cpp
|
conference.cpp
|
||||||
|
521
core/account.cpp
521
core/account.cpp
@ -41,13 +41,12 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
|||||||
rcpm(new QXmppMessageReceiptManager()),
|
rcpm(new QXmppMessageReceiptManager()),
|
||||||
reconnectScheduled(false),
|
reconnectScheduled(false),
|
||||||
reconnectTimer(new QTimer),
|
reconnectTimer(new QTimer),
|
||||||
avatarHash(),
|
|
||||||
avatarType(),
|
|
||||||
ownVCardRequestInProgress(false),
|
|
||||||
network(p_net),
|
network(p_net),
|
||||||
passwordType(Shared::AccountPassword::plain),
|
passwordType(Shared::AccountPassword::plain),
|
||||||
|
pepSupport(false),
|
||||||
mh(new MessageHandler(this)),
|
mh(new MessageHandler(this)),
|
||||||
rh(new RosterHandler(this))
|
rh(new RosterHandler(this)),
|
||||||
|
vh(new VCardHandler(this))
|
||||||
{
|
{
|
||||||
config.setUser(p_login);
|
config.setUser(p_login);
|
||||||
config.setDomain(p_server);
|
config.setDomain(p_server);
|
||||||
@ -73,10 +72,6 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
|||||||
|
|
||||||
client.addExtension(mm);
|
client.addExtension(mm);
|
||||||
client.addExtension(bm);
|
client.addExtension(bm);
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
client.addExtension(um);
|
client.addExtension(um);
|
||||||
QObject::connect(um, &QXmppUploadRequestManager::slotReceived, mh, &MessageHandler::onUploadSlotReceived);
|
QObject::connect(um, &QXmppUploadRequestManager::slotReceived, mh, &MessageHandler::onUploadSlotReceived);
|
||||||
QObject::connect(um, &QXmppUploadRequestManager::requestFailed, mh, &MessageHandler::onUploadSlotRequestFailed);
|
QObject::connect(um, &QXmppUploadRequestManager::requestFailed, mh, &MessageHandler::onUploadSlotRequestFailed);
|
||||||
@ -91,52 +86,6 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
|||||||
client.addExtension(rcpm);
|
client.addExtension(rcpm);
|
||||||
QObject::connect(rcpm, &QXmppMessageReceiptManager::messageDelivered, mh, &MessageHandler::onReceiptReceived);
|
QObject::connect(rcpm, &QXmppMessageReceiptManager::messageDelivered, mh, &MessageHandler::onReceiptReceived);
|
||||||
|
|
||||||
|
|
||||||
QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
|
|
||||||
path += "/" + name;
|
|
||||||
QDir dir(path);
|
|
||||||
|
|
||||||
if (!dir.exists()) {
|
|
||||||
bool res = dir.mkpath(path);
|
|
||||||
if (!res) {
|
|
||||||
qDebug() << "Couldn't create a cache directory for account" << name;
|
|
||||||
throw 22;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QFile* avatar = new QFile(path + "/avatar.png");
|
|
||||||
QString type = "png";
|
|
||||||
if (!avatar->exists()) {
|
|
||||||
delete avatar;
|
|
||||||
avatar = new QFile(path + "/avatar.jpg");
|
|
||||||
type = "jpg";
|
|
||||||
if (!avatar->exists()) {
|
|
||||||
delete avatar;
|
|
||||||
avatar = new QFile(path + "/avatar.jpeg");
|
|
||||||
type = "jpeg";
|
|
||||||
if (!avatar->exists()) {
|
|
||||||
delete avatar;
|
|
||||||
avatar = new QFile(path + "/avatar.gif");
|
|
||||||
type = "gif";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (avatar->exists()) {
|
|
||||||
if (avatar->open(QFile::ReadOnly)) {
|
|
||||||
QCryptographicHash sha1(QCryptographicHash::Sha1);
|
|
||||||
sha1.addData(avatar);
|
|
||||||
avatarHash = sha1.result();
|
|
||||||
avatarType = type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (avatarType.size() != 0) {
|
|
||||||
presence.setVCardUpdateType(QXmppPresence::VCardUpdateValidPhoto);
|
|
||||||
presence.setPhotoHash(avatarHash.toUtf8());
|
|
||||||
} else {
|
|
||||||
presence.setVCardUpdateType(QXmppPresence::VCardUpdateNotReady);
|
|
||||||
}
|
|
||||||
|
|
||||||
reconnectTimer->setSingleShot(true);
|
reconnectTimer->setSingleShot(true);
|
||||||
QObject::connect(reconnectTimer, &QTimer::timeout, this, &Account::onReconnectTimer);
|
QObject::connect(reconnectTimer, &QTimer::timeout, this, &Account::onReconnectTimer);
|
||||||
|
|
||||||
@ -160,6 +109,7 @@ Account::~Account()
|
|||||||
QObject::disconnect(network, &NetworkAccess::downloadFileComplete, mh, &MessageHandler::onDownloadFileComplete);
|
QObject::disconnect(network, &NetworkAccess::downloadFileComplete, mh, &MessageHandler::onDownloadFileComplete);
|
||||||
QObject::disconnect(network, &NetworkAccess::loadFileError, mh, &MessageHandler::onLoadFileError);
|
QObject::disconnect(network, &NetworkAccess::loadFileError, mh, &MessageHandler::onLoadFileError);
|
||||||
|
|
||||||
|
delete vh;
|
||||||
delete mh;
|
delete mh;
|
||||||
delete rh;
|
delete rh;
|
||||||
|
|
||||||
@ -264,36 +214,6 @@ void Core::Account::reconnect()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Core::Account::getName() const {
|
|
||||||
return name;}
|
|
||||||
|
|
||||||
QString Core::Account::getLogin() const {
|
|
||||||
return config.user();}
|
|
||||||
|
|
||||||
QString Core::Account::getPassword() const {
|
|
||||||
return config.password();}
|
|
||||||
|
|
||||||
QString Core::Account::getServer() const {
|
|
||||||
return config.domain();}
|
|
||||||
|
|
||||||
Shared::AccountPassword Core::Account::getPasswordType() const {
|
|
||||||
return passwordType;}
|
|
||||||
|
|
||||||
void Core::Account::setPasswordType(Shared::AccountPassword pt) {
|
|
||||||
passwordType = pt; }
|
|
||||||
|
|
||||||
void Core::Account::setLogin(const QString& p_login) {
|
|
||||||
config.setUser(p_login);}
|
|
||||||
|
|
||||||
void Core::Account::setName(const QString& p_name) {
|
|
||||||
name = p_name;}
|
|
||||||
|
|
||||||
void Core::Account::setPassword(const QString& p_password) {
|
|
||||||
config.setPassword(p_password);}
|
|
||||||
|
|
||||||
void Core::Account::setServer(const QString& p_server) {
|
|
||||||
config.setDomain(p_server);}
|
|
||||||
|
|
||||||
Shared::Availability Core::Account::getAvailability() const
|
Shared::Availability Core::Account::getAvailability() const
|
||||||
{
|
{
|
||||||
if (state == Shared::ConnectionState::connected) {
|
if (state == Shared::ConnectionState::connected) {
|
||||||
@ -325,32 +245,11 @@ void Core::Account::onPresenceReceived(const QXmppPresence& p_presence)
|
|||||||
QString jid = comps.front().toLower();
|
QString jid = comps.front().toLower();
|
||||||
QString resource = comps.back();
|
QString resource = comps.back();
|
||||||
|
|
||||||
QString myJid = getLogin() + "@" + getServer();
|
if (jid == getBareJid()) {
|
||||||
|
|
||||||
if (jid == myJid) {
|
|
||||||
if (resource == getResource()) {
|
if (resource == getResource()) {
|
||||||
emit availabilityChanged(static_cast<Shared::Availability>(p_presence.availableStatusType()));
|
emit availabilityChanged(static_cast<Shared::Availability>(p_presence.availableStatusType()));
|
||||||
} else {
|
} else {
|
||||||
if (!ownVCardRequestInProgress) {
|
vh->handleOtherPresenceOfMyAccountChange(p_presence);
|
||||||
switch (p_presence.vCardUpdateType()) {
|
|
||||||
case QXmppPresence::VCardUpdateNone: //this presence has nothing to do with photo
|
|
||||||
break;
|
|
||||||
case QXmppPresence::VCardUpdateNotReady: //let's say the photo didn't change here
|
|
||||||
break;
|
|
||||||
case QXmppPresence::VCardUpdateNoPhoto: //there is no photo, need to drop if any
|
|
||||||
if (avatarType.size() > 0) {
|
|
||||||
vm->requestClientVCard();
|
|
||||||
ownVCardRequestInProgress = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case QXmppPresence::VCardUpdateValidPhoto: //there is a photo, need to load
|
|
||||||
if (avatarHash != p_presence.photoHash()) {
|
|
||||||
vm->requestClientVCard();
|
|
||||||
ownVCardRequestInProgress = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RosterItem* item = rh->getRosterItem(jid);
|
RosterItem* item = rh->getRosterItem(jid);
|
||||||
@ -392,18 +291,6 @@ void Core::Account::onPresenceReceived(const QXmppPresence& p_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::onMamMessageReceived(const QString& queryId, const QXmppMessage& msg)
|
void Core::Account::onMamMessageReceived(const QString& queryId, const QXmppMessage& msg)
|
||||||
{
|
{
|
||||||
if (msg.id().size() > 0 && (msg.body().size() > 0 || msg.outOfBandUrl().size() > 0)) {
|
if (msg.id().size() > 0 && (msg.body().size() > 0 || msg.outOfBandUrl().size() > 0)) {
|
||||||
@ -667,6 +554,151 @@ void Core::Account::setRoomJoined(const QString& jid, bool joined)
|
|||||||
conf->setJoined(joined);
|
conf->setJoined(joined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Core::Account::onDiscoveryItemsReceived(const QXmppDiscoveryIq& items)
|
||||||
|
{
|
||||||
|
if (items.from() == getServer()) {
|
||||||
|
std::set<QString> needToRequest;
|
||||||
|
qDebug() << "Server items list received for account " << name << ":";
|
||||||
|
for (QXmppDiscoveryIq::Item item : items.items()) {
|
||||||
|
QString jid = item.jid();
|
||||||
|
if (jid != getServer()) {
|
||||||
|
qDebug() << " Node" << jid;
|
||||||
|
needToRequest.insert(jid);
|
||||||
|
} else {
|
||||||
|
qDebug() << " " << item.node().toStdString().c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const QString& jid : needToRequest) {
|
||||||
|
dm->requestInfo(jid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::Account::onDiscoveryInfoReceived(const QXmppDiscoveryIq& info)
|
||||||
|
{
|
||||||
|
if (info.from() == getServer()) {
|
||||||
|
bool enableCC = false;
|
||||||
|
qDebug() << "Server info received for account" << name;
|
||||||
|
QStringList features = info.features();
|
||||||
|
qDebug() << "List of supported features of the server " << getServer() << ":";
|
||||||
|
for (const QString& feature : features) {
|
||||||
|
qDebug() << " " << feature.toStdString().c_str();
|
||||||
|
if (feature == "urn:xmpp:carbons:2") {
|
||||||
|
enableCC = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enableCC) {
|
||||||
|
qDebug() << "Enabling carbon copies for account" << name;
|
||||||
|
cm->setCarbonsEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Requesting account" << name << "capabilities";
|
||||||
|
dm->requestInfo(getBareJid());
|
||||||
|
} else if (info.from() == getBareJid()) {
|
||||||
|
qDebug() << "Received capabilities for account" << name << ":";
|
||||||
|
QList<QXmppDiscoveryIq::Identity> identities = info.identities();
|
||||||
|
bool pepSupported = false;
|
||||||
|
for (const QXmppDiscoveryIq::Identity& identity : identities) {
|
||||||
|
QString type = identity.type();
|
||||||
|
qDebug() << " " << identity.category() << type;
|
||||||
|
if (type == "pep") {
|
||||||
|
pepSupported = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rh->setPepSupport(pepSupported);
|
||||||
|
} else {
|
||||||
|
qDebug() << "Received info for account" << name << "about" << info.from();
|
||||||
|
QList<QXmppDiscoveryIq::Identity> identities = info.identities();
|
||||||
|
for (const QXmppDiscoveryIq::Identity& identity : identities) {
|
||||||
|
qDebug() << " " << identity.name() << identity.category() << identity.type();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::Account::handleDisconnection()
|
||||||
|
{
|
||||||
|
cm->setCarbonsEnabled(false);
|
||||||
|
rh->handleOffline();
|
||||||
|
vh->handleOffline();
|
||||||
|
archiveQueries.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::Account::onContactHistoryResponse(const std::list<Shared::Message>& list, bool last)
|
||||||
|
{
|
||||||
|
RosterItem* contact = static_cast<RosterItem*>(sender());
|
||||||
|
|
||||||
|
qDebug() << "Collected history for contact " << contact->jid << list.size() << "elements";
|
||||||
|
if (last) {
|
||||||
|
qDebug() << "The response contains the first accounted message";
|
||||||
|
}
|
||||||
|
emit responseArchive(contact->jid, list, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Core::Account::getResource() const {
|
||||||
|
return config.resource();}
|
||||||
|
|
||||||
|
void Core::Account::setResource(const QString& p_resource) {
|
||||||
|
config.setResource(p_resource);}
|
||||||
|
|
||||||
|
QString Core::Account::getBareJid() const {
|
||||||
|
return getLogin() + "@" + getServer();}
|
||||||
|
|
||||||
|
QString Core::Account::getFullJid() const {
|
||||||
|
return getBareJid() + "/" + getResource();}
|
||||||
|
|
||||||
|
QString Core::Account::getName() const {
|
||||||
|
return name;}
|
||||||
|
|
||||||
|
QString Core::Account::getLogin() const {
|
||||||
|
return config.user();}
|
||||||
|
|
||||||
|
QString Core::Account::getPassword() const {
|
||||||
|
return config.password();}
|
||||||
|
|
||||||
|
QString Core::Account::getServer() const {
|
||||||
|
return config.domain();}
|
||||||
|
|
||||||
|
Shared::AccountPassword Core::Account::getPasswordType() const {
|
||||||
|
return passwordType;}
|
||||||
|
|
||||||
|
void Core::Account::setPasswordType(Shared::AccountPassword pt) {
|
||||||
|
passwordType = pt; }
|
||||||
|
|
||||||
|
void Core::Account::setLogin(const QString& p_login) {
|
||||||
|
config.setUser(p_login);}
|
||||||
|
|
||||||
|
void Core::Account::setName(const QString& p_name) {
|
||||||
|
name = p_name;}
|
||||||
|
|
||||||
|
void Core::Account::setPassword(const QString& p_password) {
|
||||||
|
config.setPassword(p_password);}
|
||||||
|
|
||||||
|
void Core::Account::setServer(const QString& p_server) {
|
||||||
|
config.setDomain(p_server);}
|
||||||
|
|
||||||
|
void Core::Account::sendMessage(const Shared::Message& data) {
|
||||||
|
mh->sendMessage(data);}
|
||||||
|
|
||||||
|
void Core::Account::requestChangeMessage(const QString& jid, const QString& messageId, const QMap<QString, QVariant>& data){
|
||||||
|
mh->requestChangeMessage(jid, messageId, data);}
|
||||||
|
|
||||||
|
void Core::Account::resendMessage(const QString& jid, const QString& id) {
|
||||||
|
mh->resendMessage(jid, id);}
|
||||||
|
|
||||||
|
void Core::Account::replaceMessage(const QString& originalId, const Shared::Message& data) {
|
||||||
|
mh->sendMessage(data, false, originalId);}
|
||||||
|
|
||||||
|
void Core::Account::requestVCard(const QString& jid) {
|
||||||
|
vh->requestVCard(jid);}
|
||||||
|
|
||||||
|
void Core::Account::uploadVCard(const Shared::VCard& card) {
|
||||||
|
vh->uploadVCard(card);}
|
||||||
|
|
||||||
|
QString Core::Account::getAvatarPath() const {
|
||||||
|
return vh->getAvatarPath();}
|
||||||
|
|
||||||
void Core::Account::removeRoomRequest(const QString& jid){
|
void Core::Account::removeRoomRequest(const QString& jid){
|
||||||
rh->removeRoomRequest(jid);}
|
rh->removeRoomRequest(jid);}
|
||||||
|
|
||||||
@ -688,254 +720,3 @@ void Core::Account::renameContactRequest(const QString& jid, const QString& newN
|
|||||||
rm->renameItem(jid, newName);
|
rm->renameItem(jid, newName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::onVCardReceived(const QXmppVCardIq& card)
|
|
||||||
{
|
|
||||||
QString id = card.from();
|
|
||||||
QStringList comps = id.split("/");
|
|
||||||
QString jid = comps.front().toLower();
|
|
||||||
QString resource("");
|
|
||||||
if (comps.size() > 1) {
|
|
||||||
resource = comps.back();
|
|
||||||
}
|
|
||||||
pendingVCardRequests.erase(id);
|
|
||||||
RosterItem* item = rh->getRosterItem(jid);
|
|
||||||
|
|
||||||
if (item == 0) {
|
|
||||||
if (jid == getLogin() + "@" + getServer()) {
|
|
||||||
onOwnVCardReceived(card);
|
|
||||||
} else {
|
|
||||||
qDebug() << "received vCard" << jid << "doesn't belong to any of known contacts or conferences, skipping";
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Shared::VCard vCard = item->handleResponseVCard(card, resource);
|
|
||||||
|
|
||||||
emit receivedVCard(jid, vCard);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Account::onOwnVCardReceived(const QXmppVCardIq& card)
|
|
||||||
{
|
|
||||||
QByteArray ava = card.photo();
|
|
||||||
bool avaChanged = false;
|
|
||||||
QString path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + name + "/";
|
|
||||||
if (ava.size() > 0) {
|
|
||||||
QCryptographicHash sha1(QCryptographicHash::Sha1);
|
|
||||||
sha1.addData(ava);
|
|
||||||
QString newHash(sha1.result());
|
|
||||||
QMimeDatabase db;
|
|
||||||
QMimeType newType = db.mimeTypeForData(ava);
|
|
||||||
if (avatarType.size() > 0) {
|
|
||||||
if (avatarHash != newHash) {
|
|
||||||
QString oldPath = path + "avatar." + avatarType;
|
|
||||||
QFile oldAvatar(oldPath);
|
|
||||||
bool oldToRemove = false;
|
|
||||||
if (oldAvatar.exists()) {
|
|
||||||
if (oldAvatar.rename(oldPath + ".bak")) {
|
|
||||||
oldToRemove = true;
|
|
||||||
} else {
|
|
||||||
qDebug() << "Received new avatar for account" << name << "but can't get rid of the old one, doing nothing";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QFile newAvatar(path + "avatar." + newType.preferredSuffix());
|
|
||||||
if (newAvatar.open(QFile::WriteOnly)) {
|
|
||||||
newAvatar.write(ava);
|
|
||||||
newAvatar.close();
|
|
||||||
avatarHash = newHash;
|
|
||||||
avatarType = newType.preferredSuffix();
|
|
||||||
avaChanged = true;
|
|
||||||
} else {
|
|
||||||
qDebug() << "Received new avatar for account" << name << "but can't save it";
|
|
||||||
if (oldToRemove) {
|
|
||||||
qDebug() << "rolling back to the old avatar";
|
|
||||||
if (!oldAvatar.rename(oldPath)) {
|
|
||||||
qDebug() << "Couldn't roll back to the old avatar in account" << name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
QFile newAvatar(path + "avatar." + newType.preferredSuffix());
|
|
||||||
if (newAvatar.open(QFile::WriteOnly)) {
|
|
||||||
newAvatar.write(ava);
|
|
||||||
newAvatar.close();
|
|
||||||
avatarHash = newHash;
|
|
||||||
avatarType = newType.preferredSuffix();
|
|
||||||
avaChanged = true;
|
|
||||||
} else {
|
|
||||||
qDebug() << "Received new avatar for account" << name << "but can't save it";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (avatarType.size() > 0) {
|
|
||||||
QFile oldAvatar(path + "avatar." + avatarType);
|
|
||||||
if (!oldAvatar.remove()) {
|
|
||||||
qDebug() << "Received vCard for account" << name << "without avatar, but can't get rid of the file, doing nothing";
|
|
||||||
} else {
|
|
||||||
avatarType = "";
|
|
||||||
avatarHash = "";
|
|
||||||
avaChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (avaChanged) {
|
|
||||||
QMap<QString, QVariant> change;
|
|
||||||
if (avatarType.size() > 0) {
|
|
||||||
presence.setPhotoHash(avatarHash.toUtf8());
|
|
||||||
presence.setVCardUpdateType(QXmppPresence::VCardUpdateValidPhoto);
|
|
||||||
change.insert("avatarPath", path + "avatar." + avatarType);
|
|
||||||
} else {
|
|
||||||
presence.setPhotoHash("");
|
|
||||||
presence.setVCardUpdateType(QXmppPresence::VCardUpdateNoPhoto);
|
|
||||||
change.insert("avatarPath", "");
|
|
||||||
}
|
|
||||||
client.setClientPresence(presence);
|
|
||||||
emit changed(change);
|
|
||||||
}
|
|
||||||
|
|
||||||
ownVCardRequestInProgress = false;
|
|
||||||
|
|
||||||
Shared::VCard vCard;
|
|
||||||
initializeVCard(vCard, card);
|
|
||||||
|
|
||||||
if (avatarType.size() > 0) {
|
|
||||||
vCard.setAvatarType(Shared::Avatar::valid);
|
|
||||||
vCard.setAvatarPath(path + "avatar." + avatarType);
|
|
||||||
} else {
|
|
||||||
vCard.setAvatarType(Shared::Avatar::empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit receivedVCard(getLogin() + "@" + getServer(), vCard);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Core::Account::getAvatarPath() const
|
|
||||||
{
|
|
||||||
if (avatarType.size() == 0) {
|
|
||||||
return "";
|
|
||||||
} else {
|
|
||||||
return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + name + "/" + "avatar." + avatarType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Account::requestVCard(const QString& jid)
|
|
||||||
{
|
|
||||||
if (pendingVCardRequests.find(jid) == pendingVCardRequests.end()) {
|
|
||||||
qDebug() << "requesting vCard" << jid;
|
|
||||||
if (jid == getLogin() + "@" + getServer()) {
|
|
||||||
if (!ownVCardRequestInProgress) {
|
|
||||||
vm->requestClientVCard();
|
|
||||||
ownVCardRequestInProgress = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
vm->requestVCard(jid);
|
|
||||||
pendingVCardRequests.insert(jid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Account::uploadVCard(const Shared::VCard& card)
|
|
||||||
{
|
|
||||||
QXmppVCardIq iq;
|
|
||||||
initializeQXmppVCard(iq, card);
|
|
||||||
|
|
||||||
if (card.getAvatarType() != Shared::Avatar::empty) {
|
|
||||||
QString newPath = card.getAvatarPath();
|
|
||||||
QString oldPath = getAvatarPath();
|
|
||||||
QByteArray data;
|
|
||||||
QString type;
|
|
||||||
if (newPath != oldPath) {
|
|
||||||
QFile avatar(newPath);
|
|
||||||
if (!avatar.open(QFile::ReadOnly)) {
|
|
||||||
qDebug() << "An attempt to upload new vCard to account" << name
|
|
||||||
<< "but it wasn't possible to read file" << newPath
|
|
||||||
<< "which was supposed to be new avatar, uploading old avatar";
|
|
||||||
if (avatarType.size() > 0) {
|
|
||||||
QFile oA(oldPath);
|
|
||||||
if (!oA.open(QFile::ReadOnly)) {
|
|
||||||
qDebug() << "Couldn't read old avatar of account" << name << ", uploading empty avatar";
|
|
||||||
} else {
|
|
||||||
data = oA.readAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
data = avatar.readAll();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (avatarType.size() > 0) {
|
|
||||||
QFile oA(oldPath);
|
|
||||||
if (!oA.open(QFile::ReadOnly)) {
|
|
||||||
qDebug() << "Couldn't read old avatar of account" << name << ", uploading empty avatar";
|
|
||||||
} else {
|
|
||||||
data = oA.readAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.size() > 0) {
|
|
||||||
QMimeDatabase db;
|
|
||||||
type = db.mimeTypeForData(data).name();
|
|
||||||
iq.setPhoto(data);
|
|
||||||
iq.setPhotoType(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vm->setClientVCard(iq);
|
|
||||||
onOwnVCardReceived(iq);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Account::onDiscoveryItemsReceived(const QXmppDiscoveryIq& items)
|
|
||||||
{
|
|
||||||
for (QXmppDiscoveryIq::Item item : items.items()) {
|
|
||||||
if (item.jid() != getServer()) {
|
|
||||||
dm->requestInfo(item.jid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Account::onDiscoveryInfoReceived(const QXmppDiscoveryIq& info)
|
|
||||||
{
|
|
||||||
qDebug() << "Discovery info received for account" << name;
|
|
||||||
if (info.from() == getServer()) {
|
|
||||||
if (info.features().contains("urn:xmpp:carbons:2")) {
|
|
||||||
qDebug() << "Enabling carbon copies for account" << name;
|
|
||||||
cm->setCarbonsEnabled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Account::handleDisconnection()
|
|
||||||
{
|
|
||||||
cm->setCarbonsEnabled(false);
|
|
||||||
rh->handleOffline();
|
|
||||||
archiveQueries.clear();
|
|
||||||
pendingVCardRequests.clear();
|
|
||||||
Shared::VCard vCard; //just to show, that there is now more pending request
|
|
||||||
for (const QString& jid : pendingVCardRequests) {
|
|
||||||
emit receivedVCard(jid, vCard); //need to show it better in the future, like with an error
|
|
||||||
}
|
|
||||||
pendingVCardRequests.clear();
|
|
||||||
ownVCardRequestInProgress = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Account::onContactHistoryResponse(const std::list<Shared::Message>& list, bool last)
|
|
||||||
{
|
|
||||||
RosterItem* contact = static_cast<RosterItem*>(sender());
|
|
||||||
|
|
||||||
qDebug() << "Collected history for contact " << contact->jid << list.size() << "elements";
|
|
||||||
if (last) {
|
|
||||||
qDebug() << "The response contains the first accounted message";
|
|
||||||
}
|
|
||||||
emit responseArchive(contact->jid, list, last);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Account::requestChangeMessage(const QString& jid, const QString& messageId, const QMap<QString, QVariant>& data){
|
|
||||||
mh->requestChangeMessage(jid, messageId, data);}
|
|
||||||
|
|
||||||
void Core::Account::resendMessage(const QString& jid, const QString& id) {
|
|
||||||
mh->resendMessage(jid, id);}
|
|
||||||
|
|
||||||
void Core::Account::replaceMessage(const QString& originalId, const Shared::Message& data) {
|
|
||||||
mh->sendMessage(data, false, originalId);}
|
|
||||||
|
|
||||||
|
@ -39,7 +39,6 @@
|
|||||||
#include <QXmppBookmarkManager.h>
|
#include <QXmppBookmarkManager.h>
|
||||||
#include <QXmppBookmarkSet.h>
|
#include <QXmppBookmarkSet.h>
|
||||||
#include <QXmppUploadRequestManager.h>
|
#include <QXmppUploadRequestManager.h>
|
||||||
#include <QXmppVCardIq.h>
|
|
||||||
#include <QXmppVCardManager.h>
|
#include <QXmppVCardManager.h>
|
||||||
#include <QXmppMessageReceiptManager.h>
|
#include <QXmppMessageReceiptManager.h>
|
||||||
|
|
||||||
@ -50,6 +49,7 @@
|
|||||||
|
|
||||||
#include "handlers/messagehandler.h"
|
#include "handlers/messagehandler.h"
|
||||||
#include "handlers/rosterhandler.h"
|
#include "handlers/rosterhandler.h"
|
||||||
|
#include "handlers/vcardhandler.h"
|
||||||
|
|
||||||
namespace Core
|
namespace Core
|
||||||
{
|
{
|
||||||
@ -59,6 +59,7 @@ class Account : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
friend class MessageHandler;
|
friend class MessageHandler;
|
||||||
friend class RosterHandler;
|
friend class RosterHandler;
|
||||||
|
friend class VCardHandler;
|
||||||
public:
|
public:
|
||||||
Account(
|
Account(
|
||||||
const QString& p_login,
|
const QString& p_login,
|
||||||
@ -76,6 +77,8 @@ public:
|
|||||||
QString getPassword() const;
|
QString getPassword() const;
|
||||||
QString getResource() const;
|
QString getResource() const;
|
||||||
QString getAvatarPath() const;
|
QString getAvatarPath() const;
|
||||||
|
QString getBareJid() const;
|
||||||
|
QString getFullJid() const;
|
||||||
Shared::Availability getAvailability() const;
|
Shared::Availability getAvailability() const;
|
||||||
Shared::AccountPassword getPasswordType() const;
|
Shared::AccountPassword getPasswordType() const;
|
||||||
|
|
||||||
@ -86,7 +89,6 @@ public:
|
|||||||
void setResource(const QString& p_resource);
|
void setResource(const QString& p_resource);
|
||||||
void setAvailability(Shared::Availability avail);
|
void setAvailability(Shared::Availability avail);
|
||||||
void setPasswordType(Shared::AccountPassword pt);
|
void setPasswordType(Shared::AccountPassword pt);
|
||||||
QString getFullJid() const;
|
|
||||||
void sendMessage(const Shared::Message& data);
|
void sendMessage(const Shared::Message& data);
|
||||||
void requestArchive(const QString& jid, int count, const QString& before);
|
void requestArchive(const QString& jid, int count, const QString& before);
|
||||||
void subscribeToContact(const QString& jid, const QString& reason);
|
void subscribeToContact(const QString& jid, const QString& reason);
|
||||||
@ -157,16 +159,13 @@ private:
|
|||||||
bool reconnectScheduled;
|
bool reconnectScheduled;
|
||||||
QTimer* reconnectTimer;
|
QTimer* reconnectTimer;
|
||||||
|
|
||||||
std::set<QString> pendingVCardRequests;
|
|
||||||
|
|
||||||
QString avatarHash;
|
|
||||||
QString avatarType;
|
|
||||||
bool ownVCardRequestInProgress;
|
|
||||||
NetworkAccess* network;
|
NetworkAccess* network;
|
||||||
Shared::AccountPassword passwordType;
|
Shared::AccountPassword passwordType;
|
||||||
|
bool pepSupport;
|
||||||
|
|
||||||
MessageHandler* mh;
|
MessageHandler* mh;
|
||||||
RosterHandler* rh;
|
RosterHandler* rh;
|
||||||
|
VCardHandler* vh;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onClientStateChange(QXmppClient::State state);
|
void onClientStateChange(QXmppClient::State state);
|
||||||
@ -179,9 +178,6 @@ private slots:
|
|||||||
void onMamResultsReceived(const QString &queryId, const QXmppResultSetReply &resultSetReply, bool complete);
|
void onMamResultsReceived(const QString &queryId, const QXmppResultSetReply &resultSetReply, bool complete);
|
||||||
|
|
||||||
void onMamLog(QXmppLogger::MessageType type, const QString &msg);
|
void onMamLog(QXmppLogger::MessageType type, const QString &msg);
|
||||||
|
|
||||||
void onVCardReceived(const QXmppVCardIq& card);
|
|
||||||
void onOwnVCardReceived(const QXmppVCardIq& card);
|
|
||||||
|
|
||||||
void onDiscoveryItemsReceived (const QXmppDiscoveryIq& items);
|
void onDiscoveryItemsReceived (const QXmppDiscoveryIq& items);
|
||||||
void onDiscoveryInfoReceived (const QXmppDiscoveryIq& info);
|
void onDiscoveryInfoReceived (const QXmppDiscoveryIq& info);
|
||||||
@ -191,9 +187,6 @@ private:
|
|||||||
void handleDisconnection();
|
void handleDisconnection();
|
||||||
void onReconnectTimer();
|
void onReconnectTimer();
|
||||||
};
|
};
|
||||||
|
|
||||||
void initializeVCard(Shared::VCard& vCard, const QXmppVCardIq& card);
|
|
||||||
void initializeQXmppVCard(QXmppVCardIq& card, const Shared::VCard& vCard);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Squawk messenger.
|
* Squawk messenger.
|
||||||
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
|
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -15,10 +15,8 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifndef CORE_ADAPTER_FUNCTIONS_H
|
|
||||||
#define CORE_ADAPTER_FUNCTIONS_H
|
|
||||||
|
|
||||||
#include "account.h"
|
#include "adapterfunctions.h"
|
||||||
|
|
||||||
void Core::initializeVCard(Shared::VCard& vCard, const QXmppVCardIq& card)
|
void Core::initializeVCard(Shared::VCard& vCard, const QXmppVCardIq& card)
|
||||||
{
|
{
|
||||||
@ -271,5 +269,3 @@ void Core::initializeQXmppVCard(QXmppVCardIq& iq, const Shared::VCard& card) {
|
|||||||
iq.setEmails(emails);
|
iq.setEmails(emails);
|
||||||
iq.setPhones(phs);
|
iq.setPhones(phs);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CORE_ADAPTER_FUNCTIONS_H
|
|
32
core/adapterfunctions.h
Normal file
32
core/adapterfunctions.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Squawk messenger.
|
||||||
|
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef CORE_ADAPTER_FUNCTIONS_H
|
||||||
|
#define CORE_ADAPTER_FUNCTIONS_H
|
||||||
|
|
||||||
|
#include <QXmppVCardIq.h>
|
||||||
|
#include <shared/vcard.h>
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
void initializeVCard(Shared::VCard& vCard, const QXmppVCardIq& card);
|
||||||
|
void initializeQXmppVCard(QXmppVCardIq& card, const Shared::VCard& vCard);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CORE_ADAPTER_FUNCTIONS_H
|
@ -3,4 +3,6 @@ target_sources(squawk PRIVATE
|
|||||||
messagehandler.h
|
messagehandler.h
|
||||||
rosterhandler.cpp
|
rosterhandler.cpp
|
||||||
rosterhandler.h
|
rosterhandler.h
|
||||||
|
vcardhandler.cpp
|
||||||
|
vcardhandler.h
|
||||||
)
|
)
|
||||||
|
@ -176,7 +176,7 @@ void Core::MessageHandler::initializeMessage(Shared::Message& target, const QXmp
|
|||||||
target.setForwarded(forwarded);
|
target.setForwarded(forwarded);
|
||||||
|
|
||||||
if (guessing) {
|
if (guessing) {
|
||||||
if (target.getFromJid() == acc->getLogin() + "@" + acc->getServer()) {
|
if (target.getFromJid() == acc->getBareJid()) {
|
||||||
outgoing = true;
|
outgoing = true;
|
||||||
} else {
|
} else {
|
||||||
outgoing = false;
|
outgoing = false;
|
||||||
|
@ -26,7 +26,8 @@ Core::RosterHandler::RosterHandler(Core::Account* account):
|
|||||||
conferences(),
|
conferences(),
|
||||||
groups(),
|
groups(),
|
||||||
queuedContacts(),
|
queuedContacts(),
|
||||||
outOfRosterContacts()
|
outOfRosterContacts(),
|
||||||
|
pepSupport(false)
|
||||||
{
|
{
|
||||||
connect(acc->rm, &QXmppRosterManager::rosterReceived, this, &RosterHandler::onRosterReceived);
|
connect(acc->rm, &QXmppRosterManager::rosterReceived, this, &RosterHandler::onRosterReceived);
|
||||||
connect(acc->rm, &QXmppRosterManager::itemAdded, this, &RosterHandler::onRosterItemAdded);
|
connect(acc->rm, &QXmppRosterManager::itemAdded, this, &RosterHandler::onRosterItemAdded);
|
||||||
@ -51,8 +52,7 @@ Core::RosterHandler::~RosterHandler()
|
|||||||
|
|
||||||
void Core::RosterHandler::onRosterReceived()
|
void Core::RosterHandler::onRosterReceived()
|
||||||
{
|
{
|
||||||
acc->vm->requestClientVCard(); //TODO need to make sure server actually supports vCards
|
acc->requestVCard(acc->getBareJid()); //TODO need to make sure server actually supports vCards
|
||||||
acc->ownVCardRequestInProgress = true;
|
|
||||||
|
|
||||||
QStringList bj = acc->rm->getRosterBareJids();
|
QStringList bj = acc->rm->getRosterBareJids();
|
||||||
for (int i = 0; i < bj.size(); ++i) {
|
for (int i = 0; i < bj.size(); ++i) {
|
||||||
@ -588,4 +588,13 @@ void Core::RosterHandler::handleOffline()
|
|||||||
pair.second->clearArchiveRequests();
|
pair.second->clearArchiveRequests();
|
||||||
pair.second->downgradeDatabaseState();
|
pair.second->downgradeDatabaseState();
|
||||||
}
|
}
|
||||||
|
setPepSupport(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Core::RosterHandler::setPepSupport(bool support)
|
||||||
|
{
|
||||||
|
if (pepSupport != support) {
|
||||||
|
pepSupport = support;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,7 @@ public:
|
|||||||
|
|
||||||
void storeConferences();
|
void storeConferences();
|
||||||
void clearConferences();
|
void clearConferences();
|
||||||
|
void setPepSupport(bool support);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onRosterReceived();
|
void onRosterReceived();
|
||||||
@ -107,6 +108,7 @@ private:
|
|||||||
std::map<QString, std::set<QString>> groups;
|
std::map<QString, std::set<QString>> groups;
|
||||||
std::map<QString, QString> queuedContacts;
|
std::map<QString, QString> queuedContacts;
|
||||||
std::set<QString> outOfRosterContacts;
|
std::set<QString> outOfRosterContacts;
|
||||||
|
bool pepSupport;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
312
core/handlers/vcardhandler.cpp
Normal file
312
core/handlers/vcardhandler.cpp
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
// Squawk messenger.
|
||||||
|
// Copyright (C) 2019 Yury Gubich <blue@macaw.me>
|
||||||
|
//
|
||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "vcardhandler.h"
|
||||||
|
#include "core/account.h"
|
||||||
|
|
||||||
|
Core::VCardHandler::VCardHandler(Account* account):
|
||||||
|
QObject(),
|
||||||
|
acc(account),
|
||||||
|
ownVCardRequestInProgress(false),
|
||||||
|
pendingVCardRequests(),
|
||||||
|
avatarHash(),
|
||||||
|
avatarType()
|
||||||
|
{
|
||||||
|
connect(acc->vm, &QXmppVCardManager::vCardReceived, this, &VCardHandler::onVCardReceived);
|
||||||
|
//for some reason it doesn't work, launching from common handler
|
||||||
|
//connect(acc->vm, &QXmppVCardManager::clientVCardReceived, this, &VCardHandler::onOwnVCardReceived);
|
||||||
|
|
||||||
|
QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
|
||||||
|
path += "/" + acc->name;
|
||||||
|
QDir dir(path);
|
||||||
|
|
||||||
|
if (!dir.exists()) {
|
||||||
|
bool res = dir.mkpath(path);
|
||||||
|
if (!res) {
|
||||||
|
qDebug() << "Couldn't create a cache directory for account" << acc->name;
|
||||||
|
throw 22;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile* avatar = new QFile(path + "/avatar.png");
|
||||||
|
QString type = "png";
|
||||||
|
if (!avatar->exists()) {
|
||||||
|
delete avatar;
|
||||||
|
avatar = new QFile(path + "/avatar.jpg");
|
||||||
|
type = "jpg";
|
||||||
|
if (!avatar->exists()) {
|
||||||
|
delete avatar;
|
||||||
|
avatar = new QFile(path + "/avatar.jpeg");
|
||||||
|
type = "jpeg";
|
||||||
|
if (!avatar->exists()) {
|
||||||
|
delete avatar;
|
||||||
|
avatar = new QFile(path + "/avatar.gif");
|
||||||
|
type = "gif";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avatar->exists()) {
|
||||||
|
if (avatar->open(QFile::ReadOnly)) {
|
||||||
|
QCryptographicHash sha1(QCryptographicHash::Sha1);
|
||||||
|
sha1.addData(avatar);
|
||||||
|
avatarHash = sha1.result();
|
||||||
|
avatarType = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (avatarType.size() != 0) {
|
||||||
|
acc->presence.setVCardUpdateType(QXmppPresence::VCardUpdateValidPhoto);
|
||||||
|
acc->presence.setPhotoHash(avatarHash.toUtf8());
|
||||||
|
} else {
|
||||||
|
acc->presence.setVCardUpdateType(QXmppPresence::VCardUpdateNotReady);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::VCardHandler::~VCardHandler()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::VCardHandler::onVCardReceived(const QXmppVCardIq& card)
|
||||||
|
{
|
||||||
|
QString id = card.from();
|
||||||
|
QStringList comps = id.split("/");
|
||||||
|
QString jid = comps.front().toLower();
|
||||||
|
QString resource("");
|
||||||
|
if (comps.size() > 1) {
|
||||||
|
resource = comps.back();
|
||||||
|
}
|
||||||
|
pendingVCardRequests.erase(id);
|
||||||
|
RosterItem* item = acc->rh->getRosterItem(jid);
|
||||||
|
|
||||||
|
if (item == 0) {
|
||||||
|
if (jid == acc->getBareJid()) {
|
||||||
|
onOwnVCardReceived(card);
|
||||||
|
} else {
|
||||||
|
qDebug() << "received vCard" << jid << "doesn't belong to any of known contacts or conferences, skipping";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shared::VCard vCard = item->handleResponseVCard(card, resource);
|
||||||
|
|
||||||
|
emit acc->receivedVCard(jid, vCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::VCardHandler::onOwnVCardReceived(const QXmppVCardIq& card)
|
||||||
|
{
|
||||||
|
QByteArray ava = card.photo();
|
||||||
|
bool avaChanged = false;
|
||||||
|
QString path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + acc->name + "/";
|
||||||
|
if (ava.size() > 0) {
|
||||||
|
QCryptographicHash sha1(QCryptographicHash::Sha1);
|
||||||
|
sha1.addData(ava);
|
||||||
|
QString newHash(sha1.result());
|
||||||
|
QMimeDatabase db;
|
||||||
|
QMimeType newType = db.mimeTypeForData(ava);
|
||||||
|
if (avatarType.size() > 0) {
|
||||||
|
if (avatarHash != newHash) {
|
||||||
|
QString oldPath = path + "avatar." + avatarType;
|
||||||
|
QFile oldAvatar(oldPath);
|
||||||
|
bool oldToRemove = false;
|
||||||
|
if (oldAvatar.exists()) {
|
||||||
|
if (oldAvatar.rename(oldPath + ".bak")) {
|
||||||
|
oldToRemove = true;
|
||||||
|
} else {
|
||||||
|
qDebug() << "Received new avatar for account" << acc->name << "but can't get rid of the old one, doing nothing";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QFile newAvatar(path + "avatar." + newType.preferredSuffix());
|
||||||
|
if (newAvatar.open(QFile::WriteOnly)) {
|
||||||
|
newAvatar.write(ava);
|
||||||
|
newAvatar.close();
|
||||||
|
avatarHash = newHash;
|
||||||
|
avatarType = newType.preferredSuffix();
|
||||||
|
avaChanged = true;
|
||||||
|
} else {
|
||||||
|
qDebug() << "Received new avatar for account" << acc->name << "but can't save it";
|
||||||
|
if (oldToRemove) {
|
||||||
|
qDebug() << "rolling back to the old avatar";
|
||||||
|
if (!oldAvatar.rename(oldPath)) {
|
||||||
|
qDebug() << "Couldn't roll back to the old avatar in account" << acc->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QFile newAvatar(path + "avatar." + newType.preferredSuffix());
|
||||||
|
if (newAvatar.open(QFile::WriteOnly)) {
|
||||||
|
newAvatar.write(ava);
|
||||||
|
newAvatar.close();
|
||||||
|
avatarHash = newHash;
|
||||||
|
avatarType = newType.preferredSuffix();
|
||||||
|
avaChanged = true;
|
||||||
|
} else {
|
||||||
|
qDebug() << "Received new avatar for account" << acc->name << "but can't save it";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (avatarType.size() > 0) {
|
||||||
|
QFile oldAvatar(path + "avatar." + avatarType);
|
||||||
|
if (!oldAvatar.remove()) {
|
||||||
|
qDebug() << "Received vCard for account" << acc->name << "without avatar, but can't get rid of the file, doing nothing";
|
||||||
|
} else {
|
||||||
|
avatarType = "";
|
||||||
|
avatarHash = "";
|
||||||
|
avaChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avaChanged) {
|
||||||
|
QMap<QString, QVariant> change;
|
||||||
|
if (avatarType.size() > 0) {
|
||||||
|
acc->presence.setPhotoHash(avatarHash.toUtf8());
|
||||||
|
acc->presence.setVCardUpdateType(QXmppPresence::VCardUpdateValidPhoto);
|
||||||
|
change.insert("avatarPath", path + "avatar." + avatarType);
|
||||||
|
} else {
|
||||||
|
acc->presence.setPhotoHash("");
|
||||||
|
acc->presence.setVCardUpdateType(QXmppPresence::VCardUpdateNoPhoto);
|
||||||
|
change.insert("avatarPath", "");
|
||||||
|
}
|
||||||
|
acc->client.setClientPresence(acc->presence);
|
||||||
|
emit acc->changed(change);
|
||||||
|
}
|
||||||
|
|
||||||
|
ownVCardRequestInProgress = false;
|
||||||
|
|
||||||
|
Shared::VCard vCard;
|
||||||
|
initializeVCard(vCard, card);
|
||||||
|
|
||||||
|
if (avatarType.size() > 0) {
|
||||||
|
vCard.setAvatarType(Shared::Avatar::valid);
|
||||||
|
vCard.setAvatarPath(path + "avatar." + avatarType);
|
||||||
|
} else {
|
||||||
|
vCard.setAvatarType(Shared::Avatar::empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit acc->receivedVCard(acc->getBareJid(), vCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::VCardHandler::handleOffline()
|
||||||
|
{
|
||||||
|
pendingVCardRequests.clear();
|
||||||
|
Shared::VCard vCard; //just to show, that there is now more pending request
|
||||||
|
for (const QString& jid : pendingVCardRequests) {
|
||||||
|
emit acc->receivedVCard(jid, vCard); //need to show it better in the future, like with an error
|
||||||
|
}
|
||||||
|
pendingVCardRequests.clear();
|
||||||
|
ownVCardRequestInProgress = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::VCardHandler::requestVCard(const QString& jid)
|
||||||
|
{
|
||||||
|
if (pendingVCardRequests.find(jid) == pendingVCardRequests.end()) {
|
||||||
|
qDebug() << "requesting vCard" << jid;
|
||||||
|
if (jid == acc->getBareJid()) {
|
||||||
|
if (!ownVCardRequestInProgress) {
|
||||||
|
acc->vm->requestClientVCard();
|
||||||
|
ownVCardRequestInProgress = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
acc->vm->requestVCard(jid);
|
||||||
|
pendingVCardRequests.insert(jid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::VCardHandler::handleOtherPresenceOfMyAccountChange(const QXmppPresence& p_presence)
|
||||||
|
{
|
||||||
|
if (!ownVCardRequestInProgress) {
|
||||||
|
switch (p_presence.vCardUpdateType()) {
|
||||||
|
case QXmppPresence::VCardUpdateNone: //this presence has nothing to do with photo
|
||||||
|
break;
|
||||||
|
case QXmppPresence::VCardUpdateNotReady: //let's say the photo didn't change here
|
||||||
|
break;
|
||||||
|
case QXmppPresence::VCardUpdateNoPhoto: //there is no photo, need to drop if any
|
||||||
|
if (avatarType.size() > 0) {
|
||||||
|
acc->vm->requestClientVCard();
|
||||||
|
ownVCardRequestInProgress = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QXmppPresence::VCardUpdateValidPhoto: //there is a photo, need to load
|
||||||
|
if (avatarHash != p_presence.photoHash()) {
|
||||||
|
acc->vm->requestClientVCard();
|
||||||
|
ownVCardRequestInProgress = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::VCardHandler::uploadVCard(const Shared::VCard& card)
|
||||||
|
{
|
||||||
|
QXmppVCardIq iq;
|
||||||
|
initializeQXmppVCard(iq, card);
|
||||||
|
|
||||||
|
if (card.getAvatarType() != Shared::Avatar::empty) {
|
||||||
|
QString newPath = card.getAvatarPath();
|
||||||
|
QString oldPath = getAvatarPath();
|
||||||
|
QByteArray data;
|
||||||
|
QString type;
|
||||||
|
if (newPath != oldPath) {
|
||||||
|
QFile avatar(newPath);
|
||||||
|
if (!avatar.open(QFile::ReadOnly)) {
|
||||||
|
qDebug() << "An attempt to upload new vCard to account" << acc->name
|
||||||
|
<< "but it wasn't possible to read file" << newPath
|
||||||
|
<< "which was supposed to be new avatar, uploading old avatar";
|
||||||
|
if (avatarType.size() > 0) {
|
||||||
|
QFile oA(oldPath);
|
||||||
|
if (!oA.open(QFile::ReadOnly)) {
|
||||||
|
qDebug() << "Couldn't read old avatar of account" << acc->name << ", uploading empty avatar";
|
||||||
|
} else {
|
||||||
|
data = oA.readAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data = avatar.readAll();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (avatarType.size() > 0) {
|
||||||
|
QFile oA(oldPath);
|
||||||
|
if (!oA.open(QFile::ReadOnly)) {
|
||||||
|
qDebug() << "Couldn't read old avatar of account" << acc->name << ", uploading empty avatar";
|
||||||
|
} else {
|
||||||
|
data = oA.readAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.size() > 0) {
|
||||||
|
QMimeDatabase db;
|
||||||
|
type = db.mimeTypeForData(data).name();
|
||||||
|
iq.setPhoto(data);
|
||||||
|
iq.setPhotoType(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
acc->vm->setClientVCard(iq);
|
||||||
|
onOwnVCardReceived(iq);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Core::VCardHandler::getAvatarPath() const
|
||||||
|
{
|
||||||
|
if (avatarType.size() == 0) {
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + acc->name + "/" + "avatar." + avatarType;
|
||||||
|
}
|
||||||
|
}
|
65
core/handlers/vcardhandler.h
Normal file
65
core/handlers/vcardhandler.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Squawk messenger.
|
||||||
|
// Copyright (C) 2019 Yury Gubich <blue@macaw.me>
|
||||||
|
//
|
||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef CORE_VCARDHANDLER_H
|
||||||
|
#define CORE_VCARDHANDLER_H
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <QXmppVCardIq.h>
|
||||||
|
#include <QXmppPresence.h>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <shared/vcard.h>
|
||||||
|
#include <core/adapterfunctions.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo write docs
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
class Account;
|
||||||
|
|
||||||
|
class VCardHandler : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
VCardHandler(Account* account);
|
||||||
|
~VCardHandler();
|
||||||
|
|
||||||
|
void handleOffline();
|
||||||
|
void requestVCard(const QString& jid);
|
||||||
|
void handleOtherPresenceOfMyAccountChange(const QXmppPresence& p_presence);
|
||||||
|
void uploadVCard(const Shared::VCard& card);
|
||||||
|
QString getAvatarPath() const;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onVCardReceived(const QXmppVCardIq& card);
|
||||||
|
void onOwnVCardReceived(const QXmppVCardIq& card);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Account* acc;
|
||||||
|
|
||||||
|
bool ownVCardRequestInProgress;
|
||||||
|
std::set<QString> pendingVCardRequests;
|
||||||
|
QString avatarHash;
|
||||||
|
QString avatarType;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CORE_VCARDHANDLER_H
|
@ -35,6 +35,7 @@
|
|||||||
#include "shared/message.h"
|
#include "shared/message.h"
|
||||||
#include "shared/vcard.h"
|
#include "shared/vcard.h"
|
||||||
#include "archive.h"
|
#include "archive.h"
|
||||||
|
#include "adapterfunctions.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user