1
0
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:
tux3 2015-04-25 01:26:52 +02:00
parent cdf3d9f553
commit 9d3d17d05e
No known key found for this signature in database
GPG Key ID: 7E086DD661263264
4 changed files with 115 additions and 52 deletions

View File

@ -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

View File

@ -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);
} }
}

View 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);

View File

@ -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