Skip to content
This repository has been archived by the owner on Jun 11, 2020. It is now read-only.

Implement file send/receive function #85

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions projectfiles/QtCreator/TOX-Qt-GUI.pro
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ SOURCES += \
../../src/frienditemdelegate.cpp \
../../src/editablelabelwidget.cpp \
../../src/esclineedit.cpp \
../../src/copyableelidelabel.cpp
../../src/copyableelidelabel.cpp \
../../src/filetransferstate.cpp \

HEADERS += \
../../src/mainwindow.hpp \
Expand Down Expand Up @@ -135,7 +136,8 @@ HEADERS += \
../../src/frienditemdelegate.hpp \
../../src/editablelabelwidget.hpp \
../../src/esclineedit.hpp \
../../src/copyableelidelabel.hpp
../../src/copyableelidelabel.hpp \
../../src/filetransferstate.hpp

### ToxCore section. Please keep it alphabetical ###

Expand Down
Binary file added resources/icons/attach.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/resources.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@
<file>icons/arrow_redo.png</file>
<file>icons/arrow_undo.png</file>
<file>DejaVuSans.ttf</file>
<file>icons/attach.png</file>
</qresource>
</RCC>
90 changes: 88 additions & 2 deletions src/chatpagewidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <QSplitter>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QDebug>

ChatPageWidget::ChatPageWidget(int friendId, QWidget* parent) :
QWidget(parent), friendId(friendId)
Expand All @@ -42,15 +43,25 @@ ChatPageWidget::ChatPageWidget(int friendId, QWidget* parent) :
emoticonButton = new QToolButton(inputPanel);
emoticonButton->setPopupMode(QToolButton::InstantPopup);
emoticonButton->setIcon(QIcon(":/icons/emoticons/emotion_smile.png"));
emoticonButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
emoticonButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
emoticonButton->setMenu(menu);
connect(menu, &EmoticonMenu::insertEmoticon, input, &InputTextWidget::insertHtml);

filesendButton = new QToolButton(this);
filesendButton->setIcon(QIcon(":/icons/attach.png"));
filesendButton->setToolTip(tr("Send file"));
filesendButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
connect(filesendButton, &QToolButton::clicked, this, &ChatPageWidget::promptSendFile);

QVBoxLayout *buttonlayout = new QVBoxLayout();
buttonlayout->addWidget(emoticonButton);
buttonlayout->addWidget(filesendButton);

QHBoxLayout *inputLayout = new QHBoxLayout(inputPanel);
inputLayout->setContentsMargins(0,0,0,0);
inputLayout->setSpacing(2);
inputLayout->addWidget(input);
inputLayout->addWidget(emoticonButton);
inputLayout->addLayout(buttonlayout);

QSplitter* splitter = new QSplitter(this);
splitter->setOrientation(Qt::Vertical);
Expand Down Expand Up @@ -109,3 +120,78 @@ void ChatPageWidget::actionSentResult(const QString &message)
{
display->appendAction(username, message, true);
}

quint8 ChatPageWidget::fileSendReceived(quint8 filenumber, quint64 filesize, const QString& filename)
{
QMessageBox::StandardButton ret = QMessageBox::question(this,
tr("File Transfer"),
tr("%1 is sending you a file `%2', accept?").arg(username).arg(filename));

quint8 msg_id = TOX_FILECONTROL_KILL;

if (ret == QMessageBox::Yes) {
QString saveFilename = QFileDialog::getSaveFileName(this,
tr("Save file"), filename);

if (!FileTransferState::checkPermission(saveFilename)) {
QMessageBox::critical(this, tr("Error"),
tr("Failed to open `%1' for writing").arg(saveFilename));
} else {
FileTransferState* state = new FileTransferState(friendId, filenumber,
filesize, saveFilename);
states.insert(filenumber, state);
display->appendProgress(saveFilename, state, false);
msg_id = TOX_FILECONTROL_ACCEPT;
}
}
return msg_id;
}

void ChatPageWidget::fileControlReceived(unsigned int receive_send, quint8 filenumber, quint8 control_type, const QByteArray& data)
{
if (receive_send == 0 && control_type == TOX_FILECONTROL_FINISHED) {
FileTransferState* state = states[filenumber];
states.remove(filenumber);
delete state;
} else if (receive_send == 1 && control_type == TOX_FILECONTROL_ACCEPT) {
FileTransferState* state = new FileTransferState(friendId, filenumber,
QFileInfo(currentSendFilename).size(), currentSendFilename,
FileTransferState::SEND);
states.insert(filenumber, state);
display->appendProgress(currentSendFilename, state, true);
emit sendFile(state);
}
}

void ChatPageWidget::fileDataReceived(quint8 filenumber, const QByteArray& data)
{
FileTransferState* state = states[filenumber];
if (state->writeData(data) == -1) {
QMessageBox::critical(this, tr("Error"),
tr("failed to write data for `%1'").arg(state->fileName()));
states.remove(filenumber);
delete state;
}
}

