Browse Source

initial commit

master
Oliver Groß 12 years ago
commit
40a3dd027f
  1. 9
      .gitignore
  2. 87
      cconnectiondialog.cpp
  3. 55
      cconnectiondialog.h
  4. 63
      common.h
  5. 169
      crecievethread.cpp
  6. 64
      crecievethread.h
  7. 217
      csendthread.cpp
  8. 61
      csendthread.h
  9. 113
      csocketmanager.cpp
  10. 63
      csocketmanager.h
  11. 291
      ctransfermanager.cpp
  12. 110
      ctransfermanager.h
  13. 75
      ctransferthread.cpp
  14. 50
      ctransferthread.h
  15. 425
      cworker.cpp
  16. 80
      cworker.h
  17. 51
      main.cpp
  18. 22
      qftrans.pro
  19. 111
      qtransferlistmodel.cpp
  20. 46
      qtransferlistmodel.h

9
.gitignore

@ -0,0 +1,9 @@
Makefile
Doxyfile
*.kdevelop
*.kdevelop.pcs
*.kdevses
*~
mumodel
build
ui

87
cconnectiondialog.cpp

@ -0,0 +1,87 @@
/***************************************************************************
* Copyright (C) 2008 by Oliver Groß *
* z.o.gross@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "cconnectiondialog.h"
#include <QDialogButtonBox>
#include <QLabel>
#include <QLineEdit>
#include <QSpinBox>
#include <QFormLayout>
#include <QVBoxLayout>
#include <QMessageBox>
namespace qftrans {
CConnectionDialog::CConnectionDialog(QWidget * parent, Qt::WindowFlags f) : QDialog(parent, f) {
setupUi();
}
CConnectionDialog::~CConnectionDialog() {
}
bool CConnectionDialog::execute(bool isServer) {
m_HostEdit->setEnabled(!isServer);
m_HostLabel->setEnabled(!isServer);
if (m_HostEdit->text().isEmpty())
m_HostEdit->setText("localhost");
return exec();
}
QString CConnectionDialog::host() { return m_HostEdit->text(); }
quint16 CConnectionDialog::port() { return (quint16)m_PortEdit->value(); }
inline void CConnectionDialog::setupUi() {
m_HostEdit = new QLineEdit(this);
m_HostLabel = new QLabel(tr("&Host"), this);
m_HostLabel->setBuddy(m_HostEdit);
m_PortEdit = new QSpinBox(this);
m_PortEdit->setMinimum(0);
m_PortEdit->setMaximum(65535);
m_PortEdit->setValue(8899);
m_PortLabel = new QLabel(tr("&Port"), this);
m_PortLabel->setBuddy(m_PortLabel);
QDialogButtonBox * buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
QFormLayout * formLayout = new QFormLayout();
formLayout->addRow(m_HostLabel, m_HostEdit);
formLayout->addRow(m_PortLabel, m_PortEdit);
QVBoxLayout * mainLayout = new QVBoxLayout();
mainLayout->addLayout(formLayout);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(checkHost()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}
void CConnectionDialog::checkHost() {
if (m_HostEdit->isEnabled()) {
if (m_HostEdit->text().isEmpty())
QMessageBox::warning(this, tr("Invalid host"), tr("You have to specify a host name/address."));
else
accept();
}
else
accept();
}
}

55
cconnectiondialog.h

@ -0,0 +1,55 @@
/***************************************************************************
* Copyright (C) 2008 by Oliver Groß *
* z.o.gross@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef QFTRANSCCONNECTIONDIALOG_H
#define QFTRANSCCONNECTIONDIALOG_H
#include <QDialog>
class QLineEdit;
class QSpinBox;
class QLabel;
namespace qftrans {
/**
@author Oliver Groß <z.o.gross@gmx.de>
*/
class CConnectionDialog : public QDialog {
Q_OBJECT
public:
CConnectionDialog(QWidget * parent = 0, Qt::WindowFlags f = 0);
~CConnectionDialog();
bool execute(bool isServer);
QString host();
quint16 port();
private:
QLabel * m_HostLabel;
QLabel * m_PortLabel;
QLineEdit * m_HostEdit;
QSpinBox * m_PortEdit;
inline void setupUi();
private slots:
void checkHost();
};
}
#endif

63
common.h

