/*
# Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
#
# This program is free software distributed under the GPL version 2.
# See http://openslx.org/COPYING
#
# If you have any feedback please consult http://openslx.org/feedback and
# send your suggestions, praise, or complaints to feedback@openslx.org
#
# General information about OpenSLX can be found at http://openslx.org/
# -----------------------------------------------------------------------------
# src/gui/serverFileTransfert.cpp
# This class manage any file transfert from and to server.
# -----------------------------------------------------------------------------
*/
#include "serverFileTransfert.h"
ServerFileTransfert::ServerFileTransfert(QWidget *parent):
QDialog(parent)
{
setupUi(this);
_file = NULL;
_socket = NULL;
connect(this, SIGNAL(finished(int)), this, SLOT(deleteLater()));
}
ServerFileTransfert::~ServerFileTransfert()
{
}
void ServerFileTransfert::sendFileToHost(QString host)
{
QString filename = QFileDialog::getOpenFileName(this, tr("Open File"),
QDir::homePath(), "");
if (filename == "")
{
reject();
return;
}
sendFileToHost(host, filename);
}
void ServerFileTransfert::sendFileToHost(QString host, QString filename)
{
// open file
_file = new QFile(filename);
_file->open(QIODevice::ReadOnly);
_bytesToWrite = _file->size();
div = 1 + _bytesToWrite / 1000000000; // bc. progressBar supports only int
// get host from backend
// gui
filenameLabel->setText(filename);
progressBar->setValue(0);
progressBar->setMaximum(_bytesToWrite/div);
labelB->setText(formatSize(_bytesToWrite));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(close()));
// open socket
_socket = new QTcpSocket();
_socket->connectToHost(host, 29481);
if (_socket->isOpen())
qDebug("connection open");
else
qDebug("connection closed");
qDebug("[%s] Remote host: %s", metaObject()->className(), qPrintable(host));
connect(_socket, SIGNAL(connected()), this, SLOT(sendHeader()));
connect(_socket, SIGNAL(disconnected()), this, SLOT(close()));
connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(error(QAbstractSocket::SocketError)));
qDebug("connect is set");
}
void ServerFileTransfert::receiveFileFromHost(QTcpSocket* socket)
{
_bytesToRead = 0;
_socket = socket;
connect(_socket, SIGNAL(readyRead()), this, SLOT(receiveHeader()));
connect(_socket, SIGNAL(disconnected()), this, SLOT(close()));
connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(error(QAbstractSocket::SocketError)));
qDebug("[%s] New Connection: %s", metaObject()->className(),
qPrintable(_socket->peerAddress().toString()));
}
void ServerFileTransfert::sendHeader()
{
qDebug("[%s] Sending header(1)...", metaObject()->className());
QFileInfo info(_file->fileName());
QString size = QString::number(_bytesToWrite);
QString header = "PVSMGR;" + info.fileName() + ";" + size + "\n";
_socket->write(header.toLocal8Bit());
connect(_socket, SIGNAL(readyRead()), this, SLOT(receiveAck()));
qDebug("[%s] Sending header...", metaObject()->className());
}
void ServerFileTransfert::receiveHeader()
{
// parse header
QString header = QString::fromUtf8(_socket->readLine());
QStringList args = header.split(";");
QString nick = args[0];
QString filename = args[1];
_bytesToRead = args[2].toLongLong();
div = 1 + _bytesToRead / 1000000000; // bc. progressBar supports only int
qDebug("[%s] Received header.", metaObject()->className());
// ask user
QMessageBox::StandardButton result = QMessageBox::question(0,
tr("PVS File Transfer"),tr("User '") + nick +
tr("' would like to send you a file: ") + filename +
" (" + formatSize(_bytesToRead) + ").",
QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok);
if (result != QMessageBox::Ok)
{
sendAck(false);
return;
}
// open file
QString saveAs = QFileDialog::getSaveFileName(this, tr("Open File"),
QDir::homePath() + QDir::separator() + filename, "");
if (saveAs == "")
{
sendAck(false);
return;
}
_file = new QFile(saveAs);
_file->open(QIODevice::WriteOnly);
// gui
filenameLabel->setText(saveAs);
progressBar->setValue(0);
progressBar->setMaximum(_bytesToRead/div);
labelB->setText(formatSize(_bytesToRead));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(close()));
sendAck(true);
show();
}
void ServerFileTransfert::sendAck(bool b)
{
disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveHeader()));
if (b)
{
QString ack = QString("ok\n");
_socket->write(ack.toUtf8());
qDebug("[%s] Sending ack...", metaObject()->className());
connect(_socket, SIGNAL(readyRead()), this, SLOT(receiveFile()));
}
else
{
QString ack = QString("no\n");
_socket->write(ack.toUtf8());
qDebug("[%s] Sending nack!!!", metaObject()->className());
close();
}
}
void ServerFileTransfert::receiveAck()
{
QString ack = QString::fromUtf8(_socket->readLine());
if (ack != "ok\n")
{
qDebug("[%s] Received nack!", metaObject()->className());
close();
return;
}
qDebug("[%s] Received ack.", metaObject()->className());
disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveAck()));
connect(_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(sendFile()));
this->show();
qDebug("[%s] Sending file...", metaObject()->className());
sendFile();
}
void ServerFileTransfert::sendFile()
{
if (_bytesToWrite == 0)
{
qDebug("[%s] Transfer completed.", metaObject()->className());
close(); // finished
}
else
{
qint64 bytesWritten = _socket->write(_file->read(1024)); // data left
_bytesToWrite -= bytesWritten;
progressBar->setValue(progressBar->value() + bytesWritten/div);
labelA->setText(formatSize(progressBar->value()*div));
}
}
void ServerFileTransfert::receiveFile()
{
qint64 bytesRead = _file->write(_socket->readAll());
_bytesToRead -= bytesRead;
progressBar->setValue(progressBar->value() + bytesRead/div);
labelA->setText(formatSize(progressBar->value()*div));
}
void ServerFileTransfert::close()
{
if (_file && _file->isOpen())
{
_file->close();
qDebug("[%s] File closed.", metaObject()->className());
}
if (_socket && _socket->isOpen())
{
disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveAck()));
disconnect(_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(sendFile()));
disconnect(_socket, SIGNAL(disconnected()), this, SLOT(close()));
disconnect(_socket, SIGNAL(connected()), this, SLOT(sendHeader()));
disconnect(_socket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(error(QAbstractSocket::SocketError)));
_socket->disconnectFromHost();
qDebug("[%s] Connection closed.", metaObject()->className());
}
disconnect(cancelButton, SIGNAL(clicked()), this, SLOT(close()));
if (_bytesToWrite == 0)
{
accept();
QMessageBox::information(0, tr("PVS - File Transfer"),
tr("File Transfer complete."));
}
else
{
reject();
QMessageBox::warning(0, tr("PVS - File Transfer"),
tr("File Transfer canceled!"));
}
}
void ServerFileTransfert::error(QAbstractSocket::SocketError error)
{
qDebug("[%s] Socket error: %i", metaObject()->className(), error);
close();
}
QString ServerFileTransfert::formatSize(qint64 size)
{
if (size >= 1000000000) // GB
return QString("%1GB").arg((qreal)size / 1000000000, 0, 'f',1);
else if (size >= 1000000) // MB
return QString("%1MB").arg((qreal)size / 1000000, 0, 'f',1);
else if (size >= 1000) // KB
return QString("%1KB").arg((qreal)size / 1000, 0, 'f',1);
else // B
return QString("%1B").arg((qreal)size, 0, 'f',1);
}