void ChatPageWidget::fileSendCompletedReceived(int filenumber)
{
FileTransferState* state = states[filenumber];
states.remove(filenumber);
delete state;
}

void ChatPageWidget::promptSendFile(void)
{
QString filename = QFileDialog::getOpenFileName(this, tr("Select a file"));
if (filename.length()) {
if (!FileTransferState::checkPermission(filename,
FileTransferState::SEND)) {
QMessageBox::critical(this, tr("Error"),
tr("Failed to open `%1' for reading").arg(filename));
} else {
currentSendFilename = filename;
emit sendFileRequest(filename);
}
}
}
17 changes: 16 additions & 1 deletion src/chatpagewidget.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@

#include "frienditemwidget.hpp"
#include "inputtextwidget.hpp"
#include "filetransferstate.hpp"

#include <tox.h>

#include <QFileDialog>
#include <QMap>
#include <QMessageBox>
#include <QTextBrowser>
#include <QTextEdit>
#include <QWidget>
Expand All @@ -40,24 +46,33 @@ class ChatPageWidget : public QWidget
private:
FriendItemWidget* friendItem;
MessageDisplayWidget *display;
QMap<quint8, FileTransferState*> states;

InputTextWidget* input;
QToolButton *filesendButton;
QToolButton *emoticonButton;

int friendId;
QString username;
Status status;
QString currentSendFilename;

public slots:
void messageReceived(const QString& message);
void messageSentResult(const QString& message, int messageId);
void actionReceived(const QString& message);
void actionSentResult(const QString& message);
quint8 fileSendReceived(quint8 filenumber, quint64 filesize, const QString& filename);
void fileControlReceived(unsigned int receive_send, quint8 filenumber, quint8 control_type, const QByteArray& data);
void fileDataReceived(quint8 filenumber, const QByteArray& data);
void fileSendCompletedReceived(int filenumber);
void promptSendFile(void);

signals:
void sendMessage(const QString& message);
void sendAction(const QString& action);

void sendFile(FileTransferState* state);
void sendFileRequest(const QString& filename);
};

#endif // CHATPAGEWIDGET_HPP
80 changes: 78 additions & 2 deletions src/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

#include <QThread>
#include <QTime>
#include <QFileInfo>
#include <QDebug>
#include <unistd.h>

Core::Core() :
tox(nullptr)
Expand All @@ -37,12 +40,12 @@ Core::~Core()

void Core::onFriendRequest(uint8_t* cUserId, uint8_t* cMessage, uint16_t cMessageSize, void* core)
{
emit static_cast<Core*>(core)->friendRequestRecieved(CUserId::toString(cUserId), CString::toString(cMessage, cMessageSize));
emit static_cast<Core*>(core)->friendRequestReceived(CUserId::toString(cUserId), CString::toString(cMessage, cMessageSize));
}

void Core::onFriendMessage(Tox*/* tox*/, int friendId, uint8_t* cMessage, uint16_t cMessageSize, void* core)
{
emit static_cast<Core*>(core)->friendMessageRecieved(friendId, CString::toString(cMessage, cMessageSize));
emit static_cast<Core*>(core)->friendMessageReceived(friendId, CString::toString(cMessage, cMessageSize));
}

void Core::onFriendNameChange(Tox*/* tox*/, int friendId, uint8_t* cName, uint16_t cNameSize, void* core)
Expand Down Expand Up @@ -85,6 +88,20 @@ void Core::onAction(Tox*/* tox*/, int friendId, uint8_t *cMessage, uint16_t cMes
emit static_cast<Core*>(core)->actionReceived(friendId, CString::toString(cMessage, cMessageSize));
}

void Core::onFileSendRequest(Tox*, int friendId, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *core)
{
emit static_cast<Core*>(core)->fileSendRequestReceived(friendId, filenumber, filesize, CString::toString(filename, filename_length));
}
void Core::onFileControl(Tox*, int friendId, uint8_t receive_send, uint8_t filenumber, uint8_t control_type, uint8_t *data, uint16_t length, void *core)
{
emit static_cast<Core*>(core)->fileControlReceived(friendId, receive_send, filenumber, control_type, QByteArray((const char*)data, length));
}

void Core::onFileData(Tox*, int friendId, uint8_t filenumber, uint8_t *data, uint16_t length, void *core)
{
emit static_cast<Core*>(core)->fileDataReceived(friendId, filenumber, QByteArray((const char*)data, length));
}

