forked from blue/squawk
receiving account owner vCard, displaying avatars in roster
This commit is contained in:
parent
64e33b6139
commit
dc1ec1c9d4
13 changed files with 358 additions and 64 deletions
202
core/account.cpp
202
core/account.cpp
|
@ -41,7 +41,10 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
|||
maxReconnectTimes(0),
|
||||
reconnectTimes(0),
|
||||
queuedContacts(),
|
||||
outOfRosterContacts()
|
||||
outOfRosterContacts(),
|
||||
avatarHash(),
|
||||
avatarType(),
|
||||
ownVCardRequestInProgress(false)
|
||||
{
|
||||
config.setUser(p_login);
|
||||
config.setDomain(p_server);
|
||||
|
@ -81,6 +84,52 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
|||
|
||||
QXmppVCardManager& vm = client.vCardManager();
|
||||
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
|
||||
|
||||
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");
|
||||
QString type = "jpg";
|
||||
if (!avatar->exists()) {
|
||||
delete avatar;
|
||||
avatar = new QFile(path + "/avatar.jpeg");
|
||||
QString type = "jpeg";
|
||||
if (!avatar->exists()) {
|
||||
delete avatar;
|
||||
avatar = new QFile(path + "/avatar.gif");
|
||||
QString 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);
|
||||
}
|
||||
}
|
||||
|
||||
Account::~Account()
|
||||
|
@ -191,6 +240,9 @@ QString Core::Account::getServer() const
|
|||
|
||||
void Core::Account::onRosterReceived()
|
||||
{
|
||||
client.vCardManager().requestClientVCard(); //TODO need to make sure server actually supports vCards
|
||||
ownVCardRequestInProgress = true;
|
||||
|
||||
QXmppRosterManager& rm = client.rosterManager();
|
||||
QStringList bj = rm.getRosterBareJids();
|
||||
for (int i = 0; i < bj.size(); ++i) {
|
||||
|
@ -283,14 +335,15 @@ void Core::Account::addedAccount(const QString& jid)
|
|||
});
|
||||
|
||||
if (contact->hasAvatar()) {
|
||||
if (contact->isAvatarAutoGenerated()) {
|
||||
cData.insert("avatarType", static_cast<uint>(Shared::Avatar::valid));
|
||||
if (!contact->isAvatarAutoGenerated()) {
|
||||
cData.insert("avatarState", static_cast<uint>(Shared::Avatar::valid));
|
||||
} else {
|
||||
cData.insert("avatarType", static_cast<uint>(Shared::Avatar::autocreated));
|
||||
cData.insert("avatarState", static_cast<uint>(Shared::Avatar::autocreated));
|
||||
}
|
||||
cData.insert("avatarPath", contact->avatarPath());
|
||||
} else {
|
||||
cData.insert("avatarType", static_cast<uint>(Shared::Avatar::empty));
|
||||
cData.insert("avatarState", static_cast<uint>(Shared::Avatar::empty));
|
||||
cData.insert("avatarPath", "");
|
||||
client.vCardManager().requestVCard(jid);
|
||||
pendingVCardRequests.insert(jid);
|
||||
}
|
||||
|
@ -337,9 +390,9 @@ void Core::Account::handleNewConference(Core::Conference* contact)
|
|||
QObject::connect(contact, &Conference::removeParticipant, this, &Account::onMucRemoveParticipant);
|
||||
}
|
||||
|
||||
void Core::Account::onPresenceReceived(const QXmppPresence& presence)
|
||||
void Core::Account::onPresenceReceived(const QXmppPresence& p_presence)
|
||||
{
|
||||
QString id = presence.from();
|
||||
QString id = p_presence.from();
|
||||
QStringList comps = id.split("/");
|
||||
QString jid = comps.front();
|
||||
QString resource = comps.back();
|
||||
|
@ -348,16 +401,35 @@ void Core::Account::onPresenceReceived(const QXmppPresence& presence)
|
|||
|
||||
if (jid == myJid) {
|
||||
if (resource == getResource()) {
|
||||
emit availabilityChanged(presence.availableStatusType());
|
||||
emit availabilityChanged(p_presence.availableStatusType());
|
||||
} else {
|
||||
qDebug() << "Received a presence for another resource of my " << name << " account, skipping";
|
||||
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) {
|
||||
client.vCardManager().requestClientVCard();
|
||||
ownVCardRequestInProgress = true;
|
||||
}
|
||||
break;
|
||||
case QXmppPresence::VCardUpdateValidPhoto: //there is a photo, need to load
|
||||
if (avatarHash != p_presence.photoHash()) {
|
||||
client.vCardManager().requestClientVCard();
|
||||
ownVCardRequestInProgress = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (pendingVCardRequests.find(jid) == pendingVCardRequests.end()) {
|
||||
std::map<QString, Contact*>::const_iterator itr = contacts.find(jid);
|
||||
if (itr != contacts.end()) {
|
||||
Contact* cnt = itr->second;
|
||||
switch (presence.vCardUpdateType()) {
|
||||
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
|
||||
|
@ -373,7 +445,7 @@ void Core::Account::onPresenceReceived(const QXmppPresence& presence)
|
|||
client.vCardManager().requestVCard(jid);
|
||||
pendingVCardRequests.insert(jid);
|
||||
} else {
|
||||
if (cnt->avatarHash() != presence.photoHash()) {
|
||||
if (cnt->avatarHash() != p_presence.photoHash()) {
|
||||
client.vCardManager().requestVCard(jid);
|
||||
pendingVCardRequests.insert(jid);
|
||||
}
|
||||
|
@ -388,19 +460,19 @@ void Core::Account::onPresenceReceived(const QXmppPresence& presence)
|
|||
}
|
||||
}
|
||||
|
||||
switch (presence.type()) {
|
||||
switch (p_presence.type()) {
|
||||
case QXmppPresence::Error:
|
||||
qDebug() << "An error reported by presence from" << id << presence.error().text();
|
||||
qDebug() << "An error reported by presence from" << id << p_presence.error().text();
|
||||
break;
|
||||
case QXmppPresence::Available:{
|
||||
QDateTime lastInteraction = presence.lastUserInteraction();
|
||||
QDateTime lastInteraction = p_presence.lastUserInteraction();
|
||||
if (!lastInteraction.isValid()) {
|
||||
lastInteraction = QDateTime::currentDateTime();
|
||||
}
|
||||
emit addPresence(jid, resource, {
|
||||
{"lastActivity", lastInteraction},
|
||||
{"availability", presence.availableStatusType()}, //TODO check and handle invisible
|
||||
{"status", presence.statusText()}
|
||||
{"availability", p_presence.availableStatusType()}, //TODO check and handle invisible
|
||||
{"status", p_presence.statusText()}
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
@ -1267,7 +1339,11 @@ void Core::Account::onVCardReceived(const QXmppVCardIq& card)
|
|||
if (contItr == contacts.end()) {
|
||||
std::map<QString, Conference*>::const_iterator confItr = conferences.find(jid);
|
||||
if (confItr == conferences.end()) {
|
||||
qDebug() << "received vCard" << jid << "doesn't belong to any of known contacts or conferences, skipping";
|
||||
if (jid == getLogin() + "@" + getServer()) {
|
||||
onOwnVCardReceived(card);
|
||||
} else {
|
||||
qDebug() << "received vCard" << jid << "doesn't belong to any of known contacts or conferences, skipping";
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
item = confItr->second;
|
||||
|
@ -1284,15 +1360,99 @@ void Core::Account::onVCardReceived(const QXmppVCardIq& card)
|
|||
}
|
||||
}
|
||||
|
||||
void Core::Account::onOwnVCardReceived(const QXmppVCardIq& card)
|
||||
{
|
||||
QByteArray ava = card.photo();
|
||||
bool changed = 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();
|
||||
changed = 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();
|
||||
changed = 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 {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
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);
|
||||
}
|
||||
|
||||
ownVCardRequestInProgress = false;
|
||||
}
|
||||
|
||||
QString Core::Account::getAvatarPath() const
|
||||
{
|
||||
return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + name + "/" + "avatar." + avatarType;
|
||||
}
|
||||
|
||||
void Core::Account::onContactAvatarChanged(Shared::Avatar type, const QString& path)
|
||||
{
|
||||
RosterItem* item = static_cast<RosterItem*>(sender());
|
||||
QMap<QString, QVariant> cData({
|
||||
{"avatarType", static_cast<uint>(type)}
|
||||
{"avatarState", static_cast<uint>(type)},
|
||||
{"avatarPath", path}
|
||||
});
|
||||
if (type != Shared::Avatar::empty) {
|
||||
cData.insert("avatarPath", path);
|
||||
}
|
||||
|
||||
emit changeContact(item->jid, cData);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue