diff options
Diffstat (limited to 'kftpgrabber/src/engine/thread.cpp')
-rw-r--r-- | kftpgrabber/src/engine/thread.cpp | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/kftpgrabber/src/engine/thread.cpp b/kftpgrabber/src/engine/thread.cpp new file mode 100644 index 0000000..3e151b5 --- /dev/null +++ b/kftpgrabber/src/engine/thread.cpp @@ -0,0 +1,346 @@ +/* + * This file is part of the KFTPGrabber project + * + * Copyright (C) 2003-2006 by the KFTPGrabber developers + * Copyright (C) 2003-2006 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 "thread.h" +#include "ftpsocket.h" +#include "sftpsocket.h" + +#include <qapplication.h> + +namespace KFTPEngine { + +Thread::Thread() + : QThread(), + m_eventHandler(new EventHandler(this)), + m_socket(0), + m_wakeupEvent(0), + m_abortLoop(false), + m_wakeUpPending(false) +{ + m_protocolMap.insert("ftp", new FtpSocket(this)); + m_protocolMap.insert("sftp", new SftpSocket(this)); + + // FTP is the default protocol + m_socket = m_protocolMap["ftp"]; + + // Auto start the thread + start(); +} + +Thread::~Thread() +{ + m_abortLoop = true; + + if (!wait(1000)) + terminate(); + + // Destroy all protocol sockets + delete static_cast<FtpSocket*>(m_protocolMap["ftp"]); + delete static_cast<SftpSocket*>(m_protocolMap["sftp"]); + + m_protocolMap.clear(); +} + +void Thread::run() +{ + while (!m_abortLoop) { + QThread::usleep(100); + + // "Poll" the socket + m_socket->poll(); + + // Transmit wakeup events if any + if (m_wakeUpPending && m_socket->isBusy()) { + m_wakeupMutex.lock(); + m_socket->wakeup(m_wakeupEvent); + + delete m_wakeupEvent; + m_wakeupEvent = 0; + m_wakeUpPending = false; + m_wakeupMutex.unlock(); + } + + // Execute any pending commands if the socket isn't busy + if (!m_commandQueue.empty()) { + m_queueMutex.lock(); + + QValueList<Commands::Type>::iterator queueEnd = m_commandQueue.end(); + for (QValueList<Commands::Type>::iterator i = m_commandQueue.begin(); i != queueEnd; ++i) { + Commands::Type cmdType = *i; + + // Execute the command + if (cmdType == Commands::CmdNext) { + m_commandQueue.remove(i--); + m_socket->nextCommand(); + } else if (!m_socket->isBusy()) { + m_commandQueue.remove(i--); + m_socket->setCurrentCommand(cmdType); + + switch (cmdType) { + case Commands::CmdConnect: { + m_socket->protoConnect(nextCommandParameter().asUrl()); + break; + } + case Commands::CmdDisconnect: { + m_socket->protoDisconnect(); + break; + } + case Commands::CmdList: { + m_socket->protoList(nextCommandParameter().asUrl()); + break; + } + case Commands::CmdScan: { + m_socket->protoScan(nextCommandParameter().asUrl()); + break; + } + case Commands::CmdGet: { + m_socket->protoGet(nextCommandParameter().asUrl(), + nextCommandParameter().asUrl()); + break; + } + case Commands::CmdPut: { + m_socket->protoPut(nextCommandParameter().asUrl(), + nextCommandParameter().asUrl()); + break; + } + case Commands::CmdDelete: { + m_socket->protoDelete(nextCommandParameter().asUrl()); + break; + } + case Commands::CmdRename: { + m_socket->protoRename(nextCommandParameter().asUrl(), + nextCommandParameter().asUrl()); + break; + } + case Commands::CmdChmod: { + m_socket->protoChmod(nextCommandParameter().asUrl(), + nextCommandParameter().asFileSize(), + nextCommandParameter().asBoolean()); + break; + } + case Commands::CmdMkdir: { + m_socket->protoMkdir(nextCommandParameter().asUrl()); + break; + } + case Commands::CmdRaw: { + m_socket->protoRaw(nextCommandParameter().asString()); + break; + } + case Commands::CmdFxp: { + m_socket->protoSiteToSite(static_cast<Socket*>(nextCommandParameter().asData()), + nextCommandParameter().asUrl(), + nextCommandParameter().asUrl()); + break; + } + default: { + // Just ignore unknown commands for now + break; + } + } + } + } + + m_queueMutex.unlock(); + } + } +} + +void Thread::wakeup(WakeupEvent *event) +{ + QMutexLocker locker(&m_wakeupMutex); + + m_wakeupEvent = event; + m_wakeUpPending = true; +} + +void Thread::abort() +{ + // Clear any pending wakeup events + if (m_wakeUpPending) { + QMutexLocker locker(&m_wakeupMutex); + + m_wakeupEvent = 0; + m_wakeUpPending = false; + } + + m_socket->protoAbort(); +} + +void Thread::event(Event::Type type, QValueList<EventParameter> params) +{ + if (m_eventHandler) { + Event *e = new Event(type, params); + qApp->postEvent(m_eventHandler, e); + } +} + +void Thread::selectSocketForProtocol(const KURL &url) +{ + if (url.protocol() == m_socket->protocolName()) + return; + + // Change the socket if one exists + Socket *socket = m_protocolMap.find(url.protocol()); + if (socket) + m_socket = socket; +} + +EventParameter Thread::nextCommandParameter() +{ + QMutexLocker locker(&m_paramsMutex); + EventParameter param = m_commandParams.front(); + m_commandParams.pop_front(); + + return param; +} + +void Thread::connect(const KURL &url) +{ + QMutexLocker locker(&m_paramsMutex); + QMutexLocker lockerq(&m_queueMutex); + + // Setup the correct socket to use for connection + selectSocketForProtocol(url); + + m_commandQueue.append(Commands::CmdConnect); + m_commandParams.append(EventParameter(url)); +} + +void Thread::disconnect() +{ + QMutexLocker locker(&m_paramsMutex); + QMutexLocker lockerq(&m_queueMutex); + + m_commandQueue.append(Commands::CmdDisconnect); +} + +void Thread::list(const KURL &url) +{ + QMutexLocker locker(&m_paramsMutex); + QMutexLocker lockerq(&m_queueMutex); + + m_commandQueue.append(Commands::CmdList); + m_commandParams.append(EventParameter(url)); +} + +void Thread::scan(const KURL &url) +{ + QMutexLocker locker(&m_paramsMutex); + QMutexLocker lockerq(&m_queueMutex); + + m_commandQueue.append(Commands::CmdScan); + m_commandParams.append(EventParameter(url)); +} + +void Thread::get(const KURL &source, const KURL &destination) +{ + QMutexLocker locker(&m_paramsMutex); + QMutexLocker lockerq(&m_queueMutex); + + m_commandQueue.append(Commands::CmdGet); + m_commandParams.append(EventParameter(destination)); + m_commandParams.append(EventParameter(source)); +} + +void Thread::put(const KURL &source, const KURL &destination) +{ + QMutexLocker locker(&m_paramsMutex); + QMutexLocker lockerq(&m_queueMutex); + + m_commandQueue.append(Commands::CmdPut); + m_commandParams.append(EventParameter(destination)); + m_commandParams.append(EventParameter(source)); +} + +void Thread::remove(const KURL &url) +{ + QMutexLocker locker(&m_paramsMutex); + QMutexLocker lockerq(&m_queueMutex); + + m_commandQueue.append(Commands::CmdDelete); + m_commandParams.append(EventParameter(url)); +} + +void Thread::rename(const KURL &source, const KURL &destination) +{ + QMutexLocker locker(&m_paramsMutex); + QMutexLocker lockerq(&m_queueMutex); + + m_commandQueue.append(Commands::CmdRename); + m_commandParams.append(EventParameter(destination)); + m_commandParams.append(EventParameter(source)); +} + +void Thread::chmod(const KURL &url, int mode, bool recursive) +{ + QMutexLocker locker(&m_paramsMutex); + QMutexLocker lockerq(&m_queueMutex); + + m_commandQueue.append(Commands::CmdChmod); + m_commandParams.append(EventParameter(recursive)); + m_commandParams.append(EventParameter(mode)); + m_commandParams.append(EventParameter(url)); +} + +void Thread::mkdir(const KURL &url) +{ + QMutexLocker locker(&m_paramsMutex); + QMutexLocker lockerq(&m_queueMutex); + + m_commandQueue.append(Commands::CmdMkdir); + m_commandParams.append(EventParameter(url)); +} + +void Thread::raw(const QString &raw) +{ + QMutexLocker locker(&m_paramsMutex); + QMutexLocker lockerq(&m_queueMutex); + + m_commandQueue.append(Commands::CmdRaw); + m_commandParams.append(EventParameter(raw)); +} + +void Thread::siteToSite(Thread *thread, const KURL &source, const KURL &destination) +{ + QMutexLocker locker(&m_paramsMutex); + QMutexLocker lockerq(&m_queueMutex); + + m_commandQueue.append(Commands::CmdFxp); + m_commandParams.append(EventParameter(destination)); + m_commandParams.append(EventParameter(source)); + m_commandParams.append(EventParameter(thread->socket())); +} + +} |