void Core::acceptFriendRequest(const QString& userId)
{
int friendId = tox_add_friend_norequest(tox, CUserId(userId).data());
Expand Down Expand Up @@ -188,13 +205,52 @@ void Core::bootstrapDht()
void Core::process()
{
tox_do(tox);
sendFiles();
#ifdef DEBUG
//we want to see the debug messages immediately
fflush(stdout);
#endif
checkConnection();
}

void Core::sendFiles()
{
for (QList<FileTransferState*>::iterator it = fileSenders.begin();
it != fileSenders.end();) {

FileTransferState* state = *it;
int len = 0;
char* buf = state->buffer();
int chunk_size = state->chunkSize();
int fn = state->fileNumber();
int fid = state->friendId();
bool completed = false;

while (true) {
len = state->readData(buf, chunk_size);

if (len == 0) {
tox_file_send_control(tox, fid, 0, fn,
TOX_FILECONTROL_FINISHED, NULL, 0);
completed = true;
break;
} else {
if (tox_file_send_data(tox, fid, fn, (uint8_t*)buf, len)) {
break;
}
state->readComplete();
}
}

if (completed) {
emit fileSendCompleted(fid, fn);
fileSenders.erase(it++);
} else {
it++;
}
}
}

void Core::checkConnection()
{
static bool isConnected = false;
Expand Down Expand Up @@ -224,6 +280,9 @@ void Core::start()
tox_callback_status_message(tox, onStatusMessageChanged, this);
tox_callback_user_status(tox, onUserStatusChanged, this);
tox_callback_connection_status(tox, onConnectionStatusChanged, this);
tox_callback_file_send_request(tox, onFileSendRequest, this);
tox_callback_file_control(tox, onFileControl, this);
tox_callback_file_data(tox, onFileData, this);

uint8_t friendAddress[TOX_FRIEND_ADDRESS_SIZE];
tox_get_address(tox, friendAddress);
Expand All @@ -242,6 +301,23 @@ void Core::start()
timer->start();
}

void Core::fileSendRequest(int friendId, const QString& filename)
{
tox_new_file_sender(tox, friendId, QFileInfo(filename).size(),
(uint8_t*)(const char*)filename.toUtf8(), filename.length() + 1);
}

void Core::sendFile(int friendId, FileTransferState* state)
{
int chunk_size = tox_file_data_size(tox, friendId);
state->createBuf(chunk_size);
fileSenders.append(state);
}

void Core::fileSendReply(int friendId, quint8 filenumber, quint8 message_id)
{
tox_file_send_control(tox, friendId, 1, filenumber, message_id, NULL, 0);
}

// CData

Expand Down
21 changes: 18 additions & 3 deletions src/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define CORE_HPP

#include "status.hpp"
#include "filetransferstate.hpp"

#include <tox.h>

Expand All @@ -40,11 +41,15 @@ class Core : public QObject
static void onUserStatusChanged(Tox* tox, int friendId, TOX_USERSTATUS userstatus, void* core);
static void onConnectionStatusChanged(Tox* tox, int friendId, uint8_t status, void* core);
static void onAction(Tox* tox, int friendId, uint8_t* cMessage, uint16_t cMessageSize, void* core);
static void onFileSendRequest(Tox *m, int, uint8_t, uint64_t, uint8_t *, uint16_t, void *);
static void onFileControl(Tox *m, int, uint8_t, uint8_t, uint8_t, uint8_t *, uint16_t, void *);
static void onFileData(Tox *m, int, uint8_t, uint8_t *, uint16_t length, void *);

void checkConnection();

Tox* tox;
QTimer* timer;
QList<FileTransferState*> fileSenders;

class CData
{
Expand All @@ -55,7 +60,6 @@ class Core : public QObject
protected:
explicit CData(const QString& data, uint16_t byteSize);
virtual ~CData();

static QString toString(uint8_t* cData, uint16_t cDataSize);

private:
Expand Down Expand Up @@ -127,15 +131,21 @@ public slots:
void setStatus(Status status);

void process();
void sendFiles();

void bootstrapDht();

void fileSendRequest(int friendId, const QString& filename);
void sendFile(int friendId, FileTransferState* state);
void fileSendReply(int friendId, quint8 filenumber, quint8 message_id);


signals:
void connected();
void disconnected();

void friendRequestRecieved(const QString& userId, const QString& message);
void friendMessageRecieved(int friendId, const QString& message);
void friendRequestReceived(const QString& userId, const QString& message);
void friendMessageReceived(int friendId, const QString& message);

void friendAdded(int friendId, const QString& userId);

Expand All @@ -162,6 +172,11 @@ public slots:

void failedToStart();

void fileSendRequestReceived(int friendId, quint8 filenumber, quint64 filesize, const QString& filename);
void fileControlReceived(int friendId, unsigned int receive_send, quint8 filenumber, quint8 control_type, const QByteArray& data);
void fileDataReceived(int friendId, quint8 filenumber, const QByteArray& data);

void fileSendCompleted(int friendId, int filenumber);
};

#endif // CORE_HPP
Expand Down
Loading