/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * 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 #include #include #include #include #include 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 has been aborted because there is not enough free space left on '%1':").arg(mountPoint); transAbortStr += "
"; transAbortStr += getSourceUrl().fileName(); transAbortStr += ""; 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"