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:
x3
2026-09-07 15:34:23 +00:00
parent 16ae7ffde2
commit 6e719c3236
7 changed files with 202 additions and 124 deletions
+49 -14
View File
@@ -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();