@ -0,0 +1,63 @@
/***************************************************************************
* Copyright (C) 2008 by Oliver Groß *
* z.o.gross@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <QList>
#include <QHash>
#ifndef QFTRANS_COMMON_H
#define QFTRANS_COMMON_H
#define RAWPACKET_SIZE 9
#define DATA_BLOCK_SIZE 256
#define DESCRIPTOR_STRING "QFTH"
namespace qftrans {
enum TransferStatus {TS_WAITING = 0, TS_ANNOUNCING = 1, TS_TRANSFERING = 2, TS_CLOSING = 3, TS_FINISHED = 4};
enum HeaderType {HT_ID = 0, HT_SIZE = 1, HT_NAME = 2, HT_DATA = 3, HT_CLOSE = 4, HT_ACK = 5, HT_CANCEL = 6};
struct TransferData {
QString fileDir;
QString fileName;
TransferStatus status;
bool localFile;
qint64 size;
qint64 transfered;
HeaderType lastHeader;
};
struct TransferHeader {
char descriptor[5];
quint8 type;
quint32 id;
quint32 length;
TransferHeader() {
descriptor[0] = 'Q';
descriptor[1] = 'F';
descriptor[2] = 'T';
descriptor[3] = 'H';
descriptor[4] = 0;
}
};
typedef QList<TransferData *> QTransferDataList;
typedef QHash<quint32, TransferData *> QTransferDataHash;
typedef QHash<TransferData *, quint32> QTransferIdHash;
}
#endif

169
crecievethread.cpp

@ -0,0 +1,169 @@
/***************************************************************************
* Copyright (C) 2008 by Oliver Groß *
* z.o.gross@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "crecievethread.h"
#include <QTcpSocket>
#include <QByteArray>
#include <QDataStream>
#include <QFile>
#include <QDir>
namespace qftrans {
CRecieveThread::CRecieveThread(QString & destinationDir, QTcpSocket * socket, QObject * parent) :
QThread(parent), m_Socket(socket), m_DestinationDir(destinationDir)
{
}
CRecieveThread::~CRecieveThread() {
}
void CRecieveThread::setDestinationDir(QString & value) {
m_DestinationDir = value;
}
// TODO removeDownload(...)
void CRecieveThread::removeDownload(TransferData * /*data*/) {
}
void CRecieveThread::readData() {
QDataStream in(m_Socket);
in.setVersion(QDataStream::Qt_4_0);
if (m_Socket->bytesAvailable() >= (qint64)(sizeof(TransferHeader))) {
in.readRawData((char *)(&m_LastHeader), sizeof(TransferHeader));
m_LastHeaderValid = (qstrcmp(m_LastHeader.descriptor, DESCRIPTOR_STRING) == 0);
qDebug() << "got header" << m_LastHeader.type;
if (m_LastHeaderValid)
qDebug() << "valid";
else
qDebug() << "invalid";
qDebug() << "id" << m_LastHeader.id;
qDebug() << "length" << m_LastHeader.length;
}
else
m_LastHeaderValid = false;
TransferData * target = NULL;
while (m_LastHeaderValid) {
qDebug() << "available Bytes" << m_Socket->bytesAvailable();
if (m_Socket->bytesAvailable() >= m_LastHeader.length) {
//look for existing id
if (m_LastHeader.type == HT_ACK) {
qDebug() << "got HT_ACK .. requesting to start upload";
emit uploadStartRequest(m_LastHeader.id);
}
else {
if (m_DataDict.contains(m_LastHeader.id)) {
if (m_LastHeader.type == HT_CLOSE) {
//finished or canceled by peer
qDebug() << "download closed py peer";
emit downloadRemoved(m_DataDict.take(m_LastHeader.id));
}
else
//assign target
target = m_DataDict[m_LastHeader.id];
}
//id not in dict
else if (m_LastHeader.type == HT_ID) {
//new file announced
qDebug() << "download announced";
TransferData * newFile = new TransferData;
m_DataDict.insert(m_LastHeader.id, newFile);
newFile->transfered = 0;
newFile->size = 0;
newFile->localFile = false;
newFile->status = TS_WAITING;
newFile->fileDir = m_DestinationDir;
}
//check valid target and data available
if (target && m_LastHeader.length) {
switch (m_LastHeader.type) {
case HT_ID:
target->status = TS_WAITING;
QFile::remove(target->fileDir + QDir::separator() + target->fileName);
emit downloadUpdated(target);
break;
case HT_SIZE:
qDebug() << "reading size..";
in >> target->size;
qDebug() << "got size:" << target->size;
break;
case HT_NAME:
qDebug() << "reading filename..";
in >> target->fileName;
qDebug() << "got filename:" << target->fileName;
qDebug() << "requesting to send HT_ACK";
emit downloadAcknowledged(m_LastHeader.id);
break;
case HT_DATA: {
// qDebug() << "got data" << target->transfered << '/' << target->size;
if (target->status == TS_WAITING) {
target->status = TS_TRANSFERING;
emit downloadAdded(target);
}
char * buffer = new char[m_LastHeader.length];
in.readRawData(buffer, m_LastHeader.length);
// QFile file(target->fileDir + QDir::separator() + target->fileName);
// file.open(QIODevice::WriteOnly | QIODevice::Append);
// QDataStream out(&file);
// out.writeRawData((const char *)(buffer), m_LastHeader.length);
target->transfered += m_LastHeader.length;
delete[] buffer;
emit downloadUpdated(target);
}
break;
default:
in.skipRawData(m_LastHeader.length);
break;
}
}
}
}
if (m_Socket->bytesAvailable() >= (qint64)(sizeof(TransferHeader))) {
in.readRawData((char *)(&m_LastHeader), sizeof(TransferHeader));
m_LastHeaderValid = (qstrcmp(m_LastHeader.descriptor, DESCRIPTOR_STRING) == 0);
qDebug() << "got header" << m_LastHeader.type;
if (m_LastHeaderValid)
qDebug() << "valid";
else
qDebug() << "invalid";
qDebug() << "id" << m_LastHeader.id;
qDebug() << "length" << m_LastHeader.length;
}
else
m_LastHeaderValid = false;
}
}
void CRecieveThread::run() {
qDebug() << "start reciever thread";
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(readData()));
exec();
disconnect(m_Socket, SIGNAL(readyRead()), this, SLOT(readData()));
}
}

