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.
414 lines
13 KiB
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"
|