/* # 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); }