64
crecievethread.h

@ -0,0 +1,64 @@
/***************************************************************************
* Copyright (C) 2008 by Oliver Groß *
* z.o.gross@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef QFTRANS_CRECIEVETHREAD_H
#define QFTRANS_CRECIEVETHREAD_H
#include <QThread>
#include "common.h"
class QTcpSocket;
namespace qftrans {
/**
@author Oliver Groß <z.o.gross@gmx.de>
*/
class CRecieveThread : public QThread {
Q_OBJECT
public:
CRecieveThread(QString & destinationDir, QTcpSocket * socket, QObject * parent = 0);
~CRecieveThread();
signals:
void downloadAdded(TransferData * data);
void downloadRemoved(TransferData * data);
void downloadUpdated(TransferData * transfer);
void downloadAcknowledged(quint32 id);
void uploadStartRequest(quint32 id);
public slots:
void setDestinationDir(QString & value);
void removeDownload(TransferData * data);
protected slots:
void readData();
protected:
QTcpSocket * m_Socket;
QString m_DestinationDir;
QTransferDataHash m_DataDict;
TransferHeader m_LastHeader;
bool m_LastHeaderValid;
void run();
};
}
#endif

217
csendthread.cpp

@ -0,0 +1,217 @@
/***************************************************************************
* Copyright (C) 2008 by Oliver Groß *
* z.o.gross@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "csenderthread.h"
#include <QTcpSocket>
#include <QByteArray>
#include <QDataStream>
#include <QFile>
namespace qftrans {
CSenderThread::CSenderThread(QTcpSocket * socket, QObject * parent) : QThread(parent), m_Socket(socket), m_IdCounter(0) {
}
CSenderThread::~CSenderThread() {
}
void CSenderThread::addUpload(TransferData * upload) {
if (!m_DataDict.contains(upload)) {
qDebug() << "adding upload";
m_DataDict.insert(upload, m_IdCounter);
m_IdCounter++;
}
}
void CSenderThread::removeUpload(TransferData * transfer) {
transfer->status = TS_CLOSING;
if (m_Socket->bytesToWrite() == 0) {
qDebug() << "executing upload";
writeData();
}
}
void CSenderThread::startUpload(TransferData * upload) {
if (m_DataDict.contains(upload) && upload->status == TS_WAITING) {
qDebug() << "scheduling upload for announce";
upload->status = TS_ANNOUNCING;
if (m_Socket->bytesToWrite() == 0) {
qDebug() << "executing upload";
writeData();
}
}
}
void CSenderThread::startUploadData(quint32 id) {
TransferData * transfer = m_DataDict.key(id);
if (transfer) {
qDebug() << "scheduling upload for transfer";
transfer->status = TS_TRANSFERING;
if (m_Socket->bytesToWrite() == 0) {
qDebug() << "executing upload";
writeData();
}
}
}
void CSenderThread::sendAcknowledge(quint32 id) {
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
TransferHeader header;
// header.descriptor = DESCRIPTOR_STRING;
header.type = HT_ACK;
header.id = id;
header.length = 0;
out.writeRawData((const char *)(&header), sizeof(TransferHeader));
qDebug() << "sending HT_ACK" << id;
m_Socket->write(block);
}
void CSendThread::writeData() {
if (m_DataDict.isEmpty())
exit();
QByteArray block;
QDataStream out(&block, QIODevice::ReadWrite);
out.setVersion(QDataStream::Qt_4_0);
QTransferDataList transfers = m_DataDict.keys();
QTransferDataList::iterator i;
for (i = transfers.begin(); i != transfers.end(); ++i) {
block.clear();
TransferHeader header;
// header.descriptor = DESCRIPTOR_STRING;
switch ((*i)->status) {
case TS_ANNOUNCING: {
qDebug() << "announcing" << m_DataDict[*i];
if ((*i)->transfered)
(*i)->transfered = 0;
// ID header with no data
header.type = HT_ID;
header.id = m_DataDict[*i];
header.length = 0;
out.writeRawData((const char *)(&header), sizeof(TransferHeader));
//size header with size
header.type = HT_SIZE;
header.length = sizeof(qint64);
out.writeRawData((const char *)(&header), sizeof(TransferHeader));
qDebug() << "sending size" << (*i)->size;
out << (*i)->size;
//name header with file name
qint64 oldPosition = block.size();
//fake write filename
out << (*i)->fileName;
out.device()->seek(oldPosition);
header.type = HT_NAME;
header.length = quint32(block.size() - oldPosition);
// qDebug() << "pos" << out.device()->pos() << block.size();
out.writeRawData((const char *)(&header), sizeof(TransferHeader));
// qDebug() << "pos post header" << out.device()->pos() << block.size();
// qint64 oldPosition = block.size() - sizeof(quint32);
qDebug() << "sending filename" << (*i)->fileName;
out << (*i)->fileName;
// qDebug() << "pos post filename" << out.device()->pos() << block.size();
// out.device()->seek(oldPosition);
// qDebug() << "pos post seek" << out.device()->pos();
/* qDebug() << "filename data length" << header.length;
out << header.length;
out.device()->seek(oldPosition);
out >> header.length;
qDebug() << "written length" << header.length;
out.device()->seek(block.size());
qDebug() << "pos post length correct" << out.device()->pos() << block.size();*/
(*i)->status = TS_WAITING;
}
break;
case TS_TRANSFERING: {
// qDebug() << "transfering" << m_DataDict[*i];
header.type = HT_DATA;
header.id = m_DataDict[*i];
if ((*i)->transfered + DATA_BLOCK_SIZE < (*i)->size)
header.length = DATA_BLOCK_SIZE;
else
header.length = (*i)->size - (*i)->transfered;
out.writeRawData((const char *)(&header), sizeof(TransferHeader));
char * buffer = new char[header.length];
QFile file((*i)->fileDir + (*i)->fileName);
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
in.readRawData(buffer, header.length);
out.writeRawData((const char *)(buffer), header.length);
(*i)->transfered += header.length;
delete[] buffer;
if ((*i)->transfered >= (*i)->size)
(*i)->status = TS_CLOSING;
emit uploadUpdated(*i);
}
break;
case TS_CLOSING:
header.type = HT_CLOSE;
header.id = m_DataDict[*i];
header.length = 0;
out.writeRawData((const char *)(&header), sizeof(TransferHeader));
(*i)->status = TS_FINISHED;
m_DataDict.remove(*i);
break;
default:
break;
}
if (!block.isEmpty())
m_Socket->write(block);
}
}
void CSendThread::run() {
qDebug() << "start sender thread";
connect(m_Socket, SIGNAL(bytesWritten(qint64)), this, SLOT(writeData()));
exec();
disconnect(m_Socket, SIGNAL(bytesWritten(qint64)), this, SLOT(writeData()));
}
}

