summaryrefslogtreecommitdiffstats
path: root/kftpgrabber/src/kftpsession.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kftpgrabber/src/kftpsession.cpp')
-rw-r--r--kftpgrabber/src/kftpsession.cpp920
1 files changed, 920 insertions, 0 deletions
diff --git a/kftpgrabber/src/kftpsession.cpp b/kftpgrabber/src/kftpsession.cpp
new file mode 100644
index 0000000..126eb3e
--- /dev/null
+++ b/kftpgrabber/src/kftpsession.cpp
@@ -0,0 +1,920 @@
+/*
+ * 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 "kftpsession.h"
+#include "kftpapi.h"
+#include "browser/detailsview.h"
+#include "browser/treeview.h"
+#include "browser/view.h"
+#include "kftpbookmarks.h"
+#include "misc.h"
+#include "widgets/systemtray.h"
+#include "mainactions.h"
+
+#include "misc/config.h"
+#include "misc/filter.h"
+
+#include <qdir.h>
+#include <qobjectlist.h>
+
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kpassdlg.h>
+#include <kstaticdeleter.h>
+
+using namespace KFTPGrabberBase;
+using namespace KFTPEngine;
+using namespace KFTPCore::Filter;
+
+namespace KFTPSession {
+
+//////////////////////////////////////////////////////////////////
+//////////////////////// Connection ///////////////////////
+//////////////////////////////////////////////////////////////////
+
+Connection::Connection(Session *session, bool primary)
+ : QObject(session),
+ m_primary(primary),
+ m_busy(false),
+ m_aborting(false),
+ m_scanning(false)
+{
+ // Create the actual connection client
+ m_client = new KFTPEngine::Thread();
+
+ connect(m_client->eventHandler(), SIGNAL(engineEvent(KFTPEngine::Event*)), this, SLOT(slotEngineEvent(KFTPEngine::Event*)));
+
+ // If this is not a core session connection, connect
+ if (!primary) {
+ // Connect to the server
+ KURL url = session->getClient()->socket()->getCurrentUrl();
+
+ KFTPBookmarks::Manager::self()->setupClient(session->getSite(), m_client);
+ m_client->connect(url);
+ }
+}
+
+Connection::~Connection()
+{
+ delete m_client;
+}
+
+bool Connection::isConnected()
+{
+ return !static_cast<Session*>(parent())->isRemote() || m_client->socket()->isConnected();
+}
+
+void Connection::acquire(KFTPQueue::Transfer *transfer)
+{
+ if (m_busy || !static_cast<Session*>(parent())->isRemote())
+ return;
+
+ m_curTransfer = transfer;
+ m_busy = true;
+
+ connect(transfer, SIGNAL(transferComplete(long)), this, SLOT(slotTransferCompleted()));
+ connect(transfer, SIGNAL(transferAbort(long)), this, SLOT(slotTransferCompleted()));
+
+ emit connectionAcquired();
+}
+
+void Connection::remove()
+{
+ // Disconnect all signals from the transfer
+ if (m_curTransfer)
+ m_curTransfer->QObject::disconnect(this);
+
+ m_curTransfer = 0L;
+ m_busy = false;
+
+ emit connectionRemoved();
+ emit static_cast<Session*>(parent())->freeConnectionAvailable();
+}
+
+void Connection::abort()
+{
+ if (m_aborting || !m_client->socket()->isBusy())
+ return;
+
+ // Emit the signal before aborting
+ emit aborting();
+
+ // Abort transfer
+ m_aborting = true;
+ m_client->abort();
+ m_aborting = false;
+}
+
+void Connection::scanDirectory(KFTPQueue::Transfer *parent)
+{
+ // Lock the connection and the transfer
+ acquire(parent);
+ parent->lock();
+
+ m_scanning = true;
+
+ if (isConnected())
+ m_client->scan(parent->getSourceUrl());
+}
+
+void Connection::addScannedDirectory(KFTPEngine::DirectoryTree *tree, KFTPQueue::Transfer *parent)
+{
+ // Directories
+ DirectoryTree::DirIterator dirEnd = tree->directories()->end();
+ for (DirectoryTree::DirIterator i = tree->directories()->begin(); i != dirEnd; i++) {
+ KURL sourceUrlBase = parent->getSourceUrl();
+ KURL destUrlBase = parent->getDestUrl();
+
+ sourceUrlBase.addPath((*i)->info().filename());
+ destUrlBase.addPath((*i)->info().filename());
+
+ // Check if we should skip this entry
+ const ActionChain *actionChain = Filters::self()->process(sourceUrlBase, 0, true);
+
+ if (actionChain && actionChain->getAction(Action::Skip))
+ continue;
+
+ // Add directory transfer
+ KFTPQueue::TransferDir *transfer = new KFTPQueue::TransferDir(parent);
+ transfer->setSourceUrl(sourceUrlBase);
+ transfer->setDestUrl(destUrlBase);
+ transfer->setTransferType(parent->getTransferType());
+ transfer->setId(KFTPQueue::Manager::self()->nextTransferId());
+
+ emit KFTPQueue::Manager::self()->newTransfer(transfer);
+
+ addScannedDirectory(*i, transfer);
+
+ if (KFTPCore::Config::skipEmptyDirs() && !transfer->hasChildren())
+ KFTPQueue::Manager::self()->removeTransfer(transfer, false);
+ }
+
+ // Files
+ DirectoryTree::FileIterator fileEnd = tree->files()->end();
+ for (DirectoryTree::FileIterator i = tree->files()->begin(); i != fileEnd; i++) {
+ KURL sourceUrlBase = parent->getSourceUrl();
+ KURL destUrlBase = parent->getDestUrl();
+
+ sourceUrlBase.addPath((*i).filename());
+ destUrlBase.addPath((*i).filename());
+
+ // Check if we should skip this entry
+ const ActionChain *actionChain = Filters::self()->process(sourceUrlBase, (*i).size(), false);
+
+ if (actionChain && actionChain->getAction(Action::Skip))
+ continue;
+
+ // Add file transfer
+ KFTPQueue::TransferFile *transfer = new KFTPQueue::TransferFile(parent);
+ transfer->addSize((*i).size());
+ transfer->setSourceUrl(sourceUrlBase);
+ transfer->setDestUrl(destUrlBase);
+ transfer->setTransferType(parent->getTransferType());
+ transfer->setId(KFTPQueue::Manager::self()->nextTransferId());
+
+ emit KFTPQueue::Manager::self()->newTransfer(transfer);
+ }
+}
+
+void Connection::slotEngineEvent(KFTPEngine::Event *event)
+{
+ switch (event->type()) {
+ case Event::EventDisconnect: {
+ emit connectionLost(this);
+ break;
+ }
+ case Event::EventConnect: {
+ emit connectionEstablished();
+
+ if (m_scanning) {
+ // Connected successfully, let's scan
+ m_client->scan(m_curTransfer->getSourceUrl());
+ }
+ break;
+ }
+ case Event::EventError: {
+ ErrorCode error = event->getParameter(0).asErrorCode();
+
+ if (m_scanning && (error == ConnectFailed || error == LoginFailed || error == OperationFailed)) {
+ // Scanning should be aborted, since there was an error
+ m_scanning = false;
+ m_curTransfer->unlock();
+ remove();
+
+ emit static_cast<Session*>(parent())->dirScanDone();
+ }
+ break;
+ }
+ case Event::EventScanComplete: {
+ if (m_scanning) {
+ // We have the listing
+ DirectoryTree *tree = static_cast<DirectoryTree*>(event->getParameter(0).asData());
+ addScannedDirectory(tree, m_curTransfer);
+ delete tree;
+
+ m_scanning = false;
+ m_curTransfer->unlock();
+ remove();
+
+ emit static_cast<Session*>(parent())->dirScanDone();
+ }
+ break;
+ }
+ default: break;
+ }
+}
+
+void Connection::slotTransferCompleted()
+{
+ // Remove the lock
+ remove();
+}
+
+void Connection::reconnect()
+{
+ if (!m_client->socket()->isConnected()) {
+ KFTPBookmarks::Manager::self()->setupClient(static_cast<Session*>(parent())->getSite(), m_client);
+ m_client->connect(m_client->socket()->getCurrentUrl());
+ }
+}
+
+////////////////////////////////////////////////////////
+//////////////////// Session ////////////////////
+////////////////////////////////////////////////////////
+
+Session::Session(Side side)
+ : QObject(),
+ m_side(side),
+ m_remote(false),
+ m_aborting(false),
+ m_registred(false),
+ m_site(0)
+{
+ // Register this session
+ Manager::self()->registerSession(this);
+}
+
+Session::~Session()
+{
+}
+
+KFTPEngine::Thread *Session::getClient()
+{
+ // Return the first (core) connection's client
+ return m_connections.at(0)->getClient();
+}
+
+bool Session::isConnected()
+{
+ // If there are no connections, just check if the session is remote
+ if (m_connections.count() == 0)
+ return !m_remote;
+
+ return m_connections.at(0)->isConnected();
+}
+
+void Session::slotClientEngineEvent(KFTPEngine::Event *event)
+{
+ switch (event->type()) {
+ case Event::EventConnect: {
+ // ***************************************************************************
+ // ****************************** EventConnect *******************************
+ // ***************************************************************************
+ m_remote = true;
+ m_aborting = false;
+ m_lastUrl = getClient()->socket()->getCurrentUrl();
+
+ QString siteName;
+ if (m_site)
+ siteName = m_site->getAttribute("name");
+ else
+ siteName = m_lastUrl.host();
+
+ Manager::self()->getTabs(m_side)->changeTab(m_fileView, siteName);
+ Manager::self()->getStatTabs()->changeTab(m_log, i18n("Log (%1)").arg(siteName));
+ Manager::self()->getStatTabs()->showPage(m_log);
+ Manager::self()->doEmitUpdate();
+
+ KURL homeUrl = getClient()->socket()->getCurrentUrl();
+
+ if (m_site && !m_site->getProperty("defremotepath").isEmpty())
+ homeUrl.setPath(m_site->getProperty("defremotepath"));
+ else
+ homeUrl.setPath(getClient()->socket()->getDefaultDirectory());
+
+ m_fileView->setHomeUrl(homeUrl);
+ m_fileView->goHome();
+
+ Session *opposite = Manager::self()->getActive(oppositeSide(m_side));
+
+ if (m_site && !opposite->isRemote()) {
+ QString localPath = m_site->getProperty("deflocalpath");
+
+ if (!localPath.isEmpty())
+ opposite->getFileView()->openUrl(KURL(localPath));
+ }
+ break;
+ }
+ case Event::EventDisconnect: {
+ // ***************************************************************************
+ // **************************** EventDisconnect ******************************
+ // ***************************************************************************
+ m_remote = false;
+ m_aborting = false;
+
+ Manager::self()->getTabs(m_side)->changeTab(m_fileView, i18n("Local Session"));
+ Manager::self()->getStatTabs()->changeTab(m_log, "[" + i18n("Log") + "]");
+ Manager::self()->doEmitUpdate();
+
+ m_fileView->setHomeUrl(KURL(KFTPCore::Config::defLocalDir()));
+ m_fileView->goHome();
+ break;
+ }
+ case Event::EventCommand: m_log->ftpLog(1, event->getParameter(0).asString()); break;
+ case Event::EventMultiline: m_log->ftpLog(2, event->getParameter(0).asString()); break;
+ case Event::EventResponse: m_log->ftpLog(0, event->getParameter(0).asString()); break;
+ case Event::EventMessage: m_log->ftpLog(3, event->getParameter(0).asString()); break;
+ case Event::EventRetrySuccess: {
+ // ***************************************************************************
+ // ************************** EventRetrySuccess ******************************
+ // ***************************************************************************
+ if (KFTPCore::Config::showRetrySuccessBalloon()) {
+ KFTPWidgets::SystemTray::self()->showBalloon(i18n("Connection with %1 has been successfully established.").arg(getClient()->socket()->getCurrentUrl().host()));
+ }
+ break;
+ }
+ case Event::EventReloadNeeded: {
+ // We should only do refreshes if the queue is not being processed
+ if (KFTPQueue::Manager::self()->getNumRunning() == 0)
+ m_fileView->reload();
+ break;
+ }
+ case Event::EventPubkeyPassword: {
+ // A public-key authentication password was requested
+ QCString pass;
+ int ret = KPasswordDialog::getPassword(pass, i18n("Please provide your private key decryption password."));
+
+ if (ret == KPasswordDialog::Accepted) {
+ PubkeyWakeupEvent *event = new PubkeyWakeupEvent();
+ event->password = pass;
+
+ getClient()->wakeup(event);
+ } else {
+ getClient()->abort();
+ }
+ break;
+ }
+ default: break;
+ }
+}
+
+void Session::scanDirectory(KFTPQueue::Transfer *parent, Connection *connection)
+{
+ // Go trough all files in path and add them as transfers that have parent as their parent
+ // transfer
+ KURL path = parent->getSourceUrl();
+
+ if (path.isLocalFile()) {
+ connect(new DirectoryScanner(parent), SIGNAL(completed()), this, SIGNAL(dirScanDone()));
+ } else if (m_remote) {
+ if (!connection) {
+ if (!isFreeConnection()) {
+ emit dirScanDone();
+ return;
+ }
+
+ // Assign a new connection (it might be unconnected!)
+ connection = assignConnection();
+ }
+
+ connection->scanDirectory(parent);
+ }
+}
+
+void Session::abort()
+{
+ if (m_aborting)
+ return;
+
+ m_aborting = true;
+
+ emit aborting();
+
+ // Abort all connections
+ Connection *conn;
+ for (conn = m_connections.first(); conn; conn = m_connections.next()) {
+ conn->abort();
+ }
+
+ m_aborting = false;
+}
+
+void Session::reconnect(const KURL &url)
+{
+ // Set the reconnect url
+ m_reconnectUrl = url;
+
+ if (m_remote && getClient()->socket()->isConnected()) {
+ abort();
+
+ connect(getClient()->eventHandler(), SIGNAL(disconnected()), this, SLOT(slotStartReconnect()));
+ getClient()->disconnect();
+ } else {
+ // The session is already disconnected, just call the slot
+ slotStartReconnect();
+ }
+}
+
+void Session::slotStartReconnect()
+{
+ disconnect(getClient()->eventHandler(), SIGNAL(disconnected()), this, SLOT(slotStartReconnect()));
+
+ // Reconnect only if this is a remote url
+ if (!m_reconnectUrl.isLocalFile()) {
+ KFTPBookmarks::Manager::self()->setupClient(m_site, getClient());
+ getClient()->connect(m_reconnectUrl);
+ }
+
+ // Invalidate the url
+ m_reconnectUrl = KURL();
+}
+
+int Session::getMaxThreadCount()
+{
+ // First get the global thread count
+ int count = KFTPCore::Config::threadCount();
+
+ if (!KFTPCore::Config::threadUsePrimary())
+ count++;
+
+ // Try to see if threads are disabled for this site
+ if (count > 1 && isRemote()) {
+ if (m_site && m_site->getIntProperty("disableThreads"))
+ return 1;
+ }
+
+ return count;
+}
+
+bool Session::isFreeConnection()
+{
+ unsigned int max = getMaxThreadCount();
+ unsigned int free = 0;
+
+ if ((m_connections.count() < max && max > 1) || !isRemote())
+ return true;
+
+ Connection *conn;
+ for (conn = m_connections.first(); conn; conn = m_connections.next()) {
+ if (!conn->isBusy() && (!conn->isPrimary() || KFTPCore::Config::threadUsePrimary() || max == 1))
+ free++;
+ }
+
+ return free > 0;
+}
+
+Connection *Session::assignConnection()
+{
+ unsigned int max = getMaxThreadCount();
+
+ if (m_connections.count() == 0) {
+ // We need a new core connection
+ Connection *conn = new Connection(this, true);
+ m_connections.append(conn);
+
+ Manager::self()->doEmitUpdate();
+
+ return conn;
+ } else {
+ // Find a free connection
+ Connection *conn;
+ for (conn = m_connections.first(); conn; conn = m_connections.next()) {
+ if (!conn->isBusy() && (!conn->isPrimary() || KFTPCore::Config::threadUsePrimary() || max == 1))
+ return conn;
+ }
+
+ // No free connection has been found, but we may be able to create
+ // another (if we are within limits)
+ if (m_connections.count() < max) {
+ conn = new Connection(this);
+ m_connections.append(conn);
+
+ Manager::self()->doEmitUpdate();
+
+ return conn;
+ }
+ }
+
+ return 0;
+}
+
+void Session::disconnectAllConnections()
+{
+ // Abort any possible transfers first
+ abort();
+
+ // Now disconnect all connections
+ Connection *conn;
+
+ for (conn = m_connections.first(); conn; conn = m_connections.next()) {
+ if (conn->getClient()->socket()->isConnected()) {
+ conn->getClient()->disconnect();
+ }
+ }
+}
+
+////////////////////////////////////////////////////////
+/////////////////////// Manager ////////////////////////
+////////////////////////////////////////////////////////
+
+Manager *Manager::m_self = 0;
+
+Manager *Manager::self()
+{
+ return m_self;
+}
+
+Manager::Manager(QObject *parent, QTabWidget *stat, KFTPTabWidget *left, KFTPTabWidget *right)
+ : QObject(parent),
+ m_statTabs(stat),
+ m_leftTabs(left),
+ m_rightTabs(right),
+ m_active(0),
+ m_leftActive(0),
+ m_rightActive(0)
+{
+ Manager::m_self = this;
+
+ // Connect some signals
+ connect(left, SIGNAL(currentChanged(QWidget*)), this, SLOT(slotActiveChanged(QWidget*)));
+ connect(right, SIGNAL(currentChanged(QWidget*)), this, SLOT(slotActiveChanged(QWidget*)));
+
+ connect(left, SIGNAL(closeRequest(QWidget*)), this, SLOT(slotSessionCloseRequest(QWidget*)));
+ connect(right, SIGNAL(closeRequest(QWidget*)), this, SLOT(slotSessionCloseRequest(QWidget*)));
+}
+
+void Manager::registerSession(Session *session)
+{
+ m_active = session;
+
+ // Create some new stuff and assign it to the session
+ session->assignConnection();
+ session->m_fileView = new KFTPWidgets::Browser::View(0L, "", session->getClient(), session);
+ session->m_log = new KFTPWidgets::LogView();
+
+ // Install event filters
+ session->getFileView()->getDetailsView()->installEventFilter(this);
+ session->getFileView()->getTreeView()->installEventFilter(this);
+ session->getFileView()->m_toolBarFirst->installEventFilter(this);
+ session->getFileView()->m_toolBarSecond->installEventFilter(this);
+
+ connect(session->getFileView()->getDetailsView(), SIGNAL(clicked(QListViewItem*)), this, SLOT(slotSwitchFocus()));
+ connect(session->getFileView()->getTreeView(), SIGNAL(clicked(QListViewItem*)), this, SLOT(slotSwitchFocus()));
+ connect(session->getFileView()->m_toolBarFirst, SIGNAL(clicked(int)), this, SLOT(slotSwitchFocus()));
+ connect(session->getFileView()->m_toolBarSecond, SIGNAL(clicked(int)), this, SLOT(slotSwitchFocus()));
+
+ // Connect some signals
+ connect(session->getClient()->eventHandler(), SIGNAL(engineEvent(KFTPEngine::Event*)), session, SLOT(slotClientEngineEvent(KFTPEngine::Event*)));
+
+ // Assign GUI positions
+ m_statTabs->addTab(session->m_log, "[" + i18n("Log") + "]");
+ getTabs(session->m_side)->addTab(session->m_fileView, KFTPGrabberBase::loadSmallIcon("system"), i18n("Session"));
+
+ // Actually add the session
+ m_sessionList.append(session);
+ session->m_registred = true;
+}
+
+KFTPWidgets::Browser::View *Manager::getActiveView()
+{
+ if (m_active)
+ return m_active->getFileView();
+
+ return 0;
+}
+
+Session *Manager::getActiveSession()
+{
+ return m_active;
+}
+
+bool Manager::eventFilter(QObject *object, QEvent *event)
+{
+ if (event->type() == QEvent::FocusIn || event->type() == QEvent::MouseButtonPress) {
+ switchFocusToObject(object);
+ }
+
+ return false;
+}
+
+void Manager::slotSwitchFocus()
+{
+ switchFocusToObject(QObject::sender());
+}
+
+void Manager::switchFocusToObject(const QObject *object)
+{
+ if (!object)
+ return;
+
+ for (;;) {
+ if (object->isA("KFTPWidgets::Browser::View"))
+ break;
+
+ if (!(object = object->parent()))
+ break;
+ }
+
+ if (object) {
+ // We have the proper object
+ Session *session = find(static_cast<const KFTPWidgets::Browser::View*>(object));
+
+ if (session && session != m_active) {
+ m_active = session;
+
+ // Open the current session's log tab
+ if (session->isRemote())
+ m_statTabs->showPage(session->getLog());
+ }
+ }
+}
+
+void Manager::unregisterSession(Session *session)
+{
+ // Destroy all objects related to the session and remove it
+ getTabs(session->m_side)->removePage(session->m_fileView);
+ m_statTabs->removePage(session->m_log);
+
+ if (session->getClient()->socket()->isConnected()) {
+ session->abort();
+ session->getClient()->disconnect();
+ }
+
+ // Delete objects
+ session->m_fileView->deleteLater();
+ session->m_log->deleteLater();
+
+ // Actually remove the session
+ m_sessionList.remove(session);
+ delete session;
+
+ // Emit update
+ emit update();
+}
+
+void Manager::doEmitUpdate()
+{
+ emit update();
+}
+
+void Manager::disconnectAllSessions()
+{
+ Session *i;
+
+ for (i = m_sessionList.first(); i; i = m_sessionList.next())
+ i->disconnectAllConnections();
+}
+
+Session *Manager::find(KFTPEngine::Thread *client)
+{
+ Session *i;
+
+ for (i = m_sessionList.first(); i; i = m_sessionList.next()) {
+ if (i->getClient() == client)
+ return i;
+ }
+
+ return 0L;
+}
+
+Session *Manager::find(KFTPWidgets::Browser::View *fileView)
+{
+ Session *i;
+
+ for (i = m_sessionList.first(); i; i = m_sessionList.next()) {
+ if (i->m_fileView == fileView)
+ return i;
+ }
+
+ return 0L;
+}
+
+Session *Manager::find(KFTPWidgets::LogView *log)
+{
+ Session *i;
+
+ for (i = m_sessionList.first(); i; i = m_sessionList.next()) {
+ if (i->m_log == log)
+ return i;
+ }
+
+ return 0L;
+}
+
+Session *Manager::find(const KURL &url, bool mustUnlock)
+{
+ if (url.isLocalFile())
+ return find(true);
+
+ Session *i;
+
+ for (i = m_sessionList.first(); i; i = m_sessionList.next()) {
+ KURL tmp = i->getClient()->socket()->getCurrentUrl();
+ tmp.setPath(url.path());
+
+ if (tmp == url && i->isRemote() && i->isConnected() && (!mustUnlock || i->isFreeConnection()))
+ return i;
+ }
+
+ return 0L;
+}
+
+Session *Manager::find(bool local)
+{
+ Session *i;
+
+ for (i = m_sessionList.first(); i; i = m_sessionList.next()) {
+ if (i->m_remote != local)
+ return i;
+ }
+
+ return 0L;
+}
+
+Session *Manager::findLast(const KURL &url, Side side)
+{
+ if (url.isLocalFile())
+ return find(true);
+
+ Session *i;
+
+ for (i = m_sessionList.first(); i; i = m_sessionList.next()) {
+ KURL tmp = i->m_lastUrl;
+ tmp.setPath(url.path());
+
+ if (tmp == url && !i->isRemote() && (i->getSide() || side == IgnoreSide))
+ return i;
+ }
+
+ return 0L;
+}
+
+Session *Manager::spawnLocalSession(Side side, bool forceNew)
+{
+ // Creates a new local session
+ Session *session = 0L;
+
+ if (forceNew || (session = find(true)) == 0L || (session->m_side != side && side != IgnoreSide)) {
+ side = side == IgnoreSide ? LeftSide : side;
+
+ session = new Session(side);
+ session->m_remote = false;
+ getTabs(side)->changeTab(session->m_fileView, i18n("Local Session"));
+ getStatTabs()->changeTab(session->m_log, "[" + i18n("Log") + "]");
+ }
+
+ setActive(session);
+ return session;
+}
+
+Session *Manager::spawnRemoteSession(Side side, const KURL &remoteUrl, KFTPBookmarks::Site *site, bool mustUnlock)
+{
+ // Creates a new remote session and connects it to the correct server
+ Session *session;
+
+ if (remoteUrl.isLocalFile())
+ return spawnLocalSession(side);
+
+ if ((session = find(remoteUrl, mustUnlock)) == 0L || (session->m_side != side && side != IgnoreSide)) {
+ // Try to find the session that was last connected to this URL
+ if ((session = findLast(remoteUrl, side)) == 0L) {
+ // Attempt to reuse a local session if one exists one the right side
+ session = getActive(RightSide);
+
+ if (session->isRemote()) {
+ side = side == IgnoreSide ? RightSide : side;
+ session = new Session(side);
+ }
+ }
+
+ // Try to find the site by url if it is not set
+ if (!site)
+ site = KFTPBookmarks::Manager::self()->findSite(remoteUrl);
+
+ // Set properties
+ session->m_remote = true;
+ session->m_site = site;
+ m_active = session;
+
+ KFTPBookmarks::Manager::self()->setupClient(site, session->getClient());
+ session->getClient()->connect(remoteUrl);
+ }
+
+ return session;
+}
+
+void Manager::setActive(Session *session)
+{
+ // Make a session active on its own side ;)
+ Session *oldActive = getActive(session->m_side);
+
+ oldActive ? oldActive->m_active = false : 0;
+ session->m_active = true;
+
+ switch (session->m_side) {
+ case LeftSide: m_leftActive = session; break;
+ case RightSide: m_rightActive = session; break;
+ case IgnoreSide: qDebug("Invalid side specified!"); return;
+ }
+
+ // Refresh the GUI
+ getTabs(session->m_side)->showPage(session->m_fileView);
+}
+
+Session *Manager::getActive(Side side)
+{
+ switch (side) {
+ case LeftSide: return m_leftActive;
+ case RightSide: return m_rightActive;
+ case IgnoreSide: qDebug("Invalid side specified!"); break;
+ }
+
+ return NULL;
+}
+
+KFTPTabWidget *Manager::getTabs(Side side)
+{
+ switch (side) {
+ case LeftSide: return m_leftTabs;
+ case RightSide: return m_rightTabs;
+ case IgnoreSide: qDebug("Invalid side specified!"); break;
+ }
+
+ return NULL;
+}
+
+void Manager::slotActiveChanged(QWidget *page)
+{
+ Session *session = find(static_cast<KFTPWidgets::Browser::View*>(page));
+ setActive(session);
+}
+
+void Manager::slotSessionCloseRequest(QWidget *page)
+{
+ Session *session = find(static_cast<KFTPWidgets::Browser::View*>(page));
+
+ if (getTabs(session->m_side)->count() == 1) {
+ KMessageBox::error(0L, i18n("At least one session must remain open on each side."));
+ return;
+ }
+
+ if ((session->m_remote && session->getClient()->socket()->isBusy()) || !session->isFreeConnection()) {
+ KMessageBox::error(0L, i18n("Please finish all transfers before closing the session."));
+ return;
+ } else {
+ // Remove the session
+ if (session->getClient()->socket()->isConnected()) {
+ if (KMessageBox::questionYesNo(0L, i18n("This session is currently connected. Are you sure you wish to disconnect?"), i18n("Close Session")) == KMessageBox::No)
+ return;
+ }
+
+ unregisterSession(session);
+ }
+}
+
+}
+
+#include "kftpsession.moc"