1
0
Fork 0
forked from blue/squawk

account refactoring, pep support discovery started

This commit is contained in:
Blue 2022-04-08 19:18:15 +03:00
parent 82d54ba4df
commit 69e0c88d8d
Signed by untrusted user: blue
GPG key ID: 9B203B252A63EE38
12 changed files with 588 additions and 394 deletions

View file

@ -41,13 +41,12 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
rcpm(new QXmppMessageReceiptManager()),
reconnectScheduled(false),
reconnectTimer(new QTimer),
avatarHash(),
avatarType(),
ownVCardRequestInProgress(false),
network(p_net),
passwordType(Shared::AccountPassword::plain),
pepSupport(false),
mh(new MessageHandler(this)),
rh(new RosterHandler(this))
rh(new RosterHandler(this)),
vh(new VCardHandler(this))
{
config.setUser(p_login);
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(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);
QObject::connect(um, &QXmppUploadRequestManager::slotReceived, mh, &MessageHandler::onUploadSlotReceived);
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);
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);
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::loadFileError, mh, &MessageHandler::onLoadFileError);
delete vh;
delete mh;
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
{
if (state == Shared::ConnectionState::connected) {
@ -325,32 +245,11 @@ void Core::Account::onPresenceReceived(const QXmppPresence& p_presence)
QString jid = comps.front().toLower();
QString resource = comps.back();
QString myJid = getLogin() + "@" + getServer();
if (jid == myJid) {
if (jid == getBareJid()) {
if (resource == getResource()) {
emit availabilityChanged(static_cast<Shared::Availability>(p_presence.availableStatusType()));
} else {
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) {
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;
}
}
vh->handleOtherPresenceOfMyAccountChange(p_presence);
}
} else {
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)
{
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);
}
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){
rh->removeRoomRequest(jid);}
@ -688,254 +720,3 @@ void Core::Account::renameContactRequest(const QString& jid, const QString& newN
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);}