61
csendthread.h

@ -0,0 +1,61 @@
/***************************************************************************
* Copyright (C) 2008 by Oliver Groß *
* z.o.gross@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef QFTRANS_CSENDERTHREAD_H
#define QFTRANS_CSENDERTHREAD_H
#include <QThread>
#include "common.h"
class QTcpSocket;
namespace qftrans {
/**
@author Oliver Groß <z.o.gross@gmx.de>
*/
class CSendThread : public QThread
{
Q_OBJECT
public:
CSendThread(QTcpSocket * socket, QObject * parent = 0);
~CSendThread();
signals:
void uploadUpdated(TransferData * transfer);
public slots:
void addUpload(TransferData * transfer);
void removeUpload(TransferData * transfer);
void startUpload(TransferData * transfer);
void startUploadData(quint32 id);
void sendAcknowledge(quint32 id);
protected slots:
void writeData();
protected:
QTcpSocket * m_Socket;
quint32 m_IdCounter;
QTransferIdHash m_DataDict;
void run();
};
}
#endif

113
csocketmanager.cpp

@ -0,0 +1,113 @@
/***************************************************************************
* Copyright (C) 2008 by Oliver Groß *
* z.o.gross@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "csocketmanager.h"
#include "cworker.h"
#include <QTcpServer>
#include <QThread>
namespace qftrans {
CSocketManager::CSocketManager(QObject * parent) : QObject(parent),
m_Server(NULL), m_Socket(NULL), m_Worker(NULL) {
}
CSocketManager::~CSocketManager() {
if (m_Socket)
delete m_Socket;
}
void CSocketManager::setup(bool server, quint16 port, QString & host) {
m_Host = host;
m_Port = port;
if (server) {
m_Server = new QTcpServer(this); //TODO proper setup server
connect(m_Server, SIGNAL(newConnection()), this, SLOT(handleServerConnected()));
m_Server->listen(QHostAddress(host), port);
}
else {
m_Socket = new QTcpSocket(); //TODO proper setup client
connect(m_Socket, SIGNAL(connected()), this, SLOT(handleClientConnected()));
connect(m_Socket, SIGNAL(disconnected()), this, SLOT(handleDisconnected()));
m_Socket->connectToHost(host, port);
}
}
void CSocketManager::handleServerConnected() {
qDebug() << "srv conn... thread id" << QThread::currentThreadId();
m_Socket = m_Server->nextPendingConnection();
connect(m_Socket, SIGNAL(disconnected()), this, SLOT(handleDisconnected()));
m_Worker = new CWorker(m_Socket, m_Socket);
// emit workerReady(m_Worker);
emit connectionChanged(true);
m_Server->close();
}
void CSocketManager::handleClientConnected() {
qDebug() << "clt conn... thread id" << QThread::currentThreadId();
m_Worker = new CWorker(m_Socket, m_Socket);
emit connectionChanged(true);
}
void CSocketManager::handleDisconnected() {
qDebug() << "clt/srv disconn.. thread id" << QThread::currentThreadId();
/* m_Worker->deleteLater();
m_Worker = NULL;*/
// if (m_ActAsServer) {
// m_Socket->deleteLater();
// m_Socket = NULL;
//
// m_Server->listen(, 8899);
// emit connectionChanged(false);
// }
// else {
emit connectionChanged(false);
if (m_Server) {
m_Socket->deleteLater();
m_Socket = NULL;
m_Worker = NULL;
m_Server->listen(QHostAddress(m_Host), m_Port);
}
else
QThread::currentThread()->quit();
// }
}
/*
void CSocketManager::connectToPeer() {
if (!m_Server && m_Socket)
m_Socket->connectToHost(host, port);
}*/
// void CSocketManager::disconnectFromPeer() {
// if (m_Socket)
// m_Socket->disconnectFromHost();
// }
}

