diff --git a/src/libs/3rdparty/botan/botan.pri b/src/libs/3rdparty/botan/botan.pri new file mode 100644 index 00000000000..e60343ac99b --- /dev/null +++ b/src/libs/3rdparty/botan/botan.pri @@ -0,0 +1,2 @@ +INCLUDEPATH += $$PWD/build +LIBS *= -l$$qtLibraryTarget(Botan) diff --git a/src/libs/3rdparty/net7ssh/net7ssh.pri b/src/libs/3rdparty/net7ssh/net7ssh.pri new file mode 100644 index 00000000000..6a3a923ab69 --- /dev/null +++ b/src/libs/3rdparty/net7ssh/net7ssh.pri @@ -0,0 +1,3 @@ +include(net7ssh_dependencies.pri) +INCLUDEPATH += $$PWD/src +LIBS *= -l$$qtLibraryTarget(Net7ssh) diff --git a/src/libs/3rdparty/net7ssh/net7ssh_dependencies.pri b/src/libs/3rdparty/net7ssh/net7ssh_dependencies.pri new file mode 100644 index 00000000000..d83ea3954d2 --- /dev/null +++ b/src/libs/3rdparty/net7ssh/net7ssh_dependencies.pri @@ -0,0 +1 @@ +include(../botan/botan.pri) diff --git a/src/libs/3rdparty/net7ssh/src/src.pro b/src/libs/3rdparty/net7ssh/src/src.pro index e7d2e40d529..a3eca025d79 100644 --- a/src/libs/3rdparty/net7ssh/src/src.pro +++ b/src/libs/3rdparty/net7ssh/src/src.pro @@ -8,7 +8,7 @@ include(../../../../qtcreatorlibrary.pri) DEPENDPATH += . INCLUDEPATH += $$PWD $$PWD/../../botan $$PWD/../../botan/build -LIBS += -l$$qtLibraryTarget(Botan) +include(../net7ssh_dependencies.pri) win32 { LIBS += -lWs2_32 diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index afdc2b9ee30..c28888d8b89 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -34,6 +34,7 @@ #include "modemanager.h" #include "fileiconprovider.h" #include "designmode.h" +#include "ssh/ne7sshobject.h" #include @@ -88,6 +89,7 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) m_designMode = new DesignMode(editorManager); addObject(m_designMode); + Ne7SshObject::instance(); } return success; } @@ -111,6 +113,7 @@ void CorePlugin::fileOpenRequest(const QString &f) void CorePlugin::shutdown() { m_mainWindow->shutdown(); + Ne7SshObject::removeInstance(); } Q_EXPORT_PLUGIN(CorePlugin) diff --git a/src/plugins/coreplugin/coreplugin.pro b/src/plugins/coreplugin/coreplugin.pro index 349a0bffcd7..d5b30647137 100644 --- a/src/plugins/coreplugin/coreplugin.pro +++ b/src/plugins/coreplugin/coreplugin.pro @@ -83,7 +83,10 @@ SOURCES += mainwindow.cpp \ imode.cpp \ editormanager/systemeditor.cpp \ designmode.cpp \ - editortoolbar.cpp + editortoolbar.cpp \ + ssh/ne7sshobject.cpp \ + ssh/sshconnection.cpp \ + ssh/sshkeygenerator.cpp HEADERS += mainwindow.h \ editmode.h \ @@ -165,7 +168,10 @@ HEADERS += mainwindow.h \ eventfilteringmainwindow.h \ editormanager/systemeditor.h \ designmode.h \ - editortoolbar.h + editortoolbar.h \ + ssh/ne7sshobject.h \ + ssh/sshconnection.h \ + ssh/sshkeygenerator.h FORMS += dialogs/newdialog.ui \ actionmanager/commandmappings.ui \ diff --git a/src/plugins/coreplugin/coreplugin_dependencies.pri b/src/plugins/coreplugin/coreplugin_dependencies.pri index 8b548e71796..8726e1be080 100644 --- a/src/plugins/coreplugin/coreplugin_dependencies.pri +++ b/src/plugins/coreplugin/coreplugin_dependencies.pri @@ -1,2 +1,3 @@ include(../../libs/extensionsystem/extensionsystem.pri) include(../../libs/utils/utils.pri) +include(../../libs/3rdparty/net7ssh/net7ssh.pri) diff --git a/src/plugins/qt4projectmanager/qt-maemo/ne7sshobject.cpp b/src/plugins/coreplugin/ssh/ne7sshobject.cpp similarity index 95% rename from src/plugins/qt4projectmanager/qt-maemo/ne7sshobject.cpp rename to src/plugins/coreplugin/ssh/ne7sshobject.cpp index 943f8aeb051..9f94a55b970 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/ne7sshobject.cpp +++ b/src/plugins/coreplugin/ssh/ne7sshobject.cpp @@ -45,7 +45,7 @@ #include -namespace Qt4ProjectManager { +namespace Core { namespace Internal { Ne7SshObject *Ne7SshObject::instance() @@ -60,7 +60,7 @@ void Ne7SshObject::removeInstance() delete m_instance; } -QSharedPointer Ne7SshObject::get() +Ne7SshObject::Ptr Ne7SshObject::get() { QMutexLocker locker(&m_mutex); QSharedPointer shared = m_weakRef.toStrongRef(); @@ -78,4 +78,4 @@ Ne7SshObject::Ne7SshObject() Ne7SshObject *Ne7SshObject::m_instance = 0; } // namespace Internal -} // namespace Qt4ProjectManager +} // namespace Core diff --git a/src/plugins/qt4projectmanager/qt-maemo/ne7sshobject.h b/src/plugins/coreplugin/ssh/ne7sshobject.h similarity index 93% rename from src/plugins/qt4projectmanager/qt-maemo/ne7sshobject.h rename to src/plugins/coreplugin/ssh/ne7sshobject.h index deaa2b35e18..77d601ec869 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/ne7sshobject.h +++ b/src/plugins/coreplugin/ssh/ne7sshobject.h @@ -42,22 +42,26 @@ #ifndef NE7SSHOBJECT_H #define NE7SSHOBJECT_H +#include + #include #include #include class ne7ssh; -namespace Qt4ProjectManager { +namespace Core { namespace Internal { class Ne7SshObject { public: + typedef QSharedPointer Ptr; + static Ne7SshObject *instance(); static void removeInstance(); - QSharedPointer get(); + Ptr get(); private: Ne7SshObject(); @@ -71,6 +75,6 @@ private: }; } // namespace Internal -} // namespace Qt4ProjectManager +} // namespace Core #endif // NE7SSHOBJECT_H diff --git a/src/plugins/coreplugin/ssh/sshconnection.cpp b/src/plugins/coreplugin/ssh/sshconnection.cpp new file mode 100644 index 00000000000..27f418fe4c4 --- /dev/null +++ b/src/plugins/coreplugin/ssh/sshconnection.cpp @@ -0,0 +1,422 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of Qt Creator. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "sshconnection.h" + +#include "ne7sshobject.h" + +#include +#include +#include +#include + +#include + +#include + +namespace Core { + +namespace { + +class GenericSshConnection +{ + Q_DECLARE_TR_FUNCTIONS(GenericSshConnection) +public: + GenericSshConnection(const SshServerInfo &server) + : ssh(Internal::Ne7SshObject::instance()->get()), + m_server(server), + m_channel(-1) + { } + + ~GenericSshConnection() + { + quit(); + } + + bool start(bool shell) + { + Q_ASSERT(m_channel == -1); + + try { + const QString *authString; + int (ne7ssh::*connFunc)(const char *, int, const char *, + const char *, bool, int); + if (m_server.authType == SshServerInfo::AuthByPwd) { + authString = &m_server.pwd; + connFunc = &ne7ssh::connectWithPassword; + } else { + authString = &m_server.privateKeyFile; + connFunc = &ne7ssh::connectWithKey; + } + m_channel = (ssh.data()->*connFunc)(m_server.host.toLatin1(), + m_server.port, m_server.uname.toAscii(), + authString->toLatin1(), shell, m_server.timeout); + if (m_channel == -1) { + setError(tr("Could not connect to host."), false); + return false; + } + } catch (const std::exception &e) { + // Should in theory not be necessary, but Net7 leaks Botan exceptions. + setError(tr("Error in cryptography backend: %1") + .arg(QLatin1String(e.what())), false); + return false; + } + + return true; + } + + void quit() + { + const int channel = m_channel; + if (channel != -1) { + m_channel = -1; + if (!ssh->close(channel)) + qWarning("%s: close() failed.", Q_FUNC_INFO); + } + } + + bool hasError() const { return !m_error.isEmpty(); } + QString error() const { return m_error; } + int channel() const { return m_channel; } + QString lastNe7Error() { return ssh->errors()->pop(channel()); } + const SshServerInfo &server() { return m_server; } + + void setError(const QString error, bool appendNe7ErrMsg) + { + m_error = error; + if (appendNe7ErrMsg) + m_error += QLatin1String(": ") + lastNe7Error(); + } + + QSharedPointer ssh; +private: + const SshServerInfo m_server; + QString m_error; + int m_channel; +}; + + +char *alloc(size_t n) +{ + return new char[n]; +} + +} // anonymous namespace + +namespace Internal { + +struct InteractiveSshConnectionPrivate +{ + InteractiveSshConnectionPrivate(const SshServerInfo &server) + : conn(server), outputReader(0) {} + + GenericSshConnection conn; + ConnectionOutputReader *outputReader; +}; + +struct NonInteractiveSshConnectionPrivate +{ + NonInteractiveSshConnectionPrivate(const SshServerInfo &server) + : conn(server) {} + + GenericSshConnection conn; + Ne7SftpSubsystem sftp; +}; + +class ConnectionOutputReader : public QThread +{ +public: + ConnectionOutputReader(InteractiveSshConnection *parent) + : QThread(parent), m_conn(parent), m_stopRequested(false) + {} + + ~ConnectionOutputReader() + { + stop(); + wait(); + } + + // TODO: Use a wakeup mechanism here as soon as we no longer poll for output + // from Net7. + void stop() + { + m_stopRequested = true; + } + +private: + virtual void run() + { + while (!m_stopRequested) { + const int channel = m_conn->d->conn.channel(); + if (channel != -1) { + QScopedPointer > + output(m_conn->d->conn.ssh->readAndReset(channel, alloc)); + if (output) + emit m_conn->remoteOutput(QByteArray(output.data())); + } + sleep(1); // TODO: Hack Net7 to enable wait() functionality. + } + } + + InteractiveSshConnection *m_conn; + bool m_stopRequested; +}; + +} // namespace Internal + + +InteractiveSshConnection::InteractiveSshConnection(const SshServerInfo &server) + : d(new Internal::InteractiveSshConnectionPrivate(server)) +{ + d->outputReader = new Internal::ConnectionOutputReader(this); +} + +InteractiveSshConnection::~InteractiveSshConnection() +{ + d->conn.ssh->send("exit\n", d->conn.channel()); + quit(); + delete d; +} + +bool InteractiveSshConnection::start() +{ + if (!d->conn.start(true)) + return false; + + d->outputReader->start(); + return true; +} + +bool InteractiveSshConnection::sendInput(const QByteArray &input) +{ + if (!d->conn.ssh->send(input.data(), d->conn.channel())) { + d->conn.setError(tr("Error sending input"), true); + return false; + } + return true; +} + +void InteractiveSshConnection::quit() +{ + d->outputReader->stop(); + d->conn.quit(); +} + +InteractiveSshConnection::Ptr InteractiveSshConnection::create(const SshServerInfo &server) +{ + return Ptr(new InteractiveSshConnection(server)); +} + +bool InteractiveSshConnection::hasError() const +{ + return d->conn.hasError(); +} + +QString InteractiveSshConnection::error() const +{ + return d->conn.error(); +} + + +namespace { + +class FileMgr +{ +public: + FileMgr(const QString &filePath, const char *mode) + : m_file(fopen(filePath.toLatin1().data(), mode)) {} + ~FileMgr() { if (m_file) fclose(m_file); } + FILE *file() const { return m_file; } +private: + FILE * const m_file; +}; + +} // Anonymous namespace + +SftpConnection::SftpConnection(const SshServerInfo &server) + : d(new Internal::NonInteractiveSshConnectionPrivate(server)) +{ } + +SftpConnection::~SftpConnection() +{ + quit(); + delete d; +} + +bool SftpConnection::start() +{ + if (!d->conn.start(false)) + return false; + if (!d->conn.ssh->initSftp(d->sftp, d->conn.channel()) + || !d->sftp.setTimeout(d->conn.server().timeout)) { + d->conn.setError(tr("Error setting up SFTP subsystem"), true); + return false; + } + return true; +} + +bool SftpConnection::transferFiles(const QList &transferList) +{ + for (int i = 0; i < transferList.count(); ++i) { + const SftpTransferInfo &transfer = transferList.at(i); + bool success; + if (transfer.type == SftpTransferInfo::Upload) { + success = upload(transfer.localFilePath, transfer.remoteFilePath); + } else { + success = download(transfer.remoteFilePath, transfer.localFilePath); + } + if (!success) + return false; + } + + return true; +} + +bool SftpConnection::upload(const QString &localFilePath, + const QByteArray &remoteFilePath) +{ + FileMgr fileMgr(localFilePath, "rb"); + if (!fileMgr.file()) { + d->conn.setError(tr("Could not open file '%1'").arg(localFilePath), + false); + return false; + } + + if (!d->sftp.put(fileMgr.file(), remoteFilePath.data())) { + d->conn.setError(tr("Could not uplodad file '%1'") + .arg(localFilePath), true); + return false; + } + + emit fileCopied(localFilePath); + return true; +} + +bool SftpConnection::download(const QByteArray &remoteFilePath, + const QString &localFilePath) +{ + FileMgr fileMgr(localFilePath, "wb"); + if (!fileMgr.file()) { + d->conn.setError(tr("Could not open file '%1'").arg(localFilePath), + false); + return false; + } + + if (!d->sftp.get(remoteFilePath.data(), fileMgr.file())) { + d->conn.setError(tr("Could not copy remote file '%1' to local file '%2'") + .arg(remoteFilePath, localFilePath), false); + return false; + } + + emit fileCopied(remoteFilePath); + return true; +} + +bool SftpConnection::createRemoteDir(const QByteArray &remoteDir) +{ + if (!d->sftp.mkdir(remoteDir.data())) { + d->conn.setError(tr("Could not create remote directory"), true); + return false; + } + return true; +} + +bool SftpConnection::removeRemoteDir(const QByteArray &remoteDir) +{ + if (!d->sftp.rmdir(remoteDir.data())) { + d->conn.setError(tr("Could not remove remote directory"), true); + return false; + } + return true; +} + +QByteArray SftpConnection::listRemoteDirContents(const QByteArray &remoteDir, + bool withAttributes, bool &ok) +{ + const char * const buffer = d->sftp.ls(remoteDir.data(), withAttributes); + if (!buffer) { + d->conn.setError(tr("Could not get remote directory contents"), true); + ok = false; + return QByteArray(); + } + ok = true; + return QByteArray(buffer); +} + +bool SftpConnection::removeRemoteFile(const QByteArray &remoteFile) +{ + if (!d->sftp.rm(remoteFile.data())) { + d->conn.setError(tr("Could not remove remote file"), true); + return false; + } + return true; +} + +bool SftpConnection::changeRemoteWorkingDir(const QByteArray &newRemoteDir) +{ + if (!d->sftp.cd(newRemoteDir.data())) { + d->conn.setError(tr("Could not change remote working directory"), true); + return false; + } + return true; +} + +void SftpConnection::quit() +{ + d->conn.quit(); +} + +bool SftpConnection::hasError() const +{ + return d->conn.hasError(); +} + +QString SftpConnection::error() const +{ + return d->conn.error(); +} + +SftpConnection::Ptr SftpConnection::create(const SshServerInfo &server) +{ + return Ptr(new SftpConnection(server)); +} + +} // namespace Core diff --git a/src/plugins/coreplugin/ssh/sshconnection.h b/src/plugins/coreplugin/ssh/sshconnection.h new file mode 100644 index 00000000000..767148769f4 --- /dev/null +++ b/src/plugins/coreplugin/ssh/sshconnection.h @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of Qt Creator. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SSHCONNECTION_H +#define SSHCONNECTION_H + +#include + +#include +#include +#include +#include + +namespace Core { + +namespace Internal { + struct InteractiveSshConnectionPrivate; + struct NonInteractiveSshConnectionPrivate; + class ConnectionOutputReader; +} + +struct CORE_EXPORT SshServerInfo +{ + QString host; + QString uname; + QString pwd; + QString privateKeyFile; + int timeout; + enum AuthType { AuthByPwd, AuthByKey } authType; + quint16 port; +}; + + +class CORE_EXPORT InteractiveSshConnection : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(InteractiveSshConnection) + friend class Internal::ConnectionOutputReader; +public: + typedef QSharedPointer Ptr; + + static Ptr create(const SshServerInfo &server); + + bool start(); + void quit(); + bool sendInput(const QByteArray &input); // Should normally end in newline. + bool hasError() const; + QString error() const; + ~InteractiveSshConnection(); + +signals: + void remoteOutput(const QByteArray &output); + +private: + InteractiveSshConnection(const SshServerInfo &server); + + struct Internal::InteractiveSshConnectionPrivate *d; +}; + + +struct CORE_EXPORT SftpTransferInfo +{ + enum Type { Upload, Download }; + + SftpTransferInfo(const QString &localFilePath, + const QByteArray &remoteFilePath, Type type) + : localFilePath(localFilePath), + remoteFilePath(remoteFilePath), + type(type) + { + } + + QString localFilePath; + QByteArray remoteFilePath; + Type type; +}; + +class CORE_EXPORT SftpConnection : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(SftpConnection) +public: + typedef QSharedPointer Ptr; + + static Ptr create(const SshServerInfo &server); + bool start(); + void quit(); + bool hasError() const; + QString error() const; + bool upload(const QString &localFilePath, const QByteArray &remoteFilePath); + bool download(const QByteArray &remoteFilePath, const QString &localFilePath); + bool transferFiles(const QList &transferList); + bool createRemoteDir(const QByteArray &remoteDir); + bool removeRemoteDir(const QByteArray &remoteDir); + bool removeRemoteFile(const QByteArray &remoteFile); + bool changeRemoteWorkingDir(const QByteArray &newRemoteDir); + QByteArray listRemoteDirContents(const QByteArray &remoteDir, + bool withAttributes, bool &ok); + ~SftpConnection(); + +signals: + void fileCopied(const QString &filePath); + +private: + SftpConnection(const SshServerInfo &server); + + Internal::NonInteractiveSshConnectionPrivate *d; +}; + +} // namespace Core + +#endif // SSHCONNECTION_H diff --git a/src/plugins/coreplugin/ssh/sshkeygenerator.cpp b/src/plugins/coreplugin/ssh/sshkeygenerator.cpp new file mode 100644 index 00000000000..17a63886e31 --- /dev/null +++ b/src/plugins/coreplugin/ssh/sshkeygenerator.cpp @@ -0,0 +1,56 @@ +#include "sshkeygenerator.h" + +#include "ne7sshobject.h" + +#include +#include + +#include + +namespace Core { + +SshKeyGenerator::SshKeyGenerator() +{ +} + +bool SshKeyGenerator::generateKeys(KeyType type, const QString &id, int keySize) +{ + QTemporaryFile tmpPubKeyFile; + QTemporaryFile tmpPrivKeyFile; + if (!tmpPubKeyFile.open() || !tmpPrivKeyFile.open()) { + m_error = tr("Error creating temporary files."); + return false; + } + tmpPubKeyFile.setAutoRemove(false); + tmpPubKeyFile.close(); + tmpPrivKeyFile.close(); + const char * const typeStr = type == Rsa ? "rsa" : "dsa"; + Internal::Ne7SshObject::Ptr ne7Object + = Internal::Ne7SshObject::instance()->get(); + if (!ne7Object->generateKeyPair(typeStr, id.toUtf8(), + tmpPrivKeyFile.fileName().toUtf8(), + tmpPubKeyFile.fileName().toUtf8(), keySize)) { + // TODO: Race condition on pop() call. Perhaps not use Net7 errors? Or hack API + m_error = tr("Error generating keys: %1") + .arg(ne7Object->errors()->pop()); + return false; + } + + if (!tmpPubKeyFile.open() || !tmpPrivKeyFile.open()) { + m_error = tr("Error reading temporary files."); + return false; + } + + m_publicKey = tmpPubKeyFile.readAll(); + m_privateKey = tmpPrivKeyFile.readAll(); + if (tmpPubKeyFile.error() != QFile::NoError + || tmpPrivKeyFile.error() != QFile::NoError) { + m_error = tr("Error reading temporary files."); + return false; + } + + m_type = type; + return true; +} + +} // namespace Core diff --git a/src/plugins/coreplugin/ssh/sshkeygenerator.h b/src/plugins/coreplugin/ssh/sshkeygenerator.h new file mode 100644 index 00000000000..a68237e576f --- /dev/null +++ b/src/plugins/coreplugin/ssh/sshkeygenerator.h @@ -0,0 +1,33 @@ +#ifndef SSHKEYGENERATOR_H +#define SSHKEYGENERATOR_H + +#include + +#include +#include + +namespace Core { + +class CORE_EXPORT SshKeyGenerator +{ + Q_DECLARE_TR_FUNCTIONS(SshKeyGenerator) +public: + enum KeyType { Rsa, Dsa }; + + SshKeyGenerator(); + bool generateKeys(KeyType type, const QString &id, int keySize); + QString error() const { return m_error; } + QString privateKey() const { return m_privateKey; } + QString publicKey() const { return m_publicKey; } + KeyType type() const { return m_type; } + +private: + QString m_error; + QString m_publicKey; + QString m_privateKey; + KeyType m_type; +}; + +} // namespace Core + +#endif // SSHKEYGENERATOR_H diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoconfigtestdialog.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemoconfigtestdialog.cpp index d92f0dc3179..eddb077acdd 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoconfigtestdialog.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoconfigtestdialog.cpp @@ -105,7 +105,7 @@ void MaemoConfigTestDialog::startConfigTest() "|sed 's/[[:space:]][[:space:]]*/ /g' " "|cut -d ' ' -f 2,3 |sed 's/~.*//g'"); QString command(sysInfoCmd + " && " + qtInfoCmd); - m_deviceTester = new MaemoSshRunner(m_config, command); + m_deviceTester = new MaemoSshRunner(m_config.server, command); connect(m_deviceTester, SIGNAL(remoteOutput(QString)), this, SLOT(processSshOutput(QString))); connect(m_deviceTester, SIGNAL(finished()), @@ -126,12 +126,12 @@ void MaemoConfigTestDialog::handleTestThreadFinished() output.append(tr("\nDid you start Qemu?")); } else { output = parseTestOutput(); + if (!m_qtVersionOk) { + m_ui->errorLabel->setText(tr("Qt version mismatch! " + " Expected Qt on device: 4.6.2 or later.")); + } } m_ui->testResultEdit->setPlainText(output); - if (!m_qtVersionOk) { - m_ui->errorLabel->setText(tr("Qt version mismatch! Expected Qt on device: " - "4.6.2 or later.")); - } stopConfigTest(); } diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.cpp index 4499b64eaf8..7ff2747ddfc 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.cpp @@ -42,6 +42,8 @@ #include +typedef Core::SshServerInfo::AuthType AuthType; + namespace Qt4ProjectManager { namespace Internal { @@ -78,7 +80,7 @@ namespace { const QString DefaultHostNameHW(QLatin1String("192.168.2.15")); const QString DefaultHostNameSim(QLatin1String("localhost")); const QString DefaultUserName(QLatin1String("developer")); - const MaemoDeviceConfig::AuthType DefaultAuthType(MaemoDeviceConfig::Key); + const AuthType DefaultAuthType(Core::SshServerInfo::AuthByKey); const int DefaultTimeout(30); const MaemoDeviceConfig::DeviceType DefaultDeviceType(MaemoDeviceConfig::Physical); }; @@ -98,33 +100,35 @@ private: MaemoDeviceConfig::MaemoDeviceConfig(const QString &name, MaemoDeviceConfig::DeviceType devType) : name(name), type(devType), - host(defaultHost(type)), - sshPort(defaultSshPort(type)), gdbServerPort(defaultGdbServerPort(type)), - uname(DefaultUserName), - authentication(DefaultAuthType), - keyFile(DefaultKeyFile), - timeout(DefaultTimeout), internalId(MaemoDeviceConfigurations::instance().m_nextId++) { + server.host = defaultHost(type); + server.port = defaultSshPort(type); + server.uname = DefaultUserName; + server.authType = DefaultAuthType; + server.privateKeyFile = DefaultKeyFile; + server.timeout = DefaultTimeout; } MaemoDeviceConfig::MaemoDeviceConfig(const QSettings &settings, quint64 &nextId) : name(settings.value(NameKey).toString()), type(static_cast(settings.value(TypeKey, DefaultDeviceType).toInt())), - host(settings.value(HostKey, defaultHost(type)).toString()), - sshPort(settings.value(SshPortKey, defaultSshPort(type)).toInt()), gdbServerPort(settings.value(GdbServerPortKey, defaultGdbServerPort(type)).toInt()), - uname(settings.value(UserNameKey, DefaultUserName).toString()), - authentication(static_cast(settings.value(AuthKey, DefaultAuthType).toInt())), - pwd(settings.value(PasswordKey).toString()), - keyFile(settings.value(KeyFileKey, DefaultKeyFile).toString()), - timeout(settings.value(TimeoutKey, DefaultTimeout).toInt()), internalId(settings.value(InternalIdKey, nextId).toInt()) { if (internalId == nextId) ++nextId; + server.host = settings.value(HostKey, defaultHost(type)).toString(); + server.port = settings.value(SshPortKey, defaultSshPort(type)).toInt(); + server.uname = settings.value(UserNameKey, DefaultUserName).toString(); + server.authType + = static_cast(settings.value(AuthKey, DefaultAuthType).toInt()); + server.pwd = settings.value(PasswordKey).toString(); + server.privateKeyFile + = settings.value(KeyFileKey, DefaultKeyFile).toString(); + server.timeout = settings.value(TimeoutKey, DefaultTimeout).toInt(); } MaemoDeviceConfig::MaemoDeviceConfig() @@ -156,14 +160,14 @@ void MaemoDeviceConfig::save(QSettings &settings) const { settings.setValue(NameKey, name); settings.setValue(TypeKey, type); - settings.setValue(HostKey, host); - settings.setValue(SshPortKey, sshPort); + settings.setValue(HostKey, server.host); + settings.setValue(SshPortKey, server.port); settings.setValue(GdbServerPortKey, gdbServerPort); - settings.setValue(UserNameKey, uname); - settings.setValue(AuthKey, authentication); - settings.setValue(PasswordKey, pwd); - settings.setValue(KeyFileKey, keyFile); - settings.setValue(TimeoutKey, timeout); + settings.setValue(UserNameKey, server.uname); + settings.setValue(AuthKey, server.authType); + settings.setValue(PasswordKey, server.pwd); + settings.setValue(KeyFileKey, server.privateKeyFile); + settings.setValue(TimeoutKey, server.timeout); settings.setValue(InternalIdKey, internalId); } diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.h b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.h index a478fe12902..7ffa28251ee 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.h @@ -35,6 +35,8 @@ #ifndef MAEMODEVICECONFIGURATIONS_H #define MAEMODEVICECONFIGURATIONS_H +#include + #include #include #include @@ -52,22 +54,16 @@ class MaemoDeviceConfig { public: enum DeviceType { Physical, Simulator }; - enum AuthType { Password, Key }; MaemoDeviceConfig(); MaemoDeviceConfig(const QString &name, DeviceType type); MaemoDeviceConfig(const QSettings &settings, quint64 &nextId); void save(QSettings &settings) const; bool isValid() const; + + Core::SshServerInfo server; QString name; DeviceType type; - QString host; - int sshPort; int gdbServerPort; - QString uname; - AuthType authentication; - QString pwd; - QString keyFile; - int timeout; quint64 internalId; private: diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemomanager.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemomanager.cpp index f03333e3568..feab08cd54f 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemomanager.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemomanager.cpp @@ -36,7 +36,6 @@ #include "maemosettingspage.h" #include "maemotoolchain.h" #include "maemorunconfiguration.h" -#include "ne7sshobject.h" #include #include @@ -83,8 +82,6 @@ MaemoManager::MaemoManager() pluginManager->addObject(m_runConfigurationFactory); pluginManager->addObject(m_packageCreationFactory); pluginManager->addObject(m_settingsPage); - - Ne7SshObject::instance(); } MaemoManager::~MaemoManager() @@ -96,7 +93,6 @@ MaemoManager::~MaemoManager() pluginManager->removeObject(m_packageCreationFactory); pluginManager->removeObject(m_settingsPage); - Ne7SshObject::removeInstance(); m_instance = 0; } diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp index 6fe2e12dfce..a2f639a78e3 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp @@ -123,7 +123,7 @@ void AbstractMaemoRunControl::startDeployment(bool forDebugging) emit finished(); } else { m_deployables.clear(); - if (m_runConfig->currentlyNeedsDeployment(m_devConfig.host)) { + if (m_runConfig->currentlyNeedsDeployment(m_devConfig.server.host)) { m_deployables.append(Deployable(packageFileName(), QFileInfo(executableOnHost()).canonicalPath(), &MaemoRunConfiguration::wasDeployed)); @@ -132,7 +132,7 @@ void AbstractMaemoRunControl::startDeployment(bool forDebugging) m_needsInstall = false; } if (forDebugging - && m_runConfig->debuggingHelpersNeedDeployment(m_devConfig.host)) { + && m_runConfig->debuggingHelpersNeedDeployment(m_devConfig.server.host)) { const QFileInfo &info(m_runConfig->dumperLib()); m_deployables.append(Deployable(info.fileName(), info.canonicalPath(), &MaemoRunConfiguration::debuggingHelpersDeployed)); @@ -148,7 +148,7 @@ void AbstractMaemoRunControl::deploy() ->addTask(m_progress.future(), tr("Deploying"), QLatin1String("Maemo.Deploy")); if (!m_deployables.isEmpty()) { - QList deploySpecs; + QList deploySpecs; QStringList files; foreach (const Deployable &deployable, m_deployables) { const QString srcFilePath @@ -156,10 +156,11 @@ void AbstractMaemoRunControl::deploy() const QString tgtFilePath = remoteDir() % QDir::separator() % deployable.fileName; files << srcFilePath; - deploySpecs << SshDeploySpec(srcFilePath, tgtFilePath); + deploySpecs << Core::SftpTransferInfo(srcFilePath, + tgtFilePath.toUtf8(), Core::SftpTransferInfo::Upload); } emit appendMessage(this, tr("Files to deploy: %1.").arg(files.join(" ")), false); - m_sshDeployer.reset(new MaemoSshDeployer(m_devConfig, deploySpecs)); + m_sshDeployer.reset(new MaemoSshDeployer(m_devConfig.server, deploySpecs)); connect(m_sshDeployer.data(), SIGNAL(finished()), this, SLOT(handleDeployThreadFinished())); connect(m_sshDeployer.data(), SIGNAL(fileCopied(QString)), @@ -177,7 +178,7 @@ void AbstractMaemoRunControl::deploy() void AbstractMaemoRunControl::handleFileCopied() { Deployable deployable = m_deployables.takeFirst(); - (m_runConfig->*deployable.updateTimestamp)(m_devConfig.host); + (m_runConfig->*deployable.updateTimestamp)(m_devConfig.server.host); m_progress.setProgressValue(m_progress.progressValue() + 1); } @@ -208,7 +209,7 @@ bool AbstractMaemoRunControl::isCleaning() const void AbstractMaemoRunControl::startExecution() { - m_sshRunner.reset(new MaemoSshRunner(m_devConfig, remoteCall())); + m_sshRunner.reset(new MaemoSshRunner(m_devConfig.server, remoteCall())); connect(m_sshRunner.data(), SIGNAL(finished()), this, SLOT(handleRunThreadFinished())); connect(m_sshRunner.data(), SIGNAL(remoteOutput(QString)), @@ -246,7 +247,7 @@ void AbstractMaemoRunControl::killRemoteProcesses(const QStringList &apps, remoteCall.remove(remoteCall.count() - 1, 1); // Get rid of trailing semicolon. QScopedPointer &runner = initialCleanup ? m_initialCleaner : m_sshStopper; - runner.reset(new MaemoSshRunner(m_devConfig, remoteCall)); + runner.reset(new MaemoSshRunner(m_devConfig.server, remoteCall)); if (initialCleanup) connect(runner.data(), SIGNAL(finished()), this, SLOT(handleInitialCleanupFinished())); @@ -296,7 +297,6 @@ void AbstractMaemoRunControl::handleRunThreadFinished() const QString AbstractMaemoRunControl::executableOnHost() const { - qDebug("runconfig->executable: %s", qPrintable(m_runConfig->executable())); return m_runConfig->executable(); } @@ -307,7 +307,7 @@ const QString AbstractMaemoRunControl::executableFileName() const const QString AbstractMaemoRunControl::remoteDir() const { - return homeDirOnDevice(m_devConfig.uname); + return homeDirOnDevice(m_devConfig.server.uname); } QString AbstractMaemoRunControl::remoteSudo() const @@ -384,7 +384,7 @@ MaemoDebugRunControl::MaemoDebugRunControl(RunConfiguration *runConfiguration) m_startParams->startMode = Debugger::StartRemote; m_startParams->executable = executableOnHost(); m_startParams->remoteChannel - = m_devConfig.host % QLatin1Char(':') % gdbServerPort(); + = m_devConfig.server.host % QLatin1Char(':') % gdbServerPort(); m_startParams->remoteArchitecture = QLatin1String("arm"); m_startParams->sysRoot = m_runConfig->sysRoot(); m_startParams->toolChainType = ToolChain::GCC_MAEMO; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosettingswidget.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemosettingswidget.cpp index beb9ab8a7ef..286f1473b83 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemosettingswidget.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemosettingswidget.cpp @@ -190,31 +190,31 @@ void MaemoSettingsWidget::display(const MaemoDeviceConfig &devConfig) otherConfig = &m_lastConfigHW; m_ui->simulatorButton->setChecked(true); } - otherConfig->authentication = devConfig.authentication; - otherConfig->timeout = devConfig.timeout; - otherConfig->pwd = devConfig.pwd; - otherConfig->keyFile = devConfig.keyFile; + otherConfig->server.authType = devConfig.server.authType; + otherConfig->server.timeout = devConfig.server.timeout; + otherConfig->server.pwd = devConfig.server.pwd; + otherConfig->server.privateKeyFile = devConfig.server.privateKeyFile; - if (devConfig.authentication == MaemoDeviceConfig::Password) + if (devConfig.server.authType == Core::SshServerInfo::AuthByPwd) m_ui->passwordButton->setChecked(true); else m_ui->keyButton->setChecked(true); m_ui->detailsWidget->setEnabled(true); m_nameValidator->setDisplayName(devConfig.name); - m_ui->timeoutSpinBox->setValue(devConfig.timeout); + m_ui->timeoutSpinBox->setValue(devConfig.server.timeout); fillInValues(); } void MaemoSettingsWidget::fillInValues() { m_ui->nameLineEdit->setText(currentConfig().name); - m_ui->hostLineEdit->setText(currentConfig().host); - m_ui->sshPortSpinBox->setValue(currentConfig().sshPort); + m_ui->hostLineEdit->setText(currentConfig().server.host); + m_ui->sshPortSpinBox->setValue(currentConfig().server.port); m_ui->gdbServerPortSpinBox->setValue(currentConfig().gdbServerPort); - m_ui->timeoutSpinBox->setValue(currentConfig().timeout); - m_ui->userLineEdit->setText(currentConfig().uname); - m_ui->pwdLineEdit->setText(currentConfig().pwd); - m_ui->keyFileLineEdit->setPath(currentConfig().keyFile); + m_ui->timeoutSpinBox->setValue(currentConfig().server.timeout); + m_ui->userLineEdit->setText(currentConfig().server.uname); + m_ui->pwdLineEdit->setText(currentConfig().server.pwd); + m_ui->keyFileLineEdit->setPath(currentConfig().server.privateKeyFile); const bool isSimulator = currentConfig().type == MaemoDeviceConfig::Simulator; @@ -269,9 +269,8 @@ void MaemoSettingsWidget::deviceTypeChanged() void MaemoSettingsWidget::authenticationTypeChanged() { const bool usePassword = m_ui->passwordButton->isChecked(); - currentConfig().authentication = usePassword - ? MaemoDeviceConfig::Password - : MaemoDeviceConfig::Key; + currentConfig().server.authType + = usePassword ? Core::SshServerInfo::AuthByPwd : Core::SshServerInfo::AuthByKey; m_ui->pwdLineEdit->setEnabled(usePassword); m_ui->passwordLabel->setEnabled(usePassword); m_ui->keyFileLineEdit->setEnabled(!usePassword); @@ -280,12 +279,12 @@ void MaemoSettingsWidget::authenticationTypeChanged() void MaemoSettingsWidget::hostNameEditingFinished() { - currentConfig().host = m_ui->hostLineEdit->text(); + currentConfig().server.host = m_ui->hostLineEdit->text(); } void MaemoSettingsWidget::sshPortEditingFinished() { - currentConfig().sshPort = m_ui->sshPortSpinBox->value(); + currentConfig().server.port = m_ui->sshPortSpinBox->value(); } void MaemoSettingsWidget::gdbServerPortEditingFinished() @@ -295,22 +294,22 @@ void MaemoSettingsWidget::gdbServerPortEditingFinished() void MaemoSettingsWidget::timeoutEditingFinished() { - currentConfig().timeout = m_ui->timeoutSpinBox->value(); + currentConfig().server.timeout = m_ui->timeoutSpinBox->value(); } void MaemoSettingsWidget::userNameEditingFinished() { - currentConfig().uname = m_ui->userLineEdit->text(); + currentConfig().server.uname = m_ui->userLineEdit->text(); } void MaemoSettingsWidget::passwordEditingFinished() { - currentConfig().pwd = m_ui->pwdLineEdit->text(); + currentConfig().server.pwd = m_ui->pwdLineEdit->text(); } void MaemoSettingsWidget::keyFileEditingFinished() { - currentConfig().keyFile = m_ui->keyFileLineEdit->path(); + currentConfig().server.privateKeyFile = m_ui->keyFileLineEdit->path(); } void MaemoSettingsWidget::testConfig() @@ -322,18 +321,9 @@ void MaemoSettingsWidget::testConfig() void MaemoSettingsWidget::showGenerateSshKeyDialog() { MaemoSshConfigDialog dialog(this); - connect(&dialog, SIGNAL(publicKeyGenerated(QString)), this, - SLOT(setPublicKey(QString))); - connect(&dialog, SIGNAL(privateKeyGenerated(QString)), this, - SLOT(setPrivateKey(QString))); dialog.exec(); } -void MaemoSettingsWidget::setPublicKey(const QString &path) -{ - m_publicKeyFileName = path; -} - void MaemoSettingsWidget::setPrivateKey(const QString &path) { m_ui->keyFileLineEdit->setPath(path); @@ -345,30 +335,29 @@ void MaemoSettingsWidget::deployKey() if (m_keyDeployer) return; - if (!QFileInfo(m_publicKeyFileName).exists()) { - const QString &dir = QFileInfo(currentConfig().keyFile).path(); - m_publicKeyFileName = QFileDialog::getOpenFileName(this, - tr("Choose public key file"), dir, - tr("Public Key Files(*.pub);;All Files (*)")); - } - - if (m_publicKeyFileName.isEmpty()) + const QString &dir + = QFileInfo(currentConfig().server.privateKeyFile).path(); + QString publicKeyFileName = QFileDialog::getOpenFileName(this, + tr("Choose public key file"), dir, + tr("Public Key Files(*.pub);;All Files (*)")); + if (publicKeyFileName.isEmpty()) return; - QFile keyFile(m_publicKeyFileName); + + QFile keyFile(publicKeyFileName); QByteArray key; const bool keyFileAccessible = keyFile.open(QIODevice::ReadOnly); if (keyFileAccessible) key = keyFile.readAll(); if (!keyFileAccessible || keyFile.error() != QFile::NoError) { QMessageBox::critical(this, tr("Deployment Failed"), - tr("Could not read public key file '%1'.").arg(m_publicKeyFileName)); + tr("Could not read public key file '%1'.").arg(publicKeyFileName)); return; } m_ui->deployKeyButton->disconnect(); const QString command = QLatin1String("test -d .ssh || mkdir .ssh && echo '") + key + QLatin1String("' >> .ssh/authorized_keys"); - m_keyDeployer = new MaemoSshRunner(currentConfig(), command); + m_keyDeployer = new MaemoSshRunner(currentConfig().server, command); connect(m_keyDeployer, SIGNAL(finished()), this, SLOT(handleDeployThreadFinished())); m_ui->deployKeyButton->setText(tr("Stop deploying")); @@ -399,7 +388,7 @@ void MaemoSettingsWidget::stopDeploying() m_keyDeployer->stop(); delete m_keyDeployer; m_keyDeployer = 0; - m_ui->deployKeyButton->setText(tr("Deploy Key ...")); + m_ui->deployKeyButton->setText(tr("Deploy Public Key ...")); connect(m_ui->deployKeyButton, SIGNAL(clicked()), this, SLOT(deployKey())); } } diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosettingswidget.h b/src/plugins/qt4projectmanager/qt-maemo/maemosettingswidget.h index 1c9a2b5bb8e..e8c676696a0 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemosettingswidget.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemosettingswidget.h @@ -82,7 +82,6 @@ private slots: void testConfig(); void showGenerateSshKeyDialog(); - void setPublicKey(const QString &path); void setPrivateKey(const QString &path); // For key deploying. @@ -104,7 +103,6 @@ private: MaemoDeviceConfig m_lastConfigSim; NameValidator * const m_nameValidator; MaemoSshRunner *m_keyDeployer; - QString m_publicKeyFileName; }; } // namespace Internal diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosettingswidget.ui b/src/plugins/qt4projectmanager/qt-maemo/maemosettingswidget.ui index a9cc6f9efa8..ff70b437e90 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemosettingswidget.ui +++ b/src/plugins/qt4projectmanager/qt-maemo/maemosettingswidget.ui @@ -6,7 +6,7 @@ 0 0 - 563 + 596 336 @@ -335,7 +335,7 @@ false - Deploy public Key ... + Deploy Public Key ... diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.cpp index f1fce1e23ab..19c86ba7f11 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.cpp @@ -35,23 +35,23 @@ #include "maemosshconfigdialog.h" #include "maemodeviceconfigurations.h" -#include "ne7sshobject.h" -#include +#include #include - -#include - #include #include #include +#include +#include + using namespace Qt4ProjectManager::Internal; MaemoSshConfigDialog::MaemoSshConfigDialog(QWidget *parent) : QDialog(parent) , home(QDesktopServices::storageLocation(QDesktopServices::HomeLocation)) + , m_keyGenerator(new Core::SshKeyGenerator) { m_ui.setupUi(this); @@ -75,26 +75,22 @@ void MaemoSshConfigDialog::slotToggled() void MaemoSshConfigDialog::generateSshKey() { - algorithm = m_ui.rsa->isChecked() ? "rsa" : "dsa"; - tmpKey = QDir::tempPath().append(QLatin1Char('/') + algorithm).toUtf8(); + const Core::SshKeyGenerator::KeyType keyType = m_ui.rsa->isChecked() + ? Core::SshKeyGenerator::Rsa + : Core::SshKeyGenerator::Dsa; + QByteArray userId = QString(home.mid(home.lastIndexOf(QLatin1Char('/')) + 1) + QLatin1Char('@') + QHostInfo::localHostName()).toUtf8(); - QFile::remove(tmpKey); - QFile::remove(tmpKey + ".pub"); - QApplication::setOverrideCursor(Qt::BusyCursor); - QSharedPointer ssh = Ne7SshObject::instance()->get(); - if (ssh->generateKeyPair(algorithm, userId, tmpKey, tmpKey + ".pub", - m_ui.comboBox->currentText().toUShort())) { - QFile file(tmpKey + ".pub"); - if (file.open(QIODevice::ReadOnly)) - m_ui.plainTextEdit->setPlainText(file.readAll()); + if (m_keyGenerator->generateKeys(keyType, userId, + m_ui.comboBox->currentText().toUShort())) { + m_ui.plainTextEdit->setPlainText(m_keyGenerator->publicKey()); m_ui.savePublicKey->setEnabled(true); m_ui.savePrivateKey->setEnabled(true); } else { - m_ui.plainTextEdit->setPlainText(tr("Could not create SSH key pair.")); + m_ui.plainTextEdit->setPlainText(m_keyGenerator->error()); } QApplication::restoreOverrideCursor(); @@ -102,18 +98,12 @@ void MaemoSshConfigDialog::generateSshKey() void MaemoSshConfigDialog::savePublicKey() { - checkSshDir(); - copyFile(QFileDialog::getSaveFileName(this, tr("Choose folder to save " - "public key file"), home + QString::fromLatin1("/.ssh/id_%1.pub") - .arg(algorithm.constData())), true); + saveKey(true); } void MaemoSshConfigDialog::savePrivateKey() { - checkSshDir(); - copyFile(QFileDialog::getSaveFileName(this, tr("Choose folder to save " - "private key file"), home + QString::fromLatin1("/.ssh/id_%1") - .arg(algorithm.constData())), false); + saveKey(false); } void MaemoSshConfigDialog::checkSshDir() @@ -123,15 +113,31 @@ void MaemoSshConfigDialog::checkSshDir() dir.mkpath(home + QString::fromLatin1("/.ssh")); } -void MaemoSshConfigDialog::copyFile(const QString &file, bool pubKey) +void MaemoSshConfigDialog::saveKey(bool publicKey) { - if (!file.isEmpty()) { - if (!QFile::exists(file) || QFile::remove(file)) { - QFile(tmpKey + (pubKey ? ".pub" : "")).copy(file); - if (pubKey) - emit publicKeyGenerated(file); - else - emit privateKeyGenerated(file); - } + checkSshDir(); + const QString suggestedTypeSuffix = + m_keyGenerator->type() == Core::SshKeyGenerator::Rsa ? "rsa" : "dsa"; + const QString suggestedName = home + QString::fromLatin1("/.ssh/id_%1%2") + .arg(suggestedTypeSuffix).arg(publicKey ? ".pub" : ""); + const QString dlgTitle + = publicKey ? tr("Save public key file") : tr("Save private key file"); + const QString fileName + = QFileDialog::getSaveFileName(this, dlgTitle, suggestedName); + if (fileName.isEmpty()) + return; + + QFile file(fileName); + const bool canOpen = file.open(QIODevice::WriteOnly); + if (canOpen) + file.write(publicKey + ? m_keyGenerator->publicKey().toUtf8() + : m_keyGenerator->privateKey().toUtf8()); + if (!canOpen || file.error() != QFile::NoError) { + QMessageBox::critical(this, tr("Error writing file"), + tr("Could not write file '%1':\n %2") + .arg(fileName, file.errorString())); + } else if (!publicKey) { + emit privateKeyGenerated(fileName); } } diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.h b/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.h index 6a246618e83..c8c7abe9c18 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.h @@ -37,8 +37,13 @@ #include "ui_maemosshconfigdialog.h" +#include #include +namespace Core { + class SshKeyGenerator; +} + namespace Qt4ProjectManager { namespace Internal { @@ -46,11 +51,10 @@ class MaemoSshConfigDialog : public QDialog { Q_OBJECT public: - MaemoSshConfigDialog(QWidget *parent = 0); - ~MaemoSshConfigDialog(); + MaemoSshConfigDialog(QWidget *parent = 0); + ~MaemoSshConfigDialog(); signals: - void publicKeyGenerated(const QString &path); void privateKeyGenerated(const QString &path); private slots: @@ -61,12 +65,11 @@ private slots: private: void checkSshDir(); - void copyFile(const QString &file, bool pubKey); + void saveKey(bool publicKey); private: QString home; - QByteArray tmpKey; - QByteArray algorithm; + QScopedPointer m_keyGenerator; Ui::MaemoSshConfigDialog m_ui; }; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosshconnection.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemosshconnection.cpp deleted file mode 100644 index 50c117889fd..00000000000 --- a/src/plugins/qt4projectmanager/qt-maemo/maemosshconnection.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Creator. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, 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. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "maemosshconnection.h" - -#include "maemodeviceconfigurations.h" -#include "ne7sshobject.h" - -#include - -#include -#include -#include - -#include -#include - -namespace Qt4ProjectManager { -namespace Internal { -namespace { - char *alloc(size_t n) - { - return new char[n]; - } -} - -// TODO: Which encoding to use for file names? Unicode? Latin1? ASCII? - -MaemoSshConnection::MaemoSshConnection(const MaemoDeviceConfig &devConf, - bool shell) - : ssh(Ne7SshObject::instance()->get()), - m_channel(-1), - m_stopRequested(false) -{ - const QString *authString; - int (ne7ssh::*connFunc)(const char *, int, const char *, const char *, bool, int); - if (devConf.authentication == MaemoDeviceConfig::Password) { - authString = &devConf.pwd; - connFunc = &ne7ssh::connectWithPassword; - } else { - authString = &devConf.keyFile; - connFunc = &ne7ssh::connectWithKey; - } - m_channel = (ssh.data()->*connFunc)(devConf.host.toLatin1(), devConf.sshPort, - devConf.uname.toAscii(), authString->toLatin1(), shell, devConf.timeout); - if (m_channel == -1) - throw MaemoSshException(tr("Could not connect to host")); -} - -MaemoSshConnection::~MaemoSshConnection() -{ - qDebug("%s", Q_FUNC_INFO); - ssh->close(m_channel); -} - -const char *MaemoSshConnection::lastError() -{ - return ssh->errors()->pop(channel()); -} - -void MaemoSshConnection::stop() -{ - m_stopRequested = true; -} - -MaemoInteractiveSshConnection::MaemoInteractiveSshConnection(const MaemoDeviceConfig &devConf) - : MaemoSshConnection(devConf, true) -{ - strcpy(m_prompt, devConf.uname == QLatin1String("root") ? "# " : "$ "); - if (!ssh->waitFor(channel(), m_prompt, devConf.timeout)) { - QScopedPointer > - shellString(ssh->readAndReset(channel(), alloc)); - if (!shellString.data()) { - const QString error - = tr("Could not start remote shell: %1").arg(lastError()); - throw MaemoSshException(error); - } else { - const int length = strlen(shellString.data()); - strcpy(m_prompt, shellString.data() + length - qMin(2, length)); - } - } -} - -MaemoInteractiveSshConnection::~MaemoInteractiveSshConnection() -{ - ssh->send("exit\n", channel()); - ssh->waitFor(channel(), m_prompt, 1); -} - -void MaemoInteractiveSshConnection::runCommand(const QString &command) -{ - /* - * We don't have access to the remote process management, so we - * try to track the lifetime of the process by adding a second command - * that prints a rare character. When it occurs for the second time (the - * first one is the echo from the remote terminal), we assume the - * process has finished. If anyone actually prints this special character - * in their application, they are out of luck. - */ - const QString endMarker(QChar(0x13a0)); - const int endMarkerLen = strlen(endMarker.toUtf8()); - - const QString finalCommand - = command + QLatin1String(";echo ") + endMarker + QLatin1Char('\n'); - if (!ssh->send(finalCommand.toUtf8().data(), channel())) { - throw MaemoSshException(tr("Error running command: %1") - .arg(lastError())); - } - - int endMarkerCount = 0; - do { - ssh->waitFor(channel(), endMarker.toUtf8(), 1); // TODO: Hack net7 to get rid of busy loop. - const char * const error = lastError(); - if (error) - throw MaemoSshException(tr("SSH error: %1").arg(error)); - QScopedPointer > - output(ssh->readAndReset(channel(), alloc)); - - /* - * The output the user should see is everything after the first - * and before the last occurrence of our marker string. - */ - if (output.data()) { - const char *firstCharToEmit; - int charsToEmitCount; - const char * const endMarkerPos - = strstr(output.data(), endMarker.toUtf8()); - if (endMarkerPos) { - if (endMarkerCount++ == 0) { - emit remoteOutput(QLatin1String("========== Remote output starts now. ==========\n")); - firstCharToEmit = endMarkerPos + endMarkerLen + 1; - const char * const endMarkerPos2 - = strstr(firstCharToEmit, endMarker.toUtf8()); - if (endMarkerPos2) { - ++ endMarkerCount; - charsToEmitCount = endMarkerPos2 - firstCharToEmit; - } else { - charsToEmitCount = -1; - } - } else { - firstCharToEmit = output.data(); - charsToEmitCount = endMarkerPos - output.data(); - } - } else { - if (endMarkerCount == 0) { - charsToEmitCount = 0; - } else { - firstCharToEmit = output.data(); - charsToEmitCount = -1; - } - } - - if (charsToEmitCount != 0) - emit remoteOutput(QString::fromUtf8(firstCharToEmit, charsToEmitCount)); - } - } while (endMarkerCount < 2 && !stopRequested()); - emit remoteOutput(QLatin1String("========== Remote output ends now. ==========\n")); -} - -MaemoInteractiveSshConnection::Ptr MaemoInteractiveSshConnection::create(const MaemoDeviceConfig &devConf) -{ - return Ptr(new MaemoInteractiveSshConnection(devConf)); -} - -MaemoSftpConnection::MaemoSftpConnection(const MaemoDeviceConfig &devConf) - : MaemoSshConnection(devConf, false), - sftp(new Ne7SftpSubsystem) -{ - if (!ssh->initSftp(*sftp, channel()) || !sftp->setTimeout(devConf.timeout)) - throw MaemoSshException(tr("Error setting up SFTP subsystem: %1") - .arg(lastError())); -} - -MaemoSftpConnection::~MaemoSftpConnection() -{ -} - -class FileManager -{ -public: - FileManager(const QString &filePath) - : m_file(fopen(filePath.toLatin1().data(), "rb")) {} - ~FileManager() { if (m_file) fclose(m_file); } - FILE *file() const { return m_file; } -private: - FILE * const m_file; -}; - -void MaemoSftpConnection::transferFiles(const QList &deploySpecs) -{ - for (int i = 0; i < deploySpecs.count() && !stopRequested(); ++i) { - const SshDeploySpec &deploySpec = deploySpecs.at(i); - const QString &curSrcFile = deploySpec.srcFilePath(); - FileManager fileMgr(curSrcFile); - if (!fileMgr.file()) - throw MaemoSshException(tr("Could not open file '%1'").arg(curSrcFile)); - const QString &curTgtFile = deploySpec.tgtFilePath(); - - // TODO: Is the mkdir() method recursive? If not, we have to - // introduce a recursive version ourselves. - if (deploySpec.mkdir()) { - const QString &dir = QFileInfo(curTgtFile).path(); - sftp->mkdir(dir.toLatin1().data()); - } - - qDebug("Deploying file %s to %s.", qPrintable(curSrcFile), qPrintable(curTgtFile)); - - if (!sftp->put(fileMgr.file(), curTgtFile.toLatin1().data())) { - const QString &error = tr("Could not copy local file '%1' " - "to remote file '%2': %3").arg(curSrcFile, curTgtFile) - .arg(lastError()); - throw MaemoSshException(error); - } - emit fileCopied(curSrcFile); - } -} - -MaemoSftpConnection::Ptr MaemoSftpConnection::create(const MaemoDeviceConfig &devConf) -{ - return Ptr(new MaemoSftpConnection(devConf)); -} - -} // namespace Internal -} // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosshconnection.h b/src/plugins/qt4projectmanager/qt-maemo/maemosshconnection.h deleted file mode 100644 index 6b46d568092..00000000000 --- a/src/plugins/qt4projectmanager/qt-maemo/maemosshconnection.h +++ /dev/null @@ -1,152 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Creator. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, 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. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef MAEMOSSHCONNECTION_H -#define MAEMOSSHCONNECTION_H - -#include -#include -#include -#include - -class ne7ssh; -class Ne7SftpSubsystem; - -namespace Qt4ProjectManager { -namespace Internal { - -class MaemoDeviceConfig; - -class MaemoSshException -{ -public: - MaemoSshException(const QString &error) : m_error(error) {} - const QString &error() const { return m_error; } -private: - const QString m_error; -}; - -class MaemoSshConnection : public QObject -{ - Q_OBJECT - Q_DISABLE_COPY(MaemoSshConnection) -public: - typedef QSharedPointer Ptr; - - void stop(); - virtual ~MaemoSshConnection(); - -protected: - MaemoSshConnection(const MaemoDeviceConfig &devConf, bool shell); - int channel() const { return m_channel; } - bool stopRequested() const {return m_stopRequested; } - const char *lastError(); - - QSharedPointer ssh; -private: - int m_channel; - volatile bool m_stopRequested; -}; - -class MaemoInteractiveSshConnection : public MaemoSshConnection -{ - Q_OBJECT - Q_DISABLE_COPY(MaemoInteractiveSshConnection) -public: - typedef QSharedPointer Ptr; - - static Ptr create(const MaemoDeviceConfig &devConf); - void runCommand(const QString &command); - virtual ~MaemoInteractiveSshConnection(); - -signals: - void remoteOutput(const QString &output); - -private: - MaemoInteractiveSshConnection(const MaemoDeviceConfig &devConf); - - char m_prompt[3]; -}; - - -class SshDeploySpec -{ -public: - SshDeploySpec(const QString &srcFilePath, const QString &tgtFilePath, - bool mkdir = false) - : m_srcFilePath(srcFilePath), m_tgtFilePath(tgtFilePath), m_mkdir(mkdir) - { - } - - QString srcFilePath() const { return m_srcFilePath; } - QString tgtFilePath() const { return m_tgtFilePath; } - bool mkdir() const { return m_mkdir; } - -private: - QString m_srcFilePath; - QString m_tgtFilePath; - bool m_mkdir; -}; - -class MaemoSftpConnection : public MaemoSshConnection -{ - Q_OBJECT - Q_DISABLE_COPY(MaemoSftpConnection) -public: - typedef QSharedPointer Ptr; - - static Ptr create(const MaemoDeviceConfig &devConf); - void transferFiles(const QList &deploySpecs); - virtual ~MaemoSftpConnection(); - -signals: - void fileCopied(const QString &filePath); - -private: - MaemoSftpConnection(const MaemoDeviceConfig &devConf); - - QScopedPointer sftp; -}; - -} // namespace Internal -} // namespace Qt4ProjectManager - -#endif // MAEMOSSHCONNECTION_H diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosshthread.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemosshthread.cpp index beaed3f0443..3d2b8a09a12 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemosshthread.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemosshthread.cpp @@ -41,86 +41,164 @@ #include "maemosshthread.h" -#include - namespace Qt4ProjectManager { namespace Internal { -MaemoSshThread::MaemoSshThread(const MaemoDeviceConfig &devConf) - : m_stopRequested(false), m_devConf(devConf) +template MaemoSshThread::MaemoSshThread(const Core::SshServerInfo &server) + : m_server(server), m_stopRequested(false) { } -MaemoSshThread::~MaemoSshThread() +template MaemoSshThread::~MaemoSshThread() { stop(); wait(); } -void MaemoSshThread::run() +template void MaemoSshThread::run() { - try { - if (!m_stopRequested) - runInternal(); - } catch (const MaemoSshException &e) { - m_error = e.error(); - } catch (const std::exception &e) { - // Should in theory not be necessary, but Net7 leaks Botan exceptions. - m_error = tr("Error in cryptography backend: %1").arg(QLatin1String(e.what())); - } + if (m_stopRequested) + return; + + if (!runInternal()) + m_error = m_connection->error(); } -void MaemoSshThread::stop() +template void MaemoSshThread::stop() { m_mutex.lock(); m_stopRequested = true; + m_waitCond.wakeAll(); const bool hasConnection = !m_connection.isNull(); - m_mutex.unlock(); if (hasConnection) - m_connection->stop(); + m_connection->quit(); + m_mutex.unlock(); } -template typename Conn::Ptr MaemoSshThread::createConnection() +template void MaemoSshThread::waitForStop() { - typename Conn::Ptr connection = Conn::create(m_devConf); + m_mutex.lock(); + while (!stopRequested()) + m_waitCond.wait(&m_mutex); + m_mutex.unlock(); +} + +template void MaemoSshThread::createConnection() +{ + typename SshConnection::Ptr connection = SshConnection::create(m_server); m_mutex.lock(); m_connection = connection; m_mutex.unlock(); - return connection; } -MaemoSshRunner::MaemoSshRunner(const MaemoDeviceConfig &devConf, +MaemoSshRunner::MaemoSshRunner(const Core::SshServerInfo &server, const QString &command) - : MaemoSshThread(devConf), m_command(command) + : MaemoSshThread(server), + m_command(command) { + m_prompt = server.uname == QLatin1String("root") ? "#" : "$"; } -void MaemoSshRunner::runInternal() +bool MaemoSshRunner::runInternal() { - MaemoInteractiveSshConnection::Ptr connection - = createConnection(); + createConnection(); + connect(m_connection.data(), SIGNAL(remoteOutput(QByteArray)), + this, SLOT(handleRemoteOutput(QByteArray))); + m_endMarkerCount = 0; + m_promptEncountered = false; + if (!m_connection->start()) + return false; if (stopRequested()) + return true; + + waitForStop(); + return !m_connection->hasError(); +} + +void MaemoSshRunner::handleRemoteOutput(const QByteArray &output) +{ + // Wait for a prompt before sending the command. + if (!m_promptEncountered) { + if (output.indexOf(m_prompt) != -1) { + m_promptEncountered = true; + + /* + * We don't have access to the remote process management, so we + * try to track the lifetime of the process by adding a second command + * that prints a rare character. When it occurs for the second time (the + * first one is the echo from the remote terminal), we assume the + * process has finished. If anyone actually prints this special character + * in their application, they are out of luck. + */ + const QString finalCommand = m_command + QLatin1String(";echo ") + + QString::fromUtf8(EndMarker) + QLatin1Char('\n'); + if (!m_connection->sendInput(finalCommand.toUtf8())) + stop(); + } return; - connect(connection.data(), SIGNAL(remoteOutput(QString)), - this, SIGNAL(remoteOutput(QString))); - connection->runCommand(m_command); + } + + /* + * The output the user should see is everything after the first + * and before the last occurrence of our marker string. + * Note: We don't currently handle the case of an incomplete unicode + * character being sent. + */ + int firstCharToEmit; + int charsToEmitCount; + const int endMarkerPos = output.indexOf(EndMarker); + if (endMarkerPos != -1) { + if (m_endMarkerCount++ == 0) { + firstCharToEmit = endMarkerPos + EndMarker.count() + 1; + int endMarkerPos2 + = output.indexOf(EndMarker, firstCharToEmit); + if (endMarkerPos2 != -1) { + ++ m_endMarkerCount; + charsToEmitCount = endMarkerPos2 - firstCharToEmit; + } else { + charsToEmitCount = -1; + } + } else { + firstCharToEmit = 0; + charsToEmitCount = endMarkerPos; + } + } else { + if (m_endMarkerCount == 0) { + charsToEmitCount = 0; + } else { + firstCharToEmit = 0; + charsToEmitCount = -1; + } + } + + if (charsToEmitCount != 0) + emit remoteOutput(QString::fromUtf8(output.data() + firstCharToEmit, + charsToEmitCount)); + if (m_endMarkerCount == 2) + stop(); } -MaemoSshDeployer::MaemoSshDeployer(const MaemoDeviceConfig &devConf, - const QList &deploySpecs) - : MaemoSshThread(devConf), m_deploySpecs(deploySpecs) +const QByteArray MaemoSshRunner::EndMarker(QString(QChar(0x13a0)).toUtf8()); + + +MaemoSshDeployer::MaemoSshDeployer(const Core::SshServerInfo &server, + const QList &deploySpecs) + : MaemoSshThread(server), + m_deploySpecs(deploySpecs) { } -void MaemoSshDeployer::runInternal() +bool MaemoSshDeployer::runInternal() { - MaemoSftpConnection::Ptr connection - = createConnection(); + createConnection(); + if (!m_connection->start()) + return false; if (stopRequested()) - return; - connect(connection.data(), SIGNAL(fileCopied(QString)), + return true; + + connect(m_connection.data(), SIGNAL(fileCopied(QString)), this, SIGNAL(fileCopied(QString))); - connection->transferFiles(m_deploySpecs); + return m_connection->transferFiles(m_deploySpecs); } } // namespace Internal diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosshthread.h b/src/plugins/qt4projectmanager/qt-maemo/maemosshthread.h index 80bd2f90a78..ce7358e91f6 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemosshthread.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemosshthread.h @@ -43,18 +43,20 @@ #define MAEMOSSHTHREAD_H #include "maemodeviceconfigurations.h" -#include "maemosshconnection.h" +#include + +#include #include #include #include +#include namespace Qt4ProjectManager { namespace Internal { -class MaemoSshThread : public QThread +template class MaemoSshThread : public QThread { - Q_OBJECT Q_DISABLE_COPY(MaemoSshThread) public: QString error() const { return m_error; } @@ -64,53 +66,62 @@ public: ~MaemoSshThread(); protected: - MaemoSshThread(const MaemoDeviceConfig &devConf); - template typename Conn::Ptr createConnection(); + MaemoSshThread(const Core::SshServerInfo &server); + void createConnection(); bool stopRequested() const { return m_stopRequested; } + void waitForStop(); + + typename SshConnection::Ptr m_connection; private: - virtual void runInternal() = 0; + virtual bool runInternal() = 0; + const Core::SshServerInfo m_server; bool m_stopRequested; QString m_error; QMutex m_mutex; - const MaemoDeviceConfig m_devConf; - MaemoSshConnection::Ptr m_connection; + QWaitCondition m_waitCond; }; -class MaemoSshRunner : public MaemoSshThread +class MaemoSshRunner : public MaemoSshThread { Q_OBJECT Q_DISABLE_COPY(MaemoSshRunner) public: - MaemoSshRunner(const MaemoDeviceConfig &devConf, const QString &command); + MaemoSshRunner(const Core::SshServerInfo &server, const QString &command); signals: void remoteOutput(const QString &output); private: - virtual void runInternal(); + virtual bool runInternal(); + Q_SLOT void handleRemoteOutput(const QByteArray &output); + + static const QByteArray EndMarker; const QString m_command; + const char *m_prompt; + int m_endMarkerCount; + bool m_promptEncountered; }; -class MaemoSshDeployer : public MaemoSshThread +class MaemoSshDeployer : public MaemoSshThread { Q_OBJECT Q_DISABLE_COPY(MaemoSshDeployer) public: - MaemoSshDeployer(const MaemoDeviceConfig &devConf, - const QList &deploySpecs); + MaemoSshDeployer(const Core::SshServerInfo &server, + const QList &deploySpecs); signals: void fileCopied(const QString &filePath); private: - virtual void runInternal(); + virtual bool runInternal(); - const QList m_deploySpecs; + const QList m_deploySpecs; }; } // namespace Internal diff --git a/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri b/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri index a970764cfc2..95501f184d0 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri +++ b/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri @@ -1,7 +1,3 @@ -INCLUDEPATH += $$PWD/../../../libs/3rdparty/botan/build -INCLUDEPATH += $$PWD/../../../libs/3rdparty/net7ssh/src -LIBS += -l$$qtLibraryTarget(Net7ssh) -l$$qtLibraryTarget(Botan) - HEADERS += \ $$PWD/maemoconfigtestdialog.h \ $$PWD/maemoconstants.h \ @@ -14,12 +10,10 @@ HEADERS += \ $$PWD/maemosettingspage.h \ $$PWD/maemosettingswidget.h \ $$PWD/maemosshconfigdialog.h \ - $$PWD/maemosshconnection.h \ $$PWD/maemosshthread.h \ $$PWD/maemotoolchain.h \ $$PWD/maemopackagecreationstep.h \ $$PWD/maemopackagecreationfactory.h \ - $$PWD/ne7sshobject.h \ $$PWD/maemopackagecreationwidget.h \ $$PWD/maemopackagecontents.h @@ -34,12 +28,10 @@ SOURCES += \ $$PWD/maemosettingspage.cpp \ $$PWD/maemosettingswidget.cpp \ $$PWD/maemosshconfigdialog.cpp \ - $$PWD/maemosshconnection.cpp \ $$PWD/maemosshthread.cpp \ $$PWD/maemotoolchain.cpp \ $$PWD/maemopackagecreationstep.cpp \ $$PWD/maemopackagecreationfactory.cpp \ - $$PWD/ne7sshobject.cpp \ $$PWD/maemopackagecreationwidget.cpp \ $$PWD/maemopackagecontents.cpp