summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@nokia.com>2011-07-26 18:13:11 +0200
committerChristian Kandeler <christian.kandeler@nokia.com>2011-07-26 18:17:11 +0200
commitd59a64c7dfbd6d21218520bdee23c324acf00eba (patch)
treebd42c8c57b44ddc1c4877e33e18cb30ad7a59db0
parenta3e517415d3a84570fedc8fb2fb216e65e471d15 (diff)
downloadqt-creator-d59a64c7dfbd6d21218520bdee23c324acf00eba.tar.gz
SSH: Implement remote shell support.
Change-Id: Ifcddd930bbf027f4828f8ba01544aca5dea1eeed Reviewed-on: http://codereview.qt.nokia.com/2220 Reviewed-by: Christian Kandeler <christian.kandeler@nokia.com>
-rw-r--r--src/libs/utils/ssh/sshchannelmanager.cpp7
-rw-r--r--src/libs/utils/ssh/sshchannelmanager_p.h1
-rw-r--r--src/libs/utils/ssh/sshconnection.cpp11
-rw-r--r--src/libs/utils/ssh/sshconnection.h1
-rw-r--r--src/libs/utils/ssh/sshconnection_p.h1
-rw-r--r--src/libs/utils/ssh/sshoutgoingpacket.cpp6
-rw-r--r--src/libs/utils/ssh/sshoutgoingpacket_p.h1
-rw-r--r--src/libs/utils/ssh/sshremoteprocess.cpp60
-rw-r--r--src/libs/utils/ssh/sshremoteprocess.h3
-rw-r--r--src/libs/utils/ssh/sshremoteprocess_p.h4
-rw-r--r--src/libs/utils/ssh/sshsendfacility.cpp6
-rw-r--r--src/libs/utils/ssh/sshsendfacility_p.h1
-rw-r--r--tests/manual/ssh/shell/main.cpp57
-rw-r--r--tests/manual/ssh/shell/shell.cpp121
-rw-r--r--tests/manual/ssh/shell/shell.h70
-rw-r--r--tests/manual/ssh/shell/shell.pro6
-rw-r--r--tests/manual/ssh/ssh.pro2
17 files changed, 344 insertions, 14 deletions
diff --git a/src/libs/utils/ssh/sshchannelmanager.cpp b/src/libs/utils/ssh/sshchannelmanager.cpp
index 3110d33d18..65c805e572 100644
--- a/src/libs/utils/ssh/sshchannelmanager.cpp
+++ b/src/libs/utils/ssh/sshchannelmanager.cpp
@@ -156,6 +156,13 @@ Utils::SshRemoteProcess::Ptr SshChannelManager::createRemoteProcess(const QByteA
return proc;
}
+Utils::SshRemoteProcess::Ptr SshChannelManager::createRemoteShell()
+{
+ SshRemoteProcess::Ptr proc(new SshRemoteProcess(m_nextLocalChannelId++, m_sendFacility));
+ insertChannel(proc->d, proc);
+ return proc;
+}
+
Utils::SftpChannel::Ptr SshChannelManager::createSftpChannel()
{
SftpChannel::Ptr sftp(new SftpChannel(m_nextLocalChannelId++, m_sendFacility));
diff --git a/src/libs/utils/ssh/sshchannelmanager_p.h b/src/libs/utils/ssh/sshchannelmanager_p.h
index e3ff542187..8cf35502c0 100644
--- a/src/libs/utils/ssh/sshchannelmanager_p.h
+++ b/src/libs/utils/ssh/sshchannelmanager_p.h
@@ -55,6 +55,7 @@ public:
SshChannelManager(SshSendFacility &sendFacility, QObject *parent);
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
+ QSharedPointer<SshRemoteProcess> createRemoteShell();
QSharedPointer<SftpChannel> createSftpChannel();
void closeAllChannels();
diff --git a/src/libs/utils/ssh/sshconnection.cpp b/src/libs/utils/ssh/sshconnection.cpp
index 5ff083e6d2..7e458e28f7 100644
--- a/src/libs/utils/ssh/sshconnection.cpp
+++ b/src/libs/utils/ssh/sshconnection.cpp
@@ -178,6 +178,12 @@ QSharedPointer<SshRemoteProcess> SshConnection::createRemoteProcess(const QByteA
return d->createRemoteProcess(command);
}
+QSharedPointer<SshRemoteProcess> SshConnection::createRemoteShell()
+{
+ QTC_ASSERT(state() == Connected, return QSharedPointer<SshRemoteProcess>());
+ return d->createRemoteShell();
+}
+
QSharedPointer<SftpChannel> SshConnection::createSftpChannel()
{
QTC_ASSERT(state() == Connected, return QSharedPointer<SftpChannel>());
@@ -678,6 +684,11 @@ QSharedPointer<SshRemoteProcess> SshConnectionPrivate::createRemoteProcess(const
return m_channelManager->createRemoteProcess(command);
}
+QSharedPointer<SshRemoteProcess> SshConnectionPrivate::createRemoteShell()
+{
+ return m_channelManager->createRemoteShell();
+}
+
QSharedPointer<SftpChannel> SshConnectionPrivate::createSftpChannel()
{
return m_channelManager->createSftpChannel();
diff --git a/src/libs/utils/ssh/sshconnection.h b/src/libs/utils/ssh/sshconnection.h
index 2791ab1b78..83493db53c 100644
--- a/src/libs/utils/ssh/sshconnection.h
+++ b/src/libs/utils/ssh/sshconnection.h
@@ -89,6 +89,7 @@ public:
~SshConnection();
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
+ QSharedPointer<SshRemoteProcess> createRemoteShell();
QSharedPointer<SftpChannel> createSftpChannel();
signals:
diff --git a/src/libs/utils/ssh/sshconnection_p.h b/src/libs/utils/ssh/sshconnection_p.h
index a3b728b73e..6eef908e5f 100644
--- a/src/libs/utils/ssh/sshconnection_p.h
+++ b/src/libs/utils/ssh/sshconnection_p.h
@@ -90,6 +90,7 @@ public:
void closeConnection(SshErrorCode sshError, SshError userError,
const QByteArray &serverErrorString, const QString &userErrorString);
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
+ QSharedPointer<SshRemoteProcess> createRemoteShell();
QSharedPointer<SftpChannel> createSftpChannel();
SshStateInternal state() const { return m_state; }
SshError error() const { return m_error; }
diff --git a/src/libs/utils/ssh/sshoutgoingpacket.cpp b/src/libs/utils/ssh/sshoutgoingpacket.cpp
index b7ab343433..e5f84a38a6 100644
--- a/src/libs/utils/ssh/sshoutgoingpacket.cpp
+++ b/src/libs/utils/ssh/sshoutgoingpacket.cpp
@@ -179,6 +179,12 @@ void SshOutgoingPacket::generateExecPacket(quint32 remoteChannel,
.appendBool(true).appendString(command).finalize();
}
+void SshOutgoingPacket::generateShellPacket(quint32 remoteChannel)
+{
+ init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("shell")
+ .appendBool(true).finalize();
+}
+
void SshOutgoingPacket::generateSftpPacket(quint32 remoteChannel)
{
init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel)
diff --git a/src/libs/utils/ssh/sshoutgoingpacket_p.h b/src/libs/utils/ssh/sshoutgoingpacket_p.h
index da322fabbb..fcb0f5baa8 100644
--- a/src/libs/utils/ssh/sshoutgoingpacket_p.h
+++ b/src/libs/utils/ssh/sshoutgoingpacket_p.h
@@ -69,6 +69,7 @@ public:
void generatePtyRequestPacket(quint32 remoteChannel,
const SshPseudoTerminal &terminal);
void generateExecPacket(quint32 remoteChannel, const QByteArray &command);
+ void generateShellPacket(quint32 remoteChannel);
void generateSftpPacket(quint32 remoteChannel);
void generateWindowAdjustPacket(quint32 remoteChannel, quint32 bytesToAdd);
void generateChannelDataPacket(quint32 remoteChannel,
diff --git a/src/libs/utils/ssh/sshremoteprocess.cpp b/src/libs/utils/ssh/sshremoteprocess.cpp
index 49cc556758..850c77c464 100644
--- a/src/libs/utils/ssh/sshremoteprocess.cpp
+++ b/src/libs/utils/ssh/sshremoteprocess.cpp
@@ -82,14 +82,13 @@ SshRemoteProcess::SshRemoteProcess(const QByteArray &command, quint32 channelId,
Internal::SshSendFacility &sendFacility)
: d(new Internal::SshRemoteProcessPrivate(command, channelId, sendFacility, this))
{
- connect(d, SIGNAL(started()), this, SIGNAL(started()),
- Qt::QueuedConnection);
- connect(d, SIGNAL(outputAvailable(QByteArray)), this,
- SIGNAL(outputAvailable(QByteArray)), Qt::QueuedConnection);
- connect(d, SIGNAL(errorOutputAvailable(QByteArray)), this,
- SIGNAL(errorOutputAvailable(QByteArray)), Qt::QueuedConnection);
- connect(d, SIGNAL(closed(int)), this, SIGNAL(closed(int)),
- Qt::QueuedConnection);
+ init();
+}
+
+SshRemoteProcess::SshRemoteProcess(quint32 channelId, Internal::SshSendFacility &sendFacility)
+ : d(new Internal::SshRemoteProcessPrivate(channelId, sendFacility, this))
+{
+ init();
}
SshRemoteProcess::~SshRemoteProcess()
@@ -100,6 +99,18 @@ SshRemoteProcess::~SshRemoteProcess()
delete d;
}
+void SshRemoteProcess::init()
+{
+ connect(d, SIGNAL(started()), this, SIGNAL(started()),
+ Qt::QueuedConnection);
+ connect(d, SIGNAL(outputAvailable(QByteArray)), this,
+ SIGNAL(outputAvailable(QByteArray)), Qt::QueuedConnection);
+ connect(d, SIGNAL(errorOutputAvailable(QByteArray)), this,
+ SIGNAL(errorOutputAvailable(QByteArray)), Qt::QueuedConnection);
+ connect(d, SIGNAL(closed(int)), this, SIGNAL(closed(int)),
+ Qt::QueuedConnection);
+}
+
void SshRemoteProcess::addToEnvironment(const QByteArray &var, const QByteArray &value)
{
if (d->channelState() == Internal::SshRemoteProcessPrivate::Inactive)
@@ -160,11 +171,31 @@ QByteArray SshRemoteProcess::exitSignal() const { return d->m_signal; }
namespace Internal {
SshRemoteProcessPrivate::SshRemoteProcessPrivate(const QByteArray &command,
- quint32 channelId, SshSendFacility &sendFacility, SshRemoteProcess *proc)
- : AbstractSshChannel(channelId, sendFacility), m_procState(NotYetStarted),
- m_wasRunning(false), m_exitCode(0), m_command(command),
- m_useTerminal(false), m_proc(proc)
+ quint32 channelId, SshSendFacility &sendFacility, SshRemoteProcess *proc)
+ : AbstractSshChannel(channelId, sendFacility),
+ m_command(command),
+ m_isShell(false),
+ m_useTerminal(false),
+ m_proc(proc)
+{
+ init();
+}
+
+SshRemoteProcessPrivate::SshRemoteProcessPrivate(quint32 channelId, SshSendFacility &sendFacility,
+ SshRemoteProcess *proc)
+ : AbstractSshChannel(channelId, sendFacility),
+ m_isShell(true),
+ m_useTerminal(true),
+ m_proc(proc)
+{
+ init();
+}
+
+void SshRemoteProcessPrivate::init()
{
+ m_procState = NotYetStarted;
+ m_wasRunning = false;
+ m_exitCode = 0;
}
void SshRemoteProcessPrivate::setProcState(ProcessState newState)
@@ -201,7 +232,10 @@ void SshRemoteProcessPrivate::handleOpenSuccessInternal()
if (m_useTerminal)
m_sendFacility.sendPtyRequestPacket(remoteChannel(), m_terminal);
- m_sendFacility.sendExecPacket(remoteChannel(), m_command);
+ if (m_isShell)
+ m_sendFacility.sendShellPacket(remoteChannel());
+ else
+ m_sendFacility.sendExecPacket(remoteChannel(), m_command);
setProcState(ExecRequested);
m_timeoutTimer->start(ReplyTimeout);
}
diff --git a/src/libs/utils/ssh/sshremoteprocess.h b/src/libs/utils/ssh/sshremoteprocess.h
index 12c3ea1921..e31447ee21 100644
--- a/src/libs/utils/ssh/sshremoteprocess.h
+++ b/src/libs/utils/ssh/sshremoteprocess.h
@@ -112,6 +112,9 @@ signals:
private:
SshRemoteProcess(const QByteArray &command, quint32 channelId,
Internal::SshSendFacility &sendFacility);
+ SshRemoteProcess(quint32 channelId, Internal::SshSendFacility &sendFacility);
+
+ void init();
Internal::SshRemoteProcessPrivate *d;
};
diff --git a/src/libs/utils/ssh/sshremoteprocess_p.h b/src/libs/utils/ssh/sshremoteprocess_p.h
index 7617c2b920..b36e722cb9 100644
--- a/src/libs/utils/ssh/sshremoteprocess_p.h
+++ b/src/libs/utils/ssh/sshremoteprocess_p.h
@@ -69,6 +69,8 @@ signals:
private:
SshRemoteProcessPrivate(const QByteArray &command, quint32 channelId,
SshSendFacility &sendFacility, SshRemoteProcess *proc);
+ SshRemoteProcessPrivate(quint32 channelId, SshSendFacility &sendFacility,
+ SshRemoteProcess *proc);
virtual void handleOpenSuccessInternal();
virtual void handleOpenFailureInternal();
@@ -78,6 +80,7 @@ private:
virtual void handleExitStatus(const SshChannelExitStatus &exitStatus);
virtual void handleExitSignal(const SshChannelExitSignal &signal);
+ void init();
void setProcState(ProcessState newState);
ProcessState m_procState;
@@ -86,6 +89,7 @@ private:
int m_exitCode;
const QByteArray m_command;
+ const bool m_isShell;
typedef QPair<QByteArray, QByteArray> EnvVar;
QList<EnvVar> m_env;
diff --git a/src/libs/utils/ssh/sshsendfacility.cpp b/src/libs/utils/ssh/sshsendfacility.cpp
index edf03bb72b..1608f11c3e 100644
--- a/src/libs/utils/ssh/sshsendfacility.cpp
+++ b/src/libs/utils/ssh/sshsendfacility.cpp
@@ -173,6 +173,12 @@ void SshSendFacility::sendExecPacket(quint32 remoteChannel,
sendPacket();
}
+void SshSendFacility::sendShellPacket(quint32 remoteChannel)
+{
+ m_outgoingPacket.generateShellPacket(remoteChannel);
+ sendPacket();
+}
+
void SshSendFacility::sendSftpPacket(quint32 remoteChannel)
{
m_outgoingPacket.generateSftpPacket(remoteChannel);
diff --git a/src/libs/utils/ssh/sshsendfacility_p.h b/src/libs/utils/ssh/sshsendfacility_p.h
index 5a1928f293..7d8d36a79a 100644
--- a/src/libs/utils/ssh/sshsendfacility_p.h
+++ b/src/libs/utils/ssh/sshsendfacility_p.h
@@ -76,6 +76,7 @@ public:
void sendEnvPacket(quint32 remoteChannel, const QByteArray &var,
const QByteArray &value);
void sendExecPacket(quint32 remoteChannel, const QByteArray &command);
+ void sendShellPacket(quint32 remoteChannel);
void sendSftpPacket(quint32 remoteChannel);
void sendWindowAdjustPacket(quint32 remoteChannel, quint32 bytesToAdd);
void sendChannelDataPacket(quint32 remoteChannel, const QByteArray &data);
diff --git a/tests/manual/ssh/shell/main.cpp b/tests/manual/ssh/shell/main.cpp
new file mode 100644
index 0000000000..5c1bdfcb54
--- /dev/null
+++ b/tests/manual/ssh/shell/main.cpp
@@ -0,0 +1,57 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+#include "../remoteprocess/argumentscollector.h"
+#include "shell.h"
+
+#include <utils/ssh/sshconnection.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+
+#include <cstdlib>
+#include <iostream>
+
+using namespace Utils;
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+ bool parseSuccess;
+ const Utils::SshConnectionParameters &parameters
+ = ArgumentsCollector(app.arguments()).collect(parseSuccess);
+ if (!parseSuccess)
+ return EXIT_FAILURE;
+ Shell shell(parameters);
+ shell.run();
+ return app.exec();
+}
diff --git a/tests/manual/ssh/shell/shell.cpp b/tests/manual/ssh/shell/shell.cpp
new file mode 100644
index 0000000000..344d7d53fa
--- /dev/null
+++ b/tests/manual/ssh/shell/shell.cpp
@@ -0,0 +1,121 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+#include "shell.h"
+
+#include <utils/ssh/sshconnection.h>
+#include <utils/ssh/sshremoteprocess.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QFile>
+#include <QtCore/QSocketNotifier>
+
+#include <cstdlib>
+#include <iostream>
+
+using namespace Utils;
+
+Shell::Shell(const Utils::SshConnectionParameters &parameters, QObject *parent)
+ : QObject(parent),
+ m_connection(SshConnection::create(parameters)),
+ m_stdin(new QFile(this))
+{
+ connect(m_connection.data(), SIGNAL(connected()), SLOT(handleConnected()));
+ connect(m_connection.data(), SIGNAL(dataAvailable(QString)), SLOT(handleShellMessage(QString)));
+ connect(m_connection.data(), SIGNAL(error(Utils::SshError)), SLOT(handleConnectionError()));
+}
+
+Shell::~Shell()
+{
+}
+
+void Shell::run()
+{
+ if (!m_stdin->open(stdin, QIODevice::ReadOnly | QIODevice::Unbuffered)) {
+ std::cerr << "Error: Cannot read from standard input." << std::endl;
+ qApp->exit(EXIT_FAILURE);
+ return;
+ }
+
+ m_connection->connectToHost();
+}
+
+void Shell::handleConnectionError()
+{
+ std::cerr << "SSH connection error: " << qPrintable(m_connection->errorString()) << std::endl;
+ qApp->exit(EXIT_FAILURE);
+}
+
+void Shell::handleShellMessage(const QString &message)
+{
+ std::cout << qPrintable(message);
+}
+
+void Shell::handleConnected()
+{
+ m_shell = m_connection->createRemoteShell();
+ connect(m_shell.data(), SIGNAL(started()), SLOT(handleShellStarted()));
+ connect(m_shell.data(), SIGNAL(outputAvailable(QByteArray)),
+ SLOT(handleRemoteStdout(QByteArray)));
+ connect(m_shell.data(), SIGNAL(errorOutputAvailable(QByteArray)),
+ SLOT(handleRemoteStderr(QByteArray)));
+ connect(m_shell.data(), SIGNAL(closed(int)), SLOT(handleChannelClosed(int)));
+ m_shell->start();
+}
+
+void Shell::handleShellStarted()
+{
+ QSocketNotifier * const notifier = new QSocketNotifier(0, QSocketNotifier::Read, this);
+ connect(notifier, SIGNAL(activated(int)), SLOT(handleStdin()));
+}
+
+void Shell::handleRemoteStdout(const QByteArray &output)
+{
+ std::cout << output.data() << std::flush;
+}
+
+void Shell::handleRemoteStderr(const QByteArray &output)
+{
+ std::cerr << output.data() << std::flush;
+}
+
+void Shell::handleChannelClosed(int exitStatus)
+{
+ std::cerr << "Shell closed. Exit status was " << exitStatus << ", exit code was "
+ << m_shell->exitCode() << "." << std::endl;
+ qApp->exit(exitStatus == SshRemoteProcess::ExitedNormally && m_shell->exitCode() == 0
+ ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+void Shell::handleStdin()
+{
+ m_shell->sendInput(m_stdin->readLine());
+}
diff --git a/tests/manual/ssh/shell/shell.h b/tests/manual/ssh/shell/shell.h
new file mode 100644
index 0000000000..633b3197cb
--- /dev/null
+++ b/tests/manual/ssh/shell/shell.h
@@ -0,0 +1,70 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+#include <QtCore/QObject>
+#include <QtCore/QSharedPointer>
+
+namespace Utils {
+class SshConnection;
+class SshConnectionParameters;
+class SshRemoteProcess;
+}
+
+QT_BEGIN_NAMESPACE
+class QByteArray;
+class QFile;
+class QString;
+QT_END_NAMESPACE
+
+class Shell : public QObject
+{
+ Q_OBJECT
+public:
+ Shell(const Utils::SshConnectionParameters &parameters, QObject *parent = 0);
+ ~Shell();
+
+ void run();
+
+private slots:
+ void handleConnected();
+ void handleConnectionError();
+ void handleRemoteStdout(const QByteArray &output);
+ void handleRemoteStderr(const QByteArray &output);
+ void handleShellMessage(const QString &message);
+ void handleChannelClosed(int exitStatus);
+ void handleShellStarted();
+ void handleStdin();
+
+private:
+ QSharedPointer<Utils::SshConnection> m_connection;
+ QSharedPointer<Utils::SshRemoteProcess> m_shell;
+ QFile * const m_stdin;
+};
diff --git a/tests/manual/ssh/shell/shell.pro b/tests/manual/ssh/shell/shell.pro
new file mode 100644
index 0000000000..ed3b0d987e
--- /dev/null
+++ b/tests/manual/ssh/shell/shell.pro
@@ -0,0 +1,6 @@
+include(../ssh.pri)
+QT += network
+
+TARGET=shell
+SOURCES=main.cpp shell.cpp ../remoteprocess/argumentscollector.cpp
+HEADERS=shell.h ../remoteprocess/argumentscollector.h
diff --git a/tests/manual/ssh/ssh.pro b/tests/manual/ssh/ssh.pro
index a722b3d543..04f2420ad9 100644
--- a/tests/manual/ssh/ssh.pro
+++ b/tests/manual/ssh/ssh.pro
@@ -5,4 +5,4 @@
#-------------------------------------------------
TEMPLATE = subdirs
-SUBDIRS = errorhandling sftp remoteprocess
+SUBDIRS = errorhandling sftp remoteprocess shell