63
csocketmanager.h

@ -0,0 +1,63 @@
/***************************************************************************
* Copyright (C) 2008 by Oliver Groß *
* z.o.gross@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef QFTRANSCSOCKETMANAGER_H
#define QFTRANSCSOCKETMANAGER_H
#include <QObject>
class QTcpSocket;
class QTcpServer;
namespace qftrans {
class CWorker;
/**
@author Oliver Groß <z.o.gross@gmx.de>
*/
class CSocketManager : public QObject {
Q_OBJECT
public:
CSocketManager(QObject * parent = 0);
~CSocketManager();
CWorker * worker() { return m_Worker; }
public slots:
void setup(bool server, quint16 port, QString & host);
/* void connectToPeer();*/
// void disconnectFromPeer();
signals:
void connectionChanged(bool connected);
protected:
// bool m_ActAsServer;
QString m_Host;
quint16 m_Port;
QTcpServer * m_Server;
QTcpSocket * m_Socket;
CWorker * m_Worker;
protected slots:
void handleServerConnected();
void handleClientConnected();
void handleDisconnected();
};
}
#endif

291
ctransfermanager.cpp

@ -0,0 +1,291 @@
/***************************************************************************
* Copyright (C) 2008 by Oliver Groß *
* z.o.gross@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "ctransfermanager.h"
#include "ctransferthread.h"
#include "csocketmanager.h"
#include "qtransferlistmodel.h"
#include "cworker.h"
#include "cconnectiondialog.h"
#include <QDebug>
#include <QStatusBar>
#include <QFileInfo>
#include <QDataStream>
#include <QTcpServer>
#include <QTcpSocket>
#include <QMenuBar>
#include <QMenu>
#include <QToolBar>
#include <QListView>
#include <QFileDialog>
#include <QApplication>
#include <QMessageBox>
namespace qftrans {
CTransferManager::CTransferManager(QWidget * parent) : QMainWindow(parent),
m_ActAsServer(false),
m_Connected(false),
m_DestinationDir(QDir::homePath()),
m_TransferThread(NULL),
m_SelectedTransfer(NULL)
{
setupUi();
}
// TODO ~CTransferManager()
CTransferManager::~CTransferManager() {
cleanupThread();
}
void CTransferManager::openFile() {
QStringList files = QFileDialog::getOpenFileNames(this,
tr("Select one or more files to open"),
QDir::homePath());
TransferData * newUpload = NULL;
QFileInfo fileInfo;
foreach (QString i, files) {
fileInfo.setFile(i);
newUpload = new TransferData;
newUpload->fileDir = fileInfo.absolutePath();
newUpload->fileName = fileInfo.fileName();
newUpload->size = fileInfo.size();
newUpload->transfered = 0;
newUpload->status = TS_WAITING;
newUpload->lastHeader = HT_ID;
newUpload->localFile = true;
addTransfer(newUpload);
// emit uploadAddRequested(newUpload);
}
}
void CTransferManager::setDestinationDir() {
QString selectedDir = QFileDialog::getExistingDirectory(this, tr("Select a directory to save downloaded files"), m_DestinationDir);
if (!selectedDir.isEmpty()) {
m_DestinationDir = selectedDir;
emit destinationDirChanged(m_DestinationDir);
}
}
void CTransferManager::requestServerThread() {
if (!m_ConnectionDialog->execute(true))
return;
createThread();
m_ActAsServer = true;
m_TransferThread->start();
}
void CTransferManager::requestClientThread() {
if (!m_ConnectionDialog->execute(false))
return;
createThread();
m_ActAsServer = false;
m_TransferThread->start();
}
void CTransferManager::setupConnection() {
connect(m_TransferThread->socketManager(), SIGNAL(connectionChanged(bool)), this, SLOT(updateConnectionState(bool)));
connect(this, SIGNAL(setupConnectionRequested(bool, quint16, QString &)),
m_TransferThread->socketManager(), SLOT(setup(bool, quint16, QString &)));
QString host = m_ActAsServer ? "0.0.0.0" : m_ConnectionDialog->host();
emit setupConnectionRequested(m_ActAsServer, m_ConnectionDialog->port(), host);
}
void CTransferManager::cleanupThread() {
if (m_TransferThread) {
m_TransferThread->quit();
m_TransferThread->deleteLater();
}
m_TransferThread = NULL;
statusBar()->showMessage(tr("connected"));
}
void CTransferManager::restartSelected() {
emit uploadAddRequested(m_SelectedTransfer);
emit uploadRestartRequested(m_SelectedTransfer);
}
void CTransferManager::cancelSelected() {
if (m_SelectedTransfer->localFile)
emit uploadRemoveRequested(m_SelectedTransfer);
else
emit downloadRemoveRequested(m_SelectedTransfer);
}
inline void CTransferManager::setupUi() {
setWindowTitle(tr("QFTrans"));
QMenu * currentMenu;
QToolBar * currentToolBar = addToolBar("Main");
currentMenu = menuBar()->addMenu(tr("&File"));
m_FileOpen = currentMenu->addAction(tr("&Open..."), this, SLOT(openFile()));
currentMenu->addAction(tr("Set destination directory..."), this, SLOT(setDestinationDir()));
currentToolBar->addActions(currentMenu->actions());
currentMenu->addSeparator();
currentMenu->addAction(tr("&Quit"), this, SLOT(close()));
currentToolBar->addSeparator();
currentMenu = menuBar()->addMenu(tr("&Connection"));
m_ConnectionAsServer = currentMenu->addAction(tr("Act as &server"), this, SLOT(requestServerThread()));
m_ConnectionAsClient = currentMenu->addAction(tr("Act as &client"), this, SLOT(requestClientThread()));
currentMenu->addSeparator();
m_ConnectionDisconnect = currentMenu->addAction(tr("&Disconnect"), this, SLOT(cleanupThread()));
currentToolBar->addActions(currentMenu->actions());
currentToolBar->addSeparator();
currentMenu = menuBar()->addMenu(tr("&Transfer"));
m_TransferRestartAction = currentMenu->addAction(tr("(Re)&Start"), this, SLOT(restartSelected()));
m_TransferCancelAction = currentMenu->addAction(tr("&Cancel"), this, SLOT(cancelSelected()));
m_TransferRestartAction->setEnabled(false);
m_TransferCancelAction->setEnabled(false);
currentToolBar->addActions(currentMenu->actions());
currentMenu = menuBar()->addMenu(tr("&Help"));
currentMenu->addAction(tr("&About"), this, SLOT(about()));
currentMenu->addAction(tr("About &Qt"), qApp, SLOT(aboutQt()));
m_TransferView = new QListView(this);
setCentralWidget(m_TransferView);
QTransferListModel * listModel = new QTransferListModel(&m_Data);
connect(this, SIGNAL(transferRemoved(TransferData *)), listModel, SIGNAL(layoutChanged()));
connect(this, SIGNAL(transferAdded(TransferData *)), listModel, SIGNAL(layoutChanged()));
m_TransferView->setModel(listModel);
connect(m_TransferView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
this, SLOT(handleSelectionChanged(const QItemSelection &)));
updateConnectionState(false);
m_ConnectionDialog = new CConnectionDialog(this);
}
void CTransferManager::updateConnectionState(bool connected) {
m_Connected = connected;
if (connected) {
connectToWorker(m_TransferThread->socketManager()->worker());
statusBar()->showMessage(tr("connected"));
}
else
statusBar()->showMessage(m_TransferThread ? tr("waiting") : tr("disconnected"));
m_FileOpen->setEnabled(connected);
m_ConnectionAsServer->setDisabled(connected);
m_ConnectionAsClient->setDisabled(connected);
m_ConnectionDisconnect->setEnabled(connected);
}
// TODO cleanup()
void CTransferManager::cleanup() {
}
void CTransferManager::connectToWorker(CWorker * worker) {
worker->setDestinationDir(m_DestinationDir);
connect(this, SIGNAL(destinationDirChanged(QString &)), worker, SLOT(setDestinationDir(QString &)));
connect(worker, SIGNAL(downloadAdded(TransferData *)), this, SLOT(addTransfer(TransferData *)));
QTransferListModel * model = dynamic_cast<QTransferListModel *>(m_TransferView->model());
connect(worker, SIGNAL(downloadUpdated(TransferData *)), model, SLOT(updateEntry(TransferData *)));
connect(worker, SIGNAL(uploadUpdated(TransferData *)), model, SLOT(updateEntry(TransferData *)));
connect(this, SIGNAL(uploadAddRequested(TransferData *)), worker, SLOT(addUpload(TransferData *)));
connect(this, SIGNAL(uploadRestartRequested(TransferData *)), worker, SLOT(startUpload(TransferData *)));
connect(this, SIGNAL(uploadRemoveRequested(TransferData *)), worker, SLOT(removeUpload(TransferData *)));
connect(this, SIGNAL(downloadRemoveRequested(TransferData *)), worker, SLOT(removeDownload(TransferData *)));
}
void CTransferManager::handleSelectionChanged(const QItemSelection & selected) {
QModelIndexList selectedIndexes = selected.indexes();
if (selectedIndexes.isEmpty())
m_SelectedTransfer = NULL;
else
m_SelectedTransfer = static_cast<TransferData *>(selectedIndexes[0].internalPointer());
m_TransferRestartAction->setEnabled(m_SelectedTransfer && m_SelectedTransfer->localFile);
m_TransferCancelAction->setEnabled(m_SelectedTransfer && m_SelectedTransfer->status != TS_FINISHED);
}
void CTransferManager::addTransfer(TransferData * transfer) {
m_Data << transfer;
emit transferAdded(transfer);
}
// TODO proper handle removing transfer
void CTransferManager::removeTransfer(TransferData * transfer) {
int index = m_Data.indexOf(transfer);
if (index != -1) {
m_Data.removeAt(index);
emit transferRemoved(transfer);
}
delete transfer;
}
inline void CTransferManager::createThread() {
cleanupThread();
qDebug() << "main thread" << QThread::currentThreadId();
m_TransferThread = new CTransferThread();
connect(m_TransferThread, SIGNAL(terminated()), this, SLOT(cleanupThread()));
// connect(m_TransferThread, SIGNAL(finished()), m_TransferThread, SLOT(deleteLater()));
connect(m_TransferThread, SIGNAL(socketManagerReady()), this, SLOT(setupConnection()));
}
void CTransferManager::updateStatusBar(const QString & message) {
if (message.isEmpty()) {
if (m_Connected)
statusBar()->showMessage(tr("connected"));
else
statusBar()->showMessage(m_TransferThread ? tr("waiting") : tr("disconnected"));
}
}
void CTransferManager::about() {
QMessageBox::about(this, tr("About"), tr("This is a still unfancy \"peer-to-peer\"-like file transfer tool."));
}
}

110
ctransfermanager.h

@ -0,0 +1,110 @@
/***************************************************************************
* Copyright (C) 2008 by Oliver Groß *
* z.o.gross@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef QFTRANS_CTRANSFERMANAGER_H
#define QFTRANS_CTRANSFERMANAGER_H
#include <QMainWindow>
#include "common.h"
#include <QItemSelection>
// #include <QAbstractSocket>
class QListView;
namespace qftrans {
class CTransferThread;
class CWorker;
class CConnectionDialog;
/**
@author Oliver Groß <z.o.gross@gmx.de>
*/
class CTransferManager : public QMainWindow {
Q_OBJECT
public:
CTransferManager(QWidget * parent = 0);
~CTransferManager();
public slots:
void openFile();
void setDestinationDir();
void requestServerThread();
void requestClientThread();
void cleanupThread();
void restartSelected();
void cancelSelected();
signals:
void transferAdded(TransferData * transfer);
void transferRemoved(TransferData * transfer);
void uploadAddRequested(TransferData * transfer);
void uploadRemoveRequested(TransferData * transfer);
void uploadRestartRequested(TransferData * transfer);
void downloadRemoveRequested(TransferData * transfer);
void destinationDirChanged(QString & value);
void setupConnectionRequested(bool server, quint16 port, QString & host);
private:
CConnectionDialog * m_ConnectionDialog;
QAction * m_FileOpen;
QAction * m_ConnectionAsServer;
QAction * m_ConnectionAsClient;
QAction * m_ConnectionDisconnect;
QAction * m_TransferRestartAction;
QAction * m_TransferCancelAction;
bool m_ActAsServer;
bool m_Connected;
QString m_DestinationDir;
QTransferDataList m_Data;
CTransferThread * m_TransferThread;
QListView * m_TransferView;
TransferData * m_SelectedTransfer;
void setupUi();
void removeFileTransfer(TransferData * transfer);
void cleanup();
inline void createThread();
private slots:
void setupConnection();
void connectToWorker(CWorker * worker);
void updateConnectionState(bool connected);
void handleSelectionChanged(const QItemSelection & selected);
void addTransfer(TransferData * transfer);
void removeTransfer(TransferData * transfer);
void updateStatusBar(const QString & message);
void about();
};
}
#endif

