diff --git a/src/core/core.cpp b/src/core/core.cpp index 9dcf8dded..33ffda894 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -235,8 +235,7 @@ ToxCorePtr Core::makeToxCore(const QByteArray &savedata, const ICoreSettings * c void Core::onStarted() { - // TODO(sudden6): this assert should hold? - //assert(QThread::currentThread() == coreThread); + assert(QThread::currentThread() == coreThread); // One time initialization stuff // set GUI with user and statusmsg QString name = getUsername(); diff --git a/src/core/core.h b/src/core/core.h index 82b4c4d80..f91f33405 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -139,44 +139,18 @@ signals: void disconnected(); void friendRequestReceived(const ToxPk& friendPk, const QString& message); - void friendMessageReceived(uint32_t friendId, const QString& message, bool isAction); + void friendAvatarChanged(const ToxPk& friendPk, const QPixmap& pic); + void friendAvatarData(const ToxPk& friendPk, const QByteArray& data); + void friendAvatarRemoved(const ToxPk& friendPk); - void friendAdded(uint32_t friendId, const ToxPk& friendPk); void requestSent(const ToxPk& friendPk, const QString& message); - - void friendStatusChanged(uint32_t friendId, Status status); - void friendStatusMessageChanged(uint32_t friendId, const QString& message); - void friendUsernameChanged(uint32_t friendId, const QString& username); - void friendTypingChanged(uint32_t friendId, bool isTyping); - void friendAvatarChanged(uint32_t friendId, const QPixmap& pic); - void friendAvatarRemoved(uint32_t friendId); - - void friendRemoved(uint32_t friendId); - - void friendLastSeenChanged(uint32_t friendId, const QDateTime& dateTime); - - void emptyGroupCreated(int groupnumber); - void groupInviteReceived(const GroupInvite& inviteInfo); - void groupMessageReceived(int groupnumber, int peernumber, const QString& message, bool isAction); - void groupNamelistChanged(int groupnumber, int peernumber, uint8_t change); - void groupPeerlistChanged(int groupnumber); - void groupPeerNameChanged(int groupnumber, int peernumber, const QString& newName); - void groupTitleChanged(int groupnumber, const QString& author, const QString& title); - void groupPeerAudioPlaying(int groupnumber, int peernumber); + void failedToAddFriend(const ToxPk& friendPk, const QString& errorInfo = QString()); void usernameSet(const QString& username); void statusMessageSet(const QString& message); void statusSet(Status status); void idSet(const ToxId& id); - void messageSentResult(uint32_t friendId, const QString& message, int messageId); - void groupSentFailed(int groupId); - void actionSentResult(uint32_t friendId, const QString& action, int success); - - void receiptRecieved(int friedId, int receipt); - - void failedToAddFriend(const ToxPk& friendPk, const QString& errorInfo = QString()); - void failedToRemoveFriend(uint32_t friendId); void failedToSetUsername(const QString& username); void failedToSetStatusMessage(const QString& message); void failedToSetStatus(Status status); @@ -197,10 +171,45 @@ signals: void fileTransferBrokenUnbroken(ToxFile file, bool broken); void fileNameChanged(); - void fileSendFailed(uint32_t friendId, const QString& fname); - void saveRequest(); + /** + * @deprecated prefer signals using ToxPk + */ + + void fileAvatarOfferReceived(uint32_t friendId, uint32_t fileId, const QByteArray& avatarHash); + + void friendMessageReceived(uint32_t friendId, const QString& message, bool isAction); + void friendAdded(uint32_t friendId, const ToxPk& friendPk); + + void friendStatusChanged(uint32_t friendId, Status status); + void friendStatusMessageChanged(uint32_t friendId, const QString& message); + void friendUsernameChanged(uint32_t friendId, const QString& username); + void friendTypingChanged(uint32_t friendId, bool isTyping); + + void friendAvatarChangedDeprecated(uint32_t friendId, const QPixmap& pic); + void friendRemoved(uint32_t friendId); + void friendLastSeenChanged(uint32_t friendId, const QDateTime& dateTime); + + void emptyGroupCreated(int groupnumber); + void groupInviteReceived(const GroupInvite& inviteInfo); + void groupMessageReceived(int groupnumber, int peernumber, const QString& message, bool isAction); + void groupNamelistChanged(int groupnumber, int peernumber, uint8_t change); + void groupPeerlistChanged(int groupnumber); + void groupPeerNameChanged(int groupnumber, int peernumber, const QString& newName); + void groupTitleChanged(int groupnumber, const QString& author, const QString& title); + void groupPeerAudioPlaying(int groupnumber, int peernumber); + + void messageSentResult(uint32_t friendId, const QString& message, int messageId); + void groupSentFailed(int groupId); + void actionSentResult(uint32_t friendId, const QString& action, int success); + + void receiptRecieved(int friedId, int receipt); + + void failedToRemoveFriend(uint32_t friendId); + + void fileSendFailed(uint32_t friendId, const QString& fname); + private: Core(QThread* coreThread); diff --git a/src/core/corefile.cpp b/src/core/corefile.cpp index 9ffc14907..7beac749e 100644 --- a/src/core/corefile.cpp +++ b/src/core/corefile.cpp @@ -295,33 +295,17 @@ void CoreFile::onFileReceiveCallback(Tox*, uint32_t friendId, uint32_t fileId, u if (!filesize) { qDebug() << QString("Received empty avatar request %1:%2").arg(friendId).arg(fileId); // Avatars of size 0 means explicitely no avatar - emit core->friendAvatarRemoved(friendId); - // TODO(sudden6): use signal from above for that action - //core->profile.removeAvatar(friendPk); + emit core->friendAvatarRemoved(core->getFriendPublicKey(friendId)); return; } else { static_assert(TOX_HASH_LENGTH <= TOX_FILE_ID_LENGTH, "TOX_HASH_LENGTH > TOX_FILE_ID_LENGTH!"); uint8_t avatarHash[TOX_FILE_ID_LENGTH]; tox_file_get_file_id(core->tox, friendId, fileId, avatarHash, nullptr); - // TODO(sudden6): fix that condition below - if (/*core->profile.getAvatarHash(friendPk) - == QByteArray((char*)avatarHash, TOX_HASH_LENGTH)*/ false) { - // If it's an avatar but we already have it cached, cancel - qDebug() << QString( - "Received avatar request %1:%2, reject, since we have it in cache.") - .arg(friendId) - .arg(fileId); - tox_file_control(core->tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr); - return; - } else { - // It's an avatar and we don't have it, autoaccept the transfer - qDebug() << QString("Received avatar request %1:%2, accept, since we don't have it " - "in cache.") - .arg(friendId) - .arg(fileId); - tox_file_control(core->tox, friendId, fileId, TOX_FILE_CONTROL_RESUME, nullptr); - } + QByteArray avatarBytes{static_cast(static_cast(avatarHash)), + TOX_HASH_LENGTH}; + emit core->fileAvatarOfferReceived(friendId, fileId, avatarBytes); + return; } } else { const auto cleanFileName = CoreFile::getCleanFileName(filename.getQString()); @@ -344,6 +328,37 @@ void CoreFile::onFileReceiveCallback(Tox*, uint32_t friendId, uint32_t fileId, u if (kind != TOX_FILE_KIND_AVATAR) emit core->fileReceiveRequested(file); } + +// TODO(sudden6): This whole method is a mess but needed to get stuff working for now +void CoreFile::handleAvatarOffer(uint32_t friendId, uint32_t fileId, bool accept) +{ + // TODO(sudden6): evil evil evil + auto core = Core::getInstance(); + if (!accept) { + // If it's an avatar but we already have it cached, cancel + qDebug() << QString( + "Received avatar request %1:%2, reject, since we have it in cache.") + .arg(friendId) + .arg(fileId); + tox_file_control(core->tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr); + return; + } + + // It's an avatar and we don't have it, autoaccept the transfer + qDebug() << QString("Received avatar request %1:%2, accept, since we don't have it " + "in cache.") + .arg(friendId) + .arg(fileId); + tox_file_control(core->tox, friendId, fileId, TOX_FILE_CONTROL_RESUME, nullptr); + + ToxFile file{fileId, friendId, "", "", ToxFile::RECEIVING}; + file.filesize = 0; + file.fileKind = TOX_FILE_KIND_AVATAR; + file.resumeFileId.resize(TOX_FILE_ID_LENGTH); + tox_file_get_file_id(core->tox, friendId, fileId, (uint8_t*)file.resumeFileId.data(), nullptr); + addFile(friendId, fileId, file); +} + void CoreFile::onFileControlCallback(Tox*, uint32_t friendId, uint32_t fileId, TOX_FILE_CONTROL control, void* core) { @@ -448,11 +463,10 @@ void CoreFile::onFileRecvChunkCallback(Tox* tox, uint32_t friendId, uint32_t fil pic.loadFromData(file->avatarData); if (!pic.isNull()) { qDebug() << "Got" << file->avatarData.size() << "bytes of avatar data from" << friendId; - // TODO(sudden6): handle the action below with the signal - /* - core->profile.saveAvatar(file->avatarData, - core->getFriendPublicKey(friendId));*/ - emit core->friendAvatarChanged(friendId, pic); + emit core->friendAvatarData(core->getFriendPublicKey(friendId), file->avatarData); + emit core->friendAvatarChanged(core->getFriendPublicKey(friendId), pic); + // TODO(sudden6): signal below is deprecated + emit core->friendAvatarChangedDeprecated(friendId, pic); } } else { emit core->fileTransferFinished(*file); diff --git a/src/core/corefile.h b/src/core/corefile.h index 759cd2876..88b038964 100644 --- a/src/core/corefile.h +++ b/src/core/corefile.h @@ -39,6 +39,9 @@ class CoreFile { friend class Core; + +public: + static void handleAvatarOffer(uint32_t friendId, uint32_t fileId, bool accept); private: CoreFile() = delete; diff --git a/src/model/profile/profileinfo.cpp b/src/model/profile/profileinfo.cpp index b363e2ecd..2aa18dd8d 100644 --- a/src/model/profile/profileinfo.cpp +++ b/src/model/profile/profileinfo.cpp @@ -327,7 +327,7 @@ IProfileInfo::SetAvatarResult ProfileInfo::setAvatar(const QString &path) return SetAvatarResult::TooLarge; } - profile->setAvatar(bytes, core->getSelfPublicKey()); + profile->setAvatar(bytes); return SetAvatarResult::OK; } @@ -336,5 +336,5 @@ IProfileInfo::SetAvatarResult ProfileInfo::setAvatar(const QString &path) */ void ProfileInfo::removeAvatar() { - profile->removeAvatar(); + profile->removeSelfAvatar(); } diff --git a/src/persistence/profile.cpp b/src/persistence/profile.cpp index 3715a3109..f46c30821 100644 --- a/src/persistence/profile.cpp +++ b/src/persistence/profile.cpp @@ -32,6 +32,7 @@ #include "profilelocker.h" #include "settings.h" #include "src/core/core.h" +#include "src/core/corefile.h" #include "src/net/avatarbroadcaster.h" #include "src/nexus.h" #include "src/widget/gui.h" @@ -78,19 +79,16 @@ Profile::Profile(QString name, const QString& password, bool isNewProfile, const return; } - const ToxId& selfId = core->getSelfId(); - loadDatabase(selfId, password); - const ToxPk& selfPk = selfId.getPublicKey(); - QByteArray data = loadAvatarData(selfPk); - if (data.isEmpty()) { - qDebug() << "Self avatar not found, will broadcast empty avatar to friends"; - } - // save tox file when Core requests it connect(core.get(), &Core::saveRequest, this, &Profile::onSaveToxSave); + // react to avatar changes + connect(core.get(), &Core::friendAvatarRemoved, this, &Profile::removeAvatar); + connect(core.get(), &Core::friendAvatarData, this, &Profile::saveAvatar); + connect(core.get(), &Core::fileAvatarOfferReceived, this, &Profile::onAvatarOfferReceived, Qt::ConnectionType::BlockingQueuedConnection); + + const ToxId& selfId = core->getSelfId(); + loadDatabase(selfId, password); - // TODO(sudden6): check if needed - //setAvatar(data, selfPk); } /** @@ -298,6 +296,17 @@ QString Profile::getName() const void Profile::startCore() { core->start(); + + const ToxId& selfId = core->getSelfId(); + const ToxPk& selfPk = selfId.getPublicKey(); + QByteArray data = loadAvatarData(selfPk); + if (data.isEmpty()) { + qDebug() << "Self avatar not found, will broadcast empty avatar to friends"; + } + // TODO(sudden6): moved here, because it crashes in the constructor + // reason: Core::getInstance() returns nullptr, because it's not yet initialized + // solution: kill Core::getInstance + setAvatar(data); } bool Profile::isNewProfile() @@ -317,6 +326,14 @@ void Profile::onSaveToxSave() saveToxSave(data); } +// TODO(sudden6): handle this better maybe? +void Profile::onAvatarOfferReceived(uint32_t friendId, uint32_t fileId, const QByteArray &avatarHash) +{ + // accept if we don't have it already + const bool accept = getAvatarHash(core->getFriendPublicKey(friendId)) != avatarHash; + CoreFile::handleAvatarOffer(friendId, fileId, accept); +} + /** * @brief Write the .tox save, encrypted if needed. * @param data Byte array of profile save. @@ -474,26 +491,31 @@ void Profile::loadDatabase(const ToxId& id, QString password) } } -void Profile::setAvatar(QByteArray pic, const ToxPk& owner) +/** + * @brief Sets our own avatar + * @param pic Picture to use as avatar, if empty an Identicon will be used depending on settings + * @param owner + */ +void Profile::setAvatar(QByteArray pic) { QPixmap pixmap; QByteArray avatarData; + const ToxPk& selfPk = core->getSelfPublicKey(); if (!pic.isEmpty()) { pixmap.loadFromData(pic); avatarData = pic; } else { if (Settings::getInstance().getShowIdenticons()) { // with IDENTICON_ROWS=5 this gives a 160x160 image file - const QImage identicon = Identicon(owner.getKey()).toImage(32); + const QImage identicon = Identicon(selfPk.getKey()).toImage(32); pixmap = QPixmap::fromImage(identicon); } else { pixmap.load(":/img/contact_dark.svg"); } - } - saveAvatar(avatarData, owner); + saveAvatar(selfPk, avatarData); emit selfAvatarChanged(pixmap); AvatarBroadcaster::setAvatar(avatarData); @@ -523,7 +545,7 @@ void Profile::onRequestSent(const ToxPk& friendPk, const QString& message) * @param pic Picture to save. * @param owner PK of avatar owner. */ -void Profile::saveAvatar(QByteArray pic, const ToxPk& owner) +void Profile::saveAvatar(const ToxPk& owner, QByteArray pic) { if (encrypted && !pic.isEmpty()) { pic = passkey->encrypt(pic); @@ -560,7 +582,7 @@ QByteArray Profile::getAvatarHash(const ToxPk& owner) /** * @brief Removes our own avatar. */ -void Profile::removeAvatar() +void Profile::removeSelfAvatar() { removeAvatar(core->getSelfId().getPublicKey()); } @@ -592,7 +614,7 @@ void Profile::removeAvatar(const ToxPk& owner) { QFile::remove(avatarPath(owner)); if (owner == core->getSelfId().getPublicKey()) { - setAvatar({}, core->getSelfPublicKey()); + setAvatar({}); } } @@ -777,13 +799,13 @@ QString Profile::setPassword(const QString& newPassword) Nexus::getDesktopGUI()->reloadHistory(); QByteArray avatar = loadAvatarData(core->getSelfId().getPublicKey()); - saveAvatar(avatar, core->getSelfId().getPublicKey()); + saveAvatar(core->getSelfId().getPublicKey(), avatar); QVector friendList = core->getFriendList(); QVectorIterator i(friendList); while (i.hasNext()) { const ToxPk friendPublicKey = core->getFriendPublicKey(i.next()); - saveAvatar(loadAvatarData(friendPublicKey), friendPublicKey); + saveAvatar(friendPublicKey, loadAvatarData(friendPublicKey)); } return error; } diff --git a/src/persistence/profile.h b/src/persistence/profile.h index a05c3ba03..16bc6cda7 100644 --- a/src/persistence/profile.h +++ b/src/persistence/profile.h @@ -56,11 +56,9 @@ public: QPixmap loadAvatar(); QPixmap loadAvatar(const ToxPk& owner); QByteArray loadAvatarData(const ToxPk& owner); - void setAvatar(QByteArray pic, const ToxPk& owner); - void saveAvatar(QByteArray pic, const ToxPk& owner); + void setAvatar(QByteArray pic); QByteArray getAvatarHash(const ToxPk& owner); - void removeAvatar(const ToxPk& owner); - void removeAvatar(); + void removeSelfAvatar(); bool isHistoryEnabled(); History* getHistory(); @@ -88,7 +86,11 @@ public slots: private slots: void loadDatabase(const ToxId& id, QString password); + void saveAvatar(const ToxPk& owner, QByteArray pic); + void removeAvatar(const ToxPk& owner); void onSaveToxSave(); + // TODO(sudden6): use ToxPk instead of friendId + void onAvatarOfferReceived(uint32_t friendId, uint32_t fileId, const QByteArray& avatarHash); private: Profile(QString name, const QString& password, bool newProfile, const QByteArray& toxsave); diff --git a/src/video/groupnetcamview.cpp b/src/video/groupnetcamview.cpp index 71df2d01c..7c1770b3d 100644 --- a/src/video/groupnetcamview.cpp +++ b/src/video/groupnetcamview.cpp @@ -156,7 +156,7 @@ GroupNetCamView::GroupNetCamView(int group, QWidget* parent) setActive(); }); - connect(Core::getInstance(), &Core::friendAvatarChanged, this, + connect(Core::getInstance(), &Core::friendAvatarChangedDeprecated, this, &GroupNetCamView::friendAvatarChanged); selfVideoSurface->setText(Core::getInstance()->getUsername()); diff --git a/src/video/netcamview.cpp b/src/video/netcamview.cpp index 10a6f27e3..f3ba92bde 100644 --- a/src/video/netcamview.cpp +++ b/src/video/netcamview.cpp @@ -75,7 +75,7 @@ NetCamView::NetCamView(int friendId, QWidget* parent) connections += connect(Nexus::getProfile(), &Profile::selfAvatarChanged, [this](const QPixmap& pixmap) { selfVideoSurface->setAvatar(pixmap); }); - connections += connect(Core::getInstance(), &Core::friendAvatarChanged, + connections += connect(Core::getInstance(), &Core::friendAvatarChangedDeprecated, [this](int FriendId, const QPixmap& pixmap) { if (this->friendId == FriendId) videoSurface->setAvatar(pixmap); diff --git a/src/widget/form/chatform.cpp b/src/widget/form/chatform.cpp index f3d3747b7..3da9eef39 100644 --- a/src/widget/form/chatform.cpp +++ b/src/widget/form/chatform.cpp @@ -158,7 +158,8 @@ ChatForm::ChatForm(Friend* chatFriend, History* history) const Core* core = Core::getInstance(); connect(core, &Core::fileReceiveRequested, this, &ChatForm::onFileRecvRequest); - connect(core, &Core::friendAvatarChanged, this, &ChatForm::onAvatarChange); + // TODO(sudden6): update slot to new API + connect(core, &Core::friendAvatarChangedDeprecated, this, &ChatForm::onAvatarChange); connect(core, &Core::friendAvatarRemoved, this, &ChatForm::onAvatarRemoved); connect(core, &Core::fileSendStarted, this, &ChatForm::startFileSend); connect(core, &Core::fileSendFailed, this, &ChatForm::onFileSendFailed); @@ -690,9 +691,9 @@ void ChatForm::dropEvent(QDropEvent* ev) } } -void ChatForm::onAvatarRemoved(uint32_t friendId) +void ChatForm::onAvatarRemoved(const ToxPk& friendPk) { - if (friendId != f->getId()) { + if (friendPk != f->getPublicKey()) { return; } diff --git a/src/widget/form/chatform.h b/src/widget/form/chatform.h index 84790abd0..f12e731f6 100644 --- a/src/widget/form/chatform.h +++ b/src/widget/form/chatform.h @@ -73,7 +73,7 @@ public slots: void onAvStart(uint32_t friendId, bool video); void onAvEnd(uint32_t friendId, bool error); void onAvatarChange(uint32_t friendId, const QPixmap& pic); - void onAvatarRemoved(uint32_t friendId); + void onAvatarRemoved(const ToxPk &friendPk); void onFileNameChanged(); protected slots: diff --git a/src/widget/friendwidget.cpp b/src/widget/friendwidget.cpp index c3b0399a1..a1f8e4d56 100644 --- a/src/widget/friendwidget.cpp +++ b/src/widget/friendwidget.cpp @@ -418,9 +418,9 @@ void FriendWidget::resetEventFlags() f->setEventFlag(false); } -void FriendWidget::onAvatarChange(uint32_t friendId, const QPixmap& pic) +void FriendWidget::onAvatarChange(const ToxPk& friendPk, const QPixmap& pic) { - if (friendId != frnd->getId()) { + if (friendPk != frnd->getPublicKey()) { return; } @@ -428,9 +428,9 @@ void FriendWidget::onAvatarChange(uint32_t friendId, const QPixmap& pic) avatar->setPixmap(pic); } -void FriendWidget::onAvatarRemoved(uint32_t friendId) +void FriendWidget::onAvatarRemoved(const ToxPk& friendPk) { - if (friendId != frnd->getId()) { + if (friendPk != frnd->getPublicKey()) { return; } diff --git a/src/widget/friendwidget.h b/src/widget/friendwidget.h index fd82687b5..8ee013f21 100644 --- a/src/widget/friendwidget.h +++ b/src/widget/friendwidget.h @@ -19,6 +19,7 @@ #define FRIENDWIDGET_H #include "genericchatroomwidget.h" +#include "src/core/toxpk.h" class QPixmap; class MaskablePixmapWidget; @@ -45,8 +46,8 @@ signals: void contextMenuCalled(QContextMenuEvent* event); public slots: - void onAvatarChange(uint32_t friendId, const QPixmap& pic); - void onAvatarRemoved(uint32_t friendId); + void onAvatarChange(const ToxPk &friendPk, const QPixmap& pic); + void onAvatarRemoved(const ToxPk &friendPk); void onContextMenuCalled(QContextMenuEvent* event); protected: diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 0a725bf59..f15f0caec 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -1022,7 +1022,7 @@ void Widget::addFriend(uint32_t friendId, const ToxPk& friendPk) QPixmap avatar = Nexus::getProfile()->loadAvatar(friendPk); if (!avatar.isNull()) { friendForm->onAvatarChange(friendId, avatar); - widget->onAvatarChange(friendId, avatar); + widget->onAvatarChange(friendPk, avatar); } FilterCriteria filter = getFilterCriteria(); @@ -1284,7 +1284,7 @@ void Widget::addFriendDialog(const Friend* frnd, ContentDialog* dialog) QPixmap avatar = Nexus::getProfile()->loadAvatar(frnd->getPublicKey()); if (!avatar.isNull()) { - friendWidget->onAvatarChange(friendId, avatar); + friendWidget->onAvatarChange(frnd->getPublicKey(), avatar); } }