You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kftpgrabber/kftpgrabber/src/kftptransferfile.cpp

414 lines
13 KiB

/*
* This file is part of the KFTPGrabber project
*
* Copyright (C) 2003-2004 by the KFTPGrabber developers
* Copyright (C) 2003-2004 Jernej Kos <kostko@jweb-network.net>
*
* 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
* is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
* NON-INFRINGEMENT. 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., 51 Franklin Steet, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
#include "kftptransferfile.h"
#include "widgets/systemtray.h"
#include "kftpsession.h"
#include "statistics.h"
#include "engine/thread.h"
#include "misc/kftpconfig.h"
#include <tdemessagebox.h>
#include <tdelocale.h>
#include <tdeio/renamedlg.h>
#include <kdiskfreesp.h>
#include <ntqtimer.h>
#include <ntqfileinfo.h>
using namespace KFTPEngine;
using namespace KFTPSession;
namespace KFTPQueue {
TransferFile::TransferFile(TQObject *parent)
: Transfer(parent, Transfer::File),
m_updateTimer(0),
m_dfTimer(0)
{
}
bool TransferFile::assignSessions(Session *source, Session *destination)
{
if (!Transfer::assignSessions(source, destination))
return false;
// Connect signals
if (m_srcConnection) {
connect(m_srcConnection->getClient()->eventHandler(), SIGNAL(engineEvent(KFTPEngine::Event*)), this, SLOT(slotEngineEvent(KFTPEngine::Event*)));
connect(m_srcConnection, SIGNAL(aborting()), this, SLOT(slotSessionAborting()));
connect(m_srcConnection, SIGNAL(connectionLost(KFTPSession::Connection*)), this, SLOT(slotConnectionLost(KFTPSession::Connection*)));
}
if (m_dstConnection) {
connect(m_dstConnection->getClient()->eventHandler(), SIGNAL(engineEvent(KFTPEngine::Event*)), this, SLOT(slotEngineEvent(KFTPEngine::Event*)));
connect(m_dstConnection, SIGNAL(aborting()), this, SLOT(slotSessionAborting()));
connect(m_dstConnection, SIGNAL(connectionLost(KFTPSession::Connection*)), this, SLOT(slotConnectionLost(KFTPSession::Connection*)));
}
return true;
}
void TransferFile::execute()
{
// Failed transfers aren't allowed to be executed until they are readded to
// the queue and the Failed status is changed to Stopped.
if (getStatus() == Failed)
return;
// Assign sessions if they are missing
if (!connectionsReady() && !assignSessions(m_srcSession, m_dstSession))
return;
if ((m_dstConnection && !m_dstConnection->isConnected()) || (m_srcConnection && !m_srcConnection->isConnected())) {
m_status = Connecting;
return;
}
// We are running now
m_status = Running;
m_completed = 0;
m_resumed = 0;
// Init timer to follow the update
if (!m_updateTimer) {
m_updateTimer = new TQTimer(this);
connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(slotTimerUpdate()));
m_updateTimer->start(1000);
}
// Should we check for free space ?
if (KFTPCore::Config::diskCheckSpace() && !m_dfTimer) {
m_dfTimer = new TQTimer(this);
connect(m_dfTimer, SIGNAL(timeout()), this, SLOT(slotTimerDiskFree()));
m_dfTimer->start(KFTPCore::Config::diskCheckInterval() * 1000);
}
emit transferStart(m_id);
switch(m_transferType) {
case Download: {
m_srcConnection->getClient()->get(m_sourceUrl, m_destUrl);
break;
}
case Upload: {
m_dstConnection->getClient()->put(m_sourceUrl, m_destUrl);
break;
}
case FXP: {
// Start the timer to extrapolate transfer rate
m_elapsedTime.start();
m_srcConnection->getClient()->siteToSite(m_dstConnection->getClient(), m_sourceUrl, m_destUrl);
break;
}
}
}
void TransferFile::slotConnectionLost(KFTPSession::Connection *connection)
{
if (!isRunning())
return;
if (m_status != Connecting) {
// Semi-reset the current transfer
addCompleted(-m_completed);
m_resumed = 0;
m_completed = 0;
m_aborting = false;
m_size = m_actualSize;
setSpeed(0);
// Wait for the connection to come
m_status = Connecting;
connection->reconnect();
} else
connection->reconnect();
}
void TransferFile::slotEngineEvent(KFTPEngine::Event *event)
{
if (!isRunning())
return;
switch (event->type()) {
case Event::EventTransferComplete: {
// ***************************************************************************
// ************************ EventTransferComplete ****************************
// ***************************************************************************
// Calculate transfer rate for last transfer, and save to site's statistics
if (getTransferType() == FXP) {
if (m_elapsedTime.elapsed() > 10000) {
double speed = (m_size - m_resumed) / (double) m_elapsedTime.elapsed();
Statistics::self()->getSite(m_sourceUrl)->setLastFxpSpeed(speed * 1024);
}
}
// Update the completed size if the transfer was faster than the update timer
addCompleted(m_size - m_completed);
m_updateTimer->stop();
m_updateTimer->TQObject::disconnect();
if (m_openAfterTransfer && m_transferType == Download) {
// Set status to stopped, so the view gets reloaded
m_status = Stopped;
Manager::self()->openAfterTransfer(this);
} else {
showTransCompleteBalloon();
}
m_deleteMe = true;
addActualSize(-m_size);
resetTransfer();
emit transferComplete(m_id);
KFTPQueue::Manager::self()->doEmitUpdate();
break;
}
case Event::EventResumeOffset: {
// ***************************************************************************
// ************************** EventResumeOffset ******************************
// ***************************************************************************
m_resumed = event->getParameter(0).asFileSize();
addCompleted(m_resumed);
break;
}
case Event::EventError: {
// ***************************************************************************
// ****************************** EventError *********************************
// ***************************************************************************
ErrorCode error = event->getParameter(0).asErrorCode();
switch (error) {
case ConnectFailed: {
FailedTransfer::fail(this, i18n("Connection to the server has failed."));
break;
}
case LoginFailed: {
FailedTransfer::fail(this, i18n("Login to the server has failed"));
break;
}
case FileNotFound: {
FailedTransfer::fail(this, i18n("Source file cannot be found."));
break;
}
case PermissionDenied: {
FailedTransfer::fail(this, i18n("Permission was denied."));
break;
}
case FileOpenFailed: {
FailedTransfer::fail(this, i18n("Unable to open local file for read or write operations."));
break;
}
case OperationFailed: {
FailedTransfer::fail(this, i18n("Transfer failed for some reason."));
break;
}
default: break;
}
break;
}
case Event::EventFileExists: {
// ***************************************************************************
// *************************** EventFileExists *******************************
// ***************************************************************************
DirectoryListing list = event->getParameter(0).asDirectoryListing();
FileExistsWakeupEvent *event = Manager::self()->fileExistsAction(this, list.list());
if (event)
remoteConnection()->getClient()->wakeup(event);
break;
}
default: break;
}
}
void TransferFile::wakeup(KFTPEngine::FileExistsWakeupEvent *event)
{
if (event)
remoteConnection()->getClient()->wakeup(event);
}
void TransferFile::slotTimerUpdate()
{
// Update the current stats
if (!m_srcSession && !m_dstSession) {
m_updateTimer->stop();
m_updateTimer->TQObject::disconnect();
return;
}
if (m_status == Running) {
// Get speed from connection, or use FXP extrapolation.
if (getTransferType() == FXP) {
double lastFxpSpeed = Statistics::self()->getSite(m_sourceUrl)->lastFxpSpeed();
if (lastFxpSpeed != 0.0) {
setSpeed(lastFxpSpeed);
if (m_completed < m_size)
addCompleted(getSpeed());
}
} else {
if (remoteConnection()->getClient()->socket()->getTransferBytes() > m_completed - m_resumed)
addCompleted(remoteConnection()->getClient()->socket()->getTransferBytes() - (m_completed - m_resumed));
setSpeed(remoteConnection()->getClient()->socket()->getTransferSpeed());
}
}
update();
}
void TransferFile::slotTimerDiskFree()
{
// Check for disk usage
if (KFTPCore::Config::diskCheckSpace()) {
KDiskFreeSp *df = KDiskFreeSp::findUsageInfo((getDestUrl().path()));
connect(df, SIGNAL(foundMountPoint(const TQString&, unsigned long, unsigned long, unsigned long)), this, SLOT(slotDiskFree(const TQString&, unsigned long, unsigned long, unsigned long)));
}
}
void TransferFile::slotDiskFree(const TQString &mountPoint, unsigned long, unsigned long, unsigned long kBAvail)
{
if (KFTPCore::Config::diskCheckSpace()) {
// Is there enough free space ?
if (kBAvail < (unsigned long) KFTPCore::Config::diskMinFreeSpace()) {
TQString transAbortStr = i18n("Transfer of the following files <b>has been aborted</b> because there is not enough free space left on '%1':").arg(mountPoint);
transAbortStr += "<br><i>";
transAbortStr += getSourceUrl().fileName();
transAbortStr += "</i>";
KFTPWidgets::SystemTray::self()->showBalloon(transAbortStr);
// Abort the transfer
abort();
}
}
}
void TransferFile::resetTransfer()
{
// Unlock the sessions (they should be unlocked automaticly when the transferComplete signal
// is emitted, but when a transfer is a child transfer, the next transfer may need the session
// sooner). Also sessions should be unlocked when transfer aborts.
if (getStatus() != Waiting) {
// Disconnect signals
if (m_srcConnection) {
m_srcConnection->getClient()->eventHandler()->TQObject::disconnect(this, SLOT(slotEngineEvent(KFTPEngine::Event*)));
m_srcConnection->TQObject::disconnect(this, SLOT(slotSessionAborting()));
m_srcConnection->TQObject::disconnect(this, SLOT(slotConnectionLost(KFTPSession::Connection*)));
m_srcConnection->remove();
}
if (m_dstConnection) {
m_dstConnection->getClient()->eventHandler()->TQObject::disconnect(this, SLOT(slotEngineEvent(KFTPEngine::Event*)));
m_dstConnection->TQObject::disconnect(this, SLOT(slotSessionAborting()));
m_dstConnection->TQObject::disconnect(this, SLOT(slotConnectionLost(KFTPSession::Connection*)));
m_dstConnection->remove();
}
}
Transfer::resetTransfer();
}
void TransferFile::slotSessionAborting()
{
if (!m_aborting)
abort();
}
void TransferFile::abort()
{
if (!isRunning())
return;
Transfer::abort();
if (getStatus() == Waiting) {
if (m_srcSession)
m_srcSession->TQObject::disconnect(this, SLOT(slotConnectionAvailable()));
if (m_dstSession)
m_dstSession->TQObject::disconnect(this, SLOT(slotConnectionAvailable()));
}
if (m_updateTimer) {
m_updateTimer->stop();
m_updateTimer->TQObject::disconnect();
delete m_updateTimer;
m_updateTimer = 0L;
}
if (m_dfTimer) {
m_dfTimer->stop();
m_dfTimer->TQObject::disconnect();
delete m_dfTimer;
m_dfTimer = 0L;
}
// Abort any transfers
if (m_srcConnection)
m_srcConnection->abort();
if (m_dstConnection)
m_dstConnection->abort();
// Update everything
resetTransfer();
if (!hasParentTransfer())
update();
if (hasParentObject() && parentObject()->isAborting())
disconnect(parent());
}
}
#include "kftptransferfile.moc"