75
ctransferthread.cpp

@ -0,0 +1,75 @@
/***************************************************************************
* Copyright (C) 2008 by Oliver Groß *
* z.o.gross@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "ctransferthread.h"
#include "csocketmanager.h"
#include <QTcpServer>
namespace qftrans {
CTransferThread::CTransferThread(QObject * parent) : QThread(parent),
m_SocketManager(NULL) {
}
CTransferThread::~CTransferThread() {
if (m_SocketManager)
m_SocketManager->deleteLater();
/* if (m_Socket)
delete m_Socket;
if (m_Worker)
delete m_Worker;
if (m_Server)
delete m_Server;*/
}
void CTransferThread::run() {
qDebug() << "start transfer thread" << currentThreadId();
m_SocketManager = new CSocketManager();
emit socketManagerReady();
exec();
qDebug() << "exit transfer thread" << currentThreadId();
if (m_SocketManager) {
delete m_SocketManager;
// m_SocketManager->deleteLater();
m_SocketManager = NULL;
}
/* if (m_Worker) {
delete m_Worker;
m_Worker = NULL;
}
if (m_Server) {
delete m_Server;
m_Server = NULL;
}
if (m_Socket) {
delete m_Socket;
m_Socket = NULL;
}*/
// emit connectionChanged(false);
}
}

