#ifndef ORBITHUB_SSH_SESSION_BACKEND_H #define ORBITHUB_SSH_SESSION_BACKEND_H #include "session_backend.h" #include #include #include class SshSessionBackend : public SessionBackend { Q_OBJECT public: explicit SshSessionBackend(const Profile& profile, QObject* parent = nullptr); // Test-only: overrides the executable launched instead of "ssh", so // tests can point it at a controllable fixture script. SshSessionBackend(const Profile& profile, const QString& sshProgramOverride, QObject* parent); ~SshSessionBackend() override; // Pure, state-free helpers exposed as public statics purely so tests // can exercise them directly without spinning up a real ssh process. static QString mapSshError(const QString& rawError); static QString escapeForShellSingleQuotes(const QString& value); public slots: void connectSession(const SessionConnectOptions& options) override; void disconnectSession() override; void reconnectSession(const SessionConnectOptions& options) override; void sendInput(const QString& input) override; void confirmHostKey(bool trustHost) override; void updateTerminalSize(int columns, int rows) override; private slots: void onProcessStarted(); void onProcessErrorOccurred(QProcess::ProcessError error); void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); void onReadyReadStandardOutput(); void onReadyReadStandardError(); void onConnectedProbeTimeout(); private: QProcess* m_process; QTimer* m_connectedProbeTimer; SessionState m_state; bool m_userInitiatedDisconnect; bool m_reconnectPending; SessionConnectOptions m_reconnectOptions; SessionConnectOptions m_activeOptions; QString m_lastRawError; QString m_askPassScriptPath; bool m_waitingForPasswordPrompt; bool m_waitingForHostKeyConfirmation; bool m_passwordSubmitted; int m_terminalColumns; int m_terminalRows; QString m_sshProgram; void setState(SessionState state, const QString& message); bool startSshProcess(const SessionConnectOptions& options); bool configureAskPass(const SessionConnectOptions& options, QProcessEnvironment& environment, QString& error); void cleanupAskPassScript(); QString knownHostsFileForNullDevice() const; void applyTerminalSizeIfAvailable(); }; #endif