mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Avatar sending on top of file transfers
This commit is contained in:
parent
cdf3d9f553
commit
9d3d17d05e
|
@ -484,39 +484,16 @@ void Core::onConnectionStatusChanged(Tox*/* tox*/, uint32_t friendId, TOX_CONNEC
|
||||||
if (friendStatus == Status::Offline)
|
if (friendStatus == Status::Offline)
|
||||||
{
|
{
|
||||||
static_cast<Core*>(core)->checkLastOnline(friendId);
|
static_cast<Core*>(core)->checkLastOnline(friendId);
|
||||||
|
|
||||||
/** TODO: Review file sending breaking/resuming
|
|
||||||
for (ToxFile& f : fileSendQueue)
|
|
||||||
{
|
|
||||||
if (f.friendId == friendId && f.status == ToxFile::TRANSMITTING)
|
|
||||||
{
|
|
||||||
f.status = ToxFile::BROKEN;
|
|
||||||
emit static_cast<Core*>(core)->fileTransferBrokenUnbroken(f, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (ToxFile& f : fileRecvQueue)
|
|
||||||
{
|
|
||||||
if (f.friendId == friendId && f.status == ToxFile::TRANSMITTING)
|
|
||||||
{
|
|
||||||
f.status = ToxFile::BROKEN;
|
|
||||||
emit static_cast<Core*>(core)->fileTransferBrokenUnbroken(f, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/**
|
QPixmap pic = Settings::getInstance().getSavedAvatar(static_cast<Core*>(core)->getSelfId().toString());
|
||||||
for (ToxFile& f : fileRecvQueue)
|
QByteArray bytes;
|
||||||
{
|
QBuffer buffer(&bytes);
|
||||||
if (f.friendId == friendId && f.status == ToxFile::BROKEN)
|
buffer.open(QIODevice::WriteOnly);
|
||||||
{
|
pic.save(&buffer, "PNG");
|
||||||
qDebug() << QString("Core::onConnectionStatusChanged: %1: resuming broken filetransfer from position: %2").arg(f.file->fileName()).arg(f.bytesSent);
|
buffer.close();
|
||||||
tox_file_control(static_cast<Core*>(core)->tox, friendId, f.fileNum, TOX_FILE_CONTROL_RESUME, nullptr);
|
CoreFile::sendAvatarFile(static_cast<Core*>(core), friendId, bytes);
|
||||||
emit static_cast<Core*>(core)->fileTransferBrokenUnbroken(f, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,8 +749,6 @@ void Core::setUsername(const QString& username)
|
||||||
|
|
||||||
void Core::setAvatar(const QByteArray& data)
|
void Core::setAvatar(const QByteArray& data)
|
||||||
{
|
{
|
||||||
/// TODO: Review this function, toxcore doesn't handle avatars anymore apparently. Good.
|
|
||||||
|
|
||||||
QPixmap pic;
|
QPixmap pic;
|
||||||
pic.loadFromData(data);
|
pic.loadFromData(data);
|
||||||
Settings::getInstance().saveAvatar(pic, getSelfId().toString());
|
Settings::getInstance().saveAvatar(pic, getSelfId().toString());
|
||||||
|
@ -783,7 +758,7 @@ void Core::setAvatar(const QByteArray& data)
|
||||||
// according to tox.h, we need not broadcast this ourselves, but initial testing indicated elsewise
|
// according to tox.h, we need not broadcast this ourselves, but initial testing indicated elsewise
|
||||||
const uint32_t friendCount = tox_self_get_friend_list_size(tox);
|
const uint32_t friendCount = tox_self_get_friend_list_size(tox);
|
||||||
for (unsigned i=0; i<friendCount; i++)
|
for (unsigned i=0; i<friendCount; i++)
|
||||||
;/// TODO: Send avatar info as a file
|
CoreFile::sendAvatarFile(this, i, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
ToxID Core::getSelfId() const
|
ToxID Core::getSelfId() const
|
||||||
|
|
|
@ -2,15 +2,41 @@
|
||||||
#include "corefile.h"
|
#include "corefile.h"
|
||||||
#include "corestructs.h"
|
#include "corestructs.h"
|
||||||
#include "src/misc/cstring.h"
|
#include "src/misc/cstring.h"
|
||||||
|
#include "src/misc/settings.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
#include <QDir>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
QMutex CoreFile::fileSendMutex;
|
QMutex CoreFile::fileSendMutex;
|
||||||
QHash<uint64_t, ToxFile> CoreFile::fileMap;
|
QHash<uint64_t, ToxFile> CoreFile::fileMap;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
void CoreFile::sendAvatarFile(Core* core, uint32_t friendId, const QByteArray& data)
|
||||||
|
{
|
||||||
|
QMutexLocker mlocker(&fileSendMutex);
|
||||||
|
|
||||||
|
uint8_t filename[TOX_HASH_LENGTH];
|
||||||
|
tox_hash(filename, (uint8_t*)data.data(), data.size());
|
||||||
|
uint64_t filesize = data.size();
|
||||||
|
uint32_t fileNum = tox_file_send(core->tox, friendId, TOX_FILE_KIND_AVATAR, filesize,
|
||||||
|
nullptr, filename, TOX_HASH_LENGTH, nullptr);
|
||||||
|
if (fileNum == UINT32_MAX)
|
||||||
|
{
|
||||||
|
qWarning() << "CoreFile::sendAvatarFile: Can't create the Tox file sender";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qDebug() << QString("CoreFile::sendAvatarFile: Created file sender %1 with friend %2").arg(fileNum).arg(friendId);
|
||||||
|
|
||||||
|
ToxFile file{fileNum, friendId, "", "", ToxFile::SENDING};
|
||||||
|
file.filesize = filesize;
|
||||||
|
file.fileName = QByteArray((char*)filename, TOX_HASH_LENGTH);
|
||||||
|
file.fileKind = TOX_FILE_KIND_AVATAR;
|
||||||
|
file.avatarData = data;
|
||||||
|
addFile(friendId, fileNum, file);
|
||||||
|
}
|
||||||
|
|
||||||
void CoreFile::sendFile(Core* core, uint32_t friendId, QString Filename, QString FilePath, long long filesize)
|
void CoreFile::sendFile(Core* core, uint32_t friendId, QString Filename, QString FilePath, long long filesize)
|
||||||
{
|
{
|
||||||
QMutexLocker mlocker(&fileSendMutex);
|
QMutexLocker mlocker(&fileSendMutex);
|
||||||
|
@ -175,18 +201,43 @@ void CoreFile::removeFile(uint32_t friendId, uint32_t fileId)
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreFile::onFileReceiveCallback(Tox*, uint32_t friendId, uint32_t fileId, uint32_t kind,
|
void CoreFile::onFileReceiveCallback(Tox*, uint32_t friendId, uint32_t fileId, uint32_t kind,
|
||||||
uint64_t filesize, const uint8_t *fname, size_t fnameLen, void *core)
|
uint64_t filesize, const uint8_t *fname, size_t fnameLen, void *_core)
|
||||||
{
|
{
|
||||||
|
Core* core = static_cast<Core*>(_core);
|
||||||
qDebug() << QString("CoreFile: Received file request %1:%2 kind %3")
|
qDebug() << QString("CoreFile: Received file request %1:%2 kind %3")
|
||||||
.arg(friendId).arg(fileId).arg(kind);
|
.arg(friendId).arg(fileId).arg(kind);
|
||||||
|
|
||||||
|
if (kind == TOX_FILE_KIND_AVATAR)
|
||||||
|
{
|
||||||
|
QString friendAddr = core->getFriendAddress(friendId);
|
||||||
|
if (!filesize)
|
||||||
|
{
|
||||||
|
// Avatars of size 0 means explicitely no avatar
|
||||||
|
emit core->friendAvatarRemoved(friendId);
|
||||||
|
QFile::remove(QDir(Settings::getSettingsDirPath()).filePath("avatars/"+friendAddr.left(64)+".png"));
|
||||||
|
QFile::remove(QDir(Settings::getSettingsDirPath()).filePath("avatars/"+friendAddr.left(64)+".hash"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (Settings::getInstance().getAvatarHash(friendAddr) == QByteArray((char*)fname, fnameLen))
|
||||||
|
{
|
||||||
|
// If it's an avatar but we already have it cached, cancel
|
||||||
|
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
|
||||||
|
tox_file_control(core->tox, friendId, fileId, TOX_FILE_CONTROL_RESUME, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ToxFile file{fileId, friendId,
|
ToxFile file{fileId, friendId,
|
||||||
CString::toString(fname,fnameLen).toUtf8(), "", ToxFile::RECEIVING};
|
CString::toString(fname,fnameLen).toUtf8(), "", ToxFile::RECEIVING};
|
||||||
file.filesize = filesize;
|
file.filesize = filesize;
|
||||||
file.fileKind = kind;
|
file.fileKind = kind;
|
||||||
addFile(friendId, fileId, file);
|
addFile(friendId, fileId, file);
|
||||||
if (kind == TOX_FILE_KIND_DATA)
|
if (kind != TOX_FILE_KIND_AVATAR)
|
||||||
emit static_cast<Core*>(core)->fileReceiveRequested(file);
|
emit core->fileReceiveRequested(file);
|
||||||
}
|
}
|
||||||
void CoreFile::onFileControlCallback(Tox*, uint32_t friendId, uint32_t fileId,
|
void CoreFile::onFileControlCallback(Tox*, uint32_t friendId, uint32_t fileId,
|
||||||
TOX_FILE_CONTROL control, void *core)
|
TOX_FILE_CONTROL control, void *core)
|
||||||
|
@ -238,15 +289,25 @@ void CoreFile::onFileDataCallback(Tox *tox, uint32_t friendId, uint32_t fileId,
|
||||||
if (!length)
|
if (!length)
|
||||||
{
|
{
|
||||||
qDebug("CoreFile::onFileDataCallback: File sending completed");
|
qDebug("CoreFile::onFileDataCallback: File sending completed");
|
||||||
|
if (file->fileKind != TOX_FILE_KIND_AVATAR)
|
||||||
emit static_cast<Core*>(core)->fileTransferFinished(*file);
|
emit static_cast<Core*>(core)->fileTransferFinished(*file);
|
||||||
removeFile(friendId, fileId);
|
removeFile(friendId, fileId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ptr<uint8_t[]> data(new uint8_t[length]);
|
unique_ptr<uint8_t[]> data(new uint8_t[length]);
|
||||||
|
int64_t nread;
|
||||||
|
|
||||||
|
if (file->fileKind == TOX_FILE_KIND_AVATAR)
|
||||||
|
{
|
||||||
|
QByteArray chunk = file->avatarData.mid(pos, length);
|
||||||
|
nread = chunk.size();
|
||||||
|
memcpy(data.get(), chunk.data(), nread);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
file->file->seek(pos);
|
file->file->seek(pos);
|
||||||
int64_t nread = file->file->read((char*)data.get(), length);
|
nread = file->file->read((char*)data.get(), length);
|
||||||
if (nread <= 0)
|
if (nread <= 0)
|
||||||
{
|
{
|
||||||
qWarning("CoreFile::onFileDataCallback: Failed to read from file");
|
qWarning("CoreFile::onFileDataCallback: Failed to read from file");
|
||||||
|
@ -256,12 +317,14 @@ void CoreFile::onFileDataCallback(Tox *tox, uint32_t friendId, uint32_t fileId,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
file->bytesSent += length;
|
file->bytesSent += length;
|
||||||
|
}
|
||||||
|
|
||||||
if (!tox_file_send_chunk(tox, friendId, fileId, pos, data.get(), nread, nullptr))
|
if (!tox_file_send_chunk(tox, friendId, fileId, pos, data.get(), nread, nullptr))
|
||||||
{
|
{
|
||||||
qWarning("CoreFile::onFileDataCallback: Failed to send data chunk");
|
qWarning("CoreFile::onFileDataCallback: Failed to send data chunk");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (file->fileKind != TOX_FILE_KIND_AVATAR)
|
||||||
emit static_cast<Core*>(core)->fileTransferInfo(*file);
|
emit static_cast<Core*>(core)->fileTransferInfo(*file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,17 +345,40 @@ void CoreFile::onFileRecvChunkCallback(Tox *tox, uint32_t friendId, uint32_t fil
|
||||||
{
|
{
|
||||||
/// TODO: Allow ooo receiving for non-stream transfers, with very careful checking
|
/// TODO: Allow ooo receiving for non-stream transfers, with very careful checking
|
||||||
qWarning("CoreFile::onFileRecvChunkCallback: Received a chunk out-of-order, aborting transfer");
|
qWarning("CoreFile::onFileRecvChunkCallback: Received a chunk out-of-order, aborting transfer");
|
||||||
|
if (file->fileKind != TOX_FILE_KIND_AVATAR)
|
||||||
emit static_cast<Core*>(core)->fileTransferCancelled(*file);
|
emit static_cast<Core*>(core)->fileTransferCancelled(*file);
|
||||||
tox_file_control(tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
|
tox_file_control(tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||||
removeFile(friendId, fileId);
|
removeFile(friendId, fileId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
file->bytesSent += length;
|
|
||||||
|
if (file->fileKind == TOX_FILE_KIND_AVATAR)
|
||||||
|
file->avatarData.append((char*)data, length);
|
||||||
|
else
|
||||||
file->file->write((char*)data,length);
|
file->file->write((char*)data,length);
|
||||||
//qDebug() << QString("CoreFile::onFileRecvChunkCallback: received %1/%2 bytes").arg(file->bytesSent).arg(file->filesize);
|
file->bytesSent += length;
|
||||||
|
|
||||||
if (file->bytesSent == file->filesize)
|
if (file->bytesSent == file->filesize)
|
||||||
emit static_cast<Core*>(core)->fileTransferFinished(*file);
|
{
|
||||||
|
if (file->fileKind == TOX_FILE_KIND_AVATAR)
|
||||||
|
{
|
||||||
|
QPixmap pic;
|
||||||
|
pic.loadFromData(file->avatarData);
|
||||||
|
if (!pic.isNull())
|
||||||
|
{
|
||||||
|
qDebug() << "Core: Got avatar data from" << static_cast<Core*>(core)->getFriendUsername(friendId);
|
||||||
|
Settings::getInstance().saveAvatar(pic, static_cast<Core*>(core)->getFriendAddress(friendId));
|
||||||
|
Settings::getInstance().saveAvatarHash(file->fileName, static_cast<Core*>(core)->getFriendAddress(friendId));
|
||||||
|
emit static_cast<Core*>(core)->friendAvatarChanged(friendId, pic);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
emit static_cast<Core*>(core)->fileTransferFinished(*file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (file->fileKind != TOX_FILE_KIND_AVATAR)
|
||||||
|
{
|
||||||
emit static_cast<Core*>(core)->fileTransferInfo(*file);
|
emit static_cast<Core*>(core)->fileTransferInfo(*file);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void sendFile(Core *core, uint32_t friendId, QString Filename, QString FilePath, long long filesize);
|
static void sendFile(Core *core, uint32_t friendId, QString Filename, QString FilePath, long long filesize);
|
||||||
|
static void sendAvatarFile(Core* core, uint32_t friendId, const QByteArray& data);
|
||||||
static void pauseResumeFileSend(Core* core, uint32_t friendId, uint32_t fileId);
|
static void pauseResumeFileSend(Core* core, uint32_t friendId, uint32_t fileId);
|
||||||
static void pauseResumeFileRecv(Core* core, uint32_t friendId, uint32_t fileId);
|
static void pauseResumeFileRecv(Core* core, uint32_t friendId, uint32_t fileId);
|
||||||
static void cancelFileSend(Core* core, uint32_t friendId, uint32_t fileId);
|
static void cancelFileSend(Core* core, uint32_t friendId, uint32_t fileId);
|
||||||
|
|
|
@ -78,6 +78,7 @@ struct ToxFile
|
||||||
FileStatus status;
|
FileStatus status;
|
||||||
FileDirection direction;
|
FileDirection direction;
|
||||||
QTimer* sendTimer;
|
QTimer* sendTimer;
|
||||||
|
QByteArray avatarData;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CORESTRUCTS_H
|
#endif // CORESTRUCTS_H
|
||||||
|
|
Loading…
Reference in New Issue
Block a user