50
ctransferthread.h

@ -0,0 +1,50 @@
/***************************************************************************
* Copyright (C) 2008 by Oliver Groß *
* z.o.gross@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef QFTRANS_CTRANSFERTHREAD_H
#define QFTRANS_CTRANSFERTHREAD_H
#include <QThread>
#include "common.h"
namespace qftrans {
class CSocketManager;
/**
@author Oliver Groß <z.o.gross@gmx.de>
*/
class CTransferThread : public QThread {
Q_OBJECT
public:
CTransferThread(QObject * parent = 0);
~CTransferThread();
// CWorker * worker() { return m_Worker; }
CSocketManager * socketManager() { return m_SocketManager; }
signals:
void socketManagerReady();
protected:
CSocketManager * m_SocketManager;
void run();
};
}
#endif

425
cworker.cpp

@ -0,0 +1,425 @@
/***************************************************************************
* Copyright (C) 2008 by Oliver Groß *
* z.o.gross@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "cworker.h"
#include <QTcpSocket>
#include <QByteArray>
#include <QFile>
#include <QDir>
#include <QThread>
namespace qftrans {
CWorker::CWorker(QTcpSocket * socket, QObject * parent) : QObject(parent), m_Socket(socket), m_IdCounter(0) {
connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
connect(m_Socket, SIGNAL(bytesWritten(qint64)), this, SLOT(writeData()), Qt::QueuedConnection);
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(readData()), Qt::QueuedConnection);
qDebug() << "worker created";
}
CWorker::~CWorker() {
qDebug() << "worker removed";
}