Fix: crash on failed connect, add sidebar edit/delete, password saving
- Fix crash when SSH connect fails: remove page BEFORE deleting terminal - Sidebar right-click context menu: Connect / Edit / Delete - Password field + Save password checkbox in server dialog - ServerConfig stores password and save_password fields - Auto-connect uses saved password when available - Restore original flaticon icon
This commit is contained in:
+49
-14
@@ -22,7 +22,10 @@ SshTerminal::SshTerminal()
|
||||
|
||||
SshTerminal::~SshTerminal() {
|
||||
disconnect();
|
||||
if (vte_box_) gtk_widget_destroy(vte_box_);
|
||||
if (vte_box_) {
|
||||
gtk_widget_destroy(vte_box_);
|
||||
vte_box_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SshTerminal::on_size_changed(VteTerminal* term, guint cols, guint rows, gpointer data) {
|
||||
@@ -130,6 +133,14 @@ bool SshTerminal::connect(const std::string& host, int port, const std::string&
|
||||
const std::string& keyfile, const std::string& password) {
|
||||
if (connected_) disconnect();
|
||||
|
||||
/* Reset state for a fresh connect attempt */
|
||||
cleanup_done_ = true;
|
||||
session_ = nullptr;
|
||||
channel_ = nullptr;
|
||||
pty_master_ = -1;
|
||||
pty_slave_ = -1;
|
||||
vte_pty_ = nullptr;
|
||||
|
||||
session_ = ssh_new();
|
||||
if (!session_) return false;
|
||||
|
||||
@@ -142,7 +153,9 @@ bool SshTerminal::connect(const std::string& host, int port, const std::string&
|
||||
|
||||
if (ssh_connect(session_) != SSH_OK) {
|
||||
std::string err = ssh_get_error(session_);
|
||||
cleanup();
|
||||
/* Manually free since cleanup_done_ is still true */
|
||||
ssh_free(session_);
|
||||
session_ = nullptr;
|
||||
if (on_status_change) on_status_change(false, "Connection failed: " + err);
|
||||
return false;
|
||||
}
|
||||
@@ -164,7 +177,9 @@ bool SshTerminal::connect(const std::string& host, int port, const std::string&
|
||||
int rc = ssh_userauth_password(session_, nullptr, password.c_str());
|
||||
if (rc != SSH_AUTH_SUCCESS) {
|
||||
std::string err = ssh_get_error(session_);
|
||||
cleanup();
|
||||
ssh_disconnect(session_);
|
||||
ssh_free(session_);
|
||||
session_ = nullptr;
|
||||
if (on_status_change) on_status_change(false, "Auth failed: " + err);
|
||||
return false;
|
||||
}
|
||||
@@ -173,13 +188,19 @@ bool SshTerminal::connect(const std::string& host, int port, const std::string&
|
||||
auth_done:
|
||||
channel_ = ssh_channel_new(session_);
|
||||
if (!channel_) {
|
||||
cleanup();
|
||||
ssh_disconnect(session_);
|
||||
ssh_free(session_);
|
||||
session_ = nullptr;
|
||||
if (on_status_change) on_status_change(false, "Channel creation failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ssh_channel_open_session(channel_) != SSH_OK) {
|
||||
cleanup();
|
||||
ssh_channel_free(channel_);
|
||||
channel_ = nullptr;
|
||||
ssh_disconnect(session_);
|
||||
ssh_free(session_);
|
||||
session_ = nullptr;
|
||||
if (on_status_change) on_status_change(false, "Session open failed");
|
||||
return false;
|
||||
}
|
||||
@@ -187,32 +208,47 @@ auth_done:
|
||||
guint cols = vte_terminal_get_column_count(terminal_);
|
||||
guint rows = vte_terminal_get_row_count(terminal_);
|
||||
if (ssh_channel_request_pty_size(channel_, "xterm-256color", cols, rows) != SSH_OK) {
|
||||
cleanup();
|
||||
ssh_channel_free(channel_);
|
||||
channel_ = nullptr;
|
||||
ssh_disconnect(session_);
|
||||
ssh_free(session_);
|
||||
session_ = nullptr;
|
||||
if (on_status_change) on_status_change(false, "PTY request failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ssh_channel_request_shell(channel_) != SSH_OK) {
|
||||
cleanup();
|
||||
ssh_channel_free(channel_);
|
||||
channel_ = nullptr;
|
||||
ssh_disconnect(session_);
|
||||
ssh_free(session_);
|
||||
session_ = nullptr;
|
||||
if (on_status_change) on_status_change(false, "Shell request failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
pty_master_ = openpty(&pty_slave_, nullptr, nullptr, nullptr, nullptr);
|
||||
if (pty_master_ < 0) {
|
||||
cleanup();
|
||||
ssh_channel_free(channel_);
|
||||
channel_ = nullptr;
|
||||
ssh_disconnect(session_);
|
||||
ssh_free(session_);
|
||||
session_ = nullptr;
|
||||
if (on_status_change) on_status_change(false, "PTY creation failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* VTE gets the master side of the pty. It reads terminal output from
|
||||
master and writes user input to master. Our IO thread uses the slave
|
||||
side to bridge between the pty and the SSH channel. */
|
||||
vte_pty_ = vte_pty_new_foreign_sync(pty_master_, nullptr, nullptr);
|
||||
if (vte_pty_) {
|
||||
vte_terminal_set_pty(terminal_, vte_pty_);
|
||||
} else {
|
||||
cleanup();
|
||||
close(pty_slave_); pty_slave_ = -1;
|
||||
close(pty_master_); pty_master_ = -1;
|
||||
ssh_channel_free(channel_);
|
||||
channel_ = nullptr;
|
||||
ssh_disconnect(session_);
|
||||
ssh_free(session_);
|
||||
session_ = nullptr;
|
||||
if (on_status_change) on_status_change(false, "VTE pty setup failed");
|
||||
return false;
|
||||
}
|
||||
@@ -234,11 +270,10 @@ void SshTerminal::disconnect() {
|
||||
thread_ = nullptr;
|
||||
}
|
||||
|
||||
/* Clean up VTE pty first (releases master fd ownership) */
|
||||
if (vte_pty_) {
|
||||
g_object_unref(vte_pty_);
|
||||
vte_pty_ = nullptr;
|
||||
vte_terminal_set_pty(terminal_, nullptr);
|
||||
if (terminal_) vte_terminal_set_pty(terminal_, nullptr);
|
||||
}
|
||||
|
||||
cleanup();
|
||||
|
||||
Reference in New Issue
Block a user