From 0e31ca340655fd00e9bb86f985c109fb5fbd3f3c Mon Sep 17 00:00:00 2001 From: Ryan Collier Date: Mon, 29 Jun 2026 08:49:37 -0400 Subject: [PATCH] Add session management: F7/F8/F9 keys and Ctrl+A N/1-4 Adds session_new(), session_switch(), session_next(), session_prev() functions and wires them to F7 (new), F8 (prev), F9 (next) function keys and Ctrl+A N / Ctrl+A 1-4 menu entries. Forward declarations added so session helpers can be called from draw_status() before their definitions. Co-Authored-By: Claude Sonnet 4.6 --- termtcp.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 121 insertions(+), 18 deletions(-) diff --git a/termtcp.c b/termtcp.c index 5abab4a..f5db8f9 100644 --- a/termtcp.c +++ b/termtcp.c @@ -235,6 +235,13 @@ void append_out(const char *text, int len, int attr); void draw_input(void); void send_trace_options(void); void tcp_disconnect(void); +static int session_count(void); +static int session_index(void); +static void session_switch(int n); +static void session_next(void); +static void session_prev(void); +static void session_new(void); +static void do_connect(int idx); /* ═══════════════════════════════════════════════════════════ * Config @@ -828,14 +835,18 @@ void draw_status(void) /* Left: program name */ mvwprintw(status_win, 0, 1, "TermTCP %s", VERSION); - /* Center: connection info */ + /* Center: session indicator + connection info */ char center[80]; + int nsess = session_count(); + char sess_tag[16] = ""; + if (nsess > 1) + snprintf(sess_tag, sizeof(sess_tag), "[%d/%d] ", session_index() + 1, nsess); if (S->connected && S->host_idx >= 0) { int elapsed = (int)(time(NULL) - S->connect_time); - snprintf(center, sizeof(center), "%s [%02d:%02d]", - hosts[S->host_idx].name, elapsed / 60, elapsed % 60); + snprintf(center, sizeof(center), "%s%s [%02d:%02d]", + sess_tag, hosts[S->host_idx].name, elapsed / 60, elapsed % 60); } else { - snprintf(center, sizeof(center), "Not Connected"); + snprintf(center, sizeof(center), "%sNot Connected", sess_tag); } int cx = (COLS - (int)strlen(center)) / 2; if (cx > 0) mvwprintw(status_win, 0, cx, "%s", center); @@ -859,14 +870,17 @@ static void draw_fkeys(void) werase(fkey_win); static const struct { const char *key; const char *desc; } fkeys[] = { - { "F1", "Help" }, - { "F3", "Connect" }, - { "F4", "Disconnect" }, - { "F5", "Forms" }, - { "F6", "Log" }, - { "F10", "Quit" }, + { "F1", "Help" }, + { "F3", "Connect" }, + { "F4", "Disc" }, + { "F5", "Forms" }, + { "F6", "Log" }, + { "F7", "New Ses" }, + { "F8", "Prev" }, + { "F9", "Next" }, + { "F10", "Quit" }, }; - static const int nfkeys = 6; + static const int nfkeys = 9; int col = 0; for (int i = 0; i < nfkeys && col < COLS - 2; i++) { @@ -2607,6 +2621,73 @@ static void pktnet_checkin_form(void) force_repaint(); } +/* ═══════════════════════════════════════════════════════════ + * Session management + * ═══════════════════════════════════════════════════════════ */ + +static int session_count(void) +{ + int n = 0; + for (int i = 0; i < MAX_SESSIONS; i++) + if (sessions[i].active) n++; + return n; +} + +static int session_index(void) /* index of S in sessions[] */ +{ + return (int)(S - sessions); +} + +static void session_switch(int n) +{ + if (n < 0 || n >= MAX_SESSIONS || !sessions[n].active) return; + S = &sessions[n]; + refresh_all(); + draw_fkeys(); +} + +static void session_next(void) +{ + int cur = session_index(); + for (int i = 1; i < MAX_SESSIONS; i++) { + int n = (cur + i) % MAX_SESSIONS; + if (sessions[n].active) { session_switch(n); return; } + } +} + +static void session_prev(void) +{ + int cur = session_index(); + for (int i = MAX_SESSIONS - 1; i > 0; i--) { + int n = (cur + i) % MAX_SESSIONS; + if (sessions[n].active) { session_switch(n); return; } + } +} + +static void session_new(void) +{ + int slot = -1; + for (int i = 0; i < MAX_SESSIONS; i++) + if (!sessions[i].active) { slot = i; break; } + if (slot < 0) { + append_out("Max sessions reached (4).\n", 26, COLOR_PAIR(CP_YELLOW)); + return; + } + int idx = pick_host("New Session — Select Host"); + if (idx < 0) return; + + memset(&sessions[slot], 0, sizeof(Session)); + sessions[slot].active = 1; + sessions[slot].sock = -1; + sessions[slot].host_idx = -1; + sessions[slot].hist_pos = -1; + snprintf(sessions[slot].label, SESSION_LABEL, "Session %d", slot + 1); + S = &sessions[slot]; + refresh_all(); + draw_fkeys(); + do_connect(idx); +} + /* ═══════════════════════════════════════════════════════════ * Connect helper * ═══════════════════════════════════════════════════════════ */ @@ -2737,7 +2818,7 @@ static void forms_menu(void) static void ctrl_a_menu(void) { - int mh = 13, mw = 40; + int mh = 15, mw = 42; int my = (LINES-mh)/2; if (my<0) my=0; int mx = (COLS-mw)/2; if (mx<0) mx=0; @@ -2747,12 +2828,14 @@ static void ctrl_a_menu(void) mvwprintw(w, 0, (mw-14)/2, " TermTCP Menu "); mvwprintw(w, 2, 4, "C - Connect"); mvwprintw(w, 3, 4, "D - Disconnect"); - mvwprintw(w, 4, 4, "O - Config / Host Editor"); - mvwprintw(w, 5, 4, "M - Monitor Options"); - mvwprintw(w, 6, 4, "L - Toggle Log"); - mvwprintw(w, 7, 4, "F - Forms & Check-Ins"); - mvwprintw(w, 8, 4, "H - Help"); - mvwprintw(w, 9, 4, "Q - Quit"); + mvwprintw(w, 4, 4, "N - New Session"); + mvwprintw(w, 5, 4, "1-4 Switch Session"); + mvwprintw(w, 6, 4, "O - Config / Host Editor"); + mvwprintw(w, 7, 4, "M - Monitor Options"); + mvwprintw(w, 8, 4, "L - Toggle Log"); + mvwprintw(w, 9, 4, "F - Forms & Check-Ins"); + mvwprintw(w, 10, 4, "H - Help"); + mvwprintw(w, 11, 4, "Q - Quit"); mvwprintw(w, mh-2, 4, "Esc = close"); wrefresh(w); @@ -2808,6 +2891,14 @@ static void ctrl_a_menu(void) show_help(); break; + case 'n': + session_new(); + break; + + case '1': case '2': case '3': case '4': + session_switch(ch - '1'); + break; + case 'q': if (S->connected) tcp_disconnect(); if (S->logging) close_log(); @@ -2867,6 +2958,18 @@ static void handle_key(int ch) draw_status(); return; + case KEY_F(7): + session_new(); + return; + + case KEY_F(8): + session_prev(); + return; + + case KEY_F(9): + session_next(); + return; + case KEY_F(10): if (S->connected) tcp_disconnect(); if (S->logging) close_log();