Fix scrollback wrap bug, add /clear, add TCP keepalive
- Fix off-by-one in redraw_window circular buffer indexing (<= to <) that caused stale content after 500 lines filled - Add /clear command to reset current window scrollback - Add TCP keepalive and application-level ping timeout to detect dead connections
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#include <termios.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#include "charset.h"
|
||||
|
||||
@@ -56,6 +57,8 @@ static size_t recv_len = 0;
|
||||
static char nick[64] = "kiro_user";
|
||||
static int term_rows = 24, term_cols = 80;
|
||||
static struct termios orig_term;
|
||||
static time_t last_recv = 0; /* time of last data from server */
|
||||
static int ping_sent = 0; /* we sent a client PING, awaiting reply */
|
||||
|
||||
/* Per-window scrollback buffer */
|
||||
static struct {
|
||||
@@ -81,6 +84,7 @@ static int translate_public = 0; /* /trans toggle: echo translations to channel
|
||||
static int translate_enabled = 1; /* master toggle for translation */
|
||||
static int irc_colors = 1; /* display IRC colour codes as ANSI */
|
||||
static char rent_msg[256] = "This space available for rent";
|
||||
static int log_enabled = 0;
|
||||
|
||||
/* Track nicks who sent us private messages */
|
||||
#define MAX_PM_NICKS 32
|
||||
@@ -191,6 +195,8 @@ static void ai_config_load(void)
|
||||
irc_colors = atoi(eq);
|
||||
else if (strcmp(line, "rent") == 0)
|
||||
snprintf(rent_msg, sizeof(rent_msg), "%s", eq);
|
||||
else if (strcmp(line, "log") == 0)
|
||||
log_enabled = (strcmp(eq, "true") == 0 || atoi(eq));
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
@@ -686,7 +692,7 @@ static void redraw_window(void)
|
||||
while (start_pos > 0 && rows_used < visible) {
|
||||
int li = start_pos - 1;
|
||||
int buf_idx;
|
||||
if (count <= SCROLLBACK)
|
||||
if (count < SCROLLBACK)
|
||||
buf_idx = li;
|
||||
else
|
||||
buf_idx = (win_buf[current_level].head - count + li + SCROLLBACK) % SCROLLBACK;
|
||||
@@ -706,7 +712,7 @@ static void redraw_window(void)
|
||||
for (int i = 0; i < show; i++) {
|
||||
int li = start_pos + i;
|
||||
int buf_idx;
|
||||
if (count <= SCROLLBACK)
|
||||
if (count < SCROLLBACK)
|
||||
buf_idx = li;
|
||||
else
|
||||
buf_idx = (win_buf[current_level].head - count + li + SCROLLBACK) % SCROLLBACK;
|
||||
@@ -821,6 +827,16 @@ static int irc_connect(const char *host, const char *port)
|
||||
if (fd < 0)
|
||||
die("connect");
|
||||
|
||||
/* Enable TCP keepalive to detect dead connections */
|
||||
int one = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one));
|
||||
int idle = 60;
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle));
|
||||
int intvl = 15;
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl));
|
||||
int cnt = 4;
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt));
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -964,48 +980,12 @@ static FILE *logfp = NULL;
|
||||
|
||||
static void log_raw(const char *line, size_t len)
|
||||
{
|
||||
(void)len;
|
||||
if (!logfp) return;
|
||||
time_t now = time(NULL);
|
||||
struct tm *tm = localtime(&now);
|
||||
fprintf(logfp, "[%02d:%02d:%02d] len=%zu charset=",
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec, len);
|
||||
|
||||
/* Detect charset */
|
||||
const unsigned char *u = (const unsigned char *)line;
|
||||
int has_high = 0, valid_utf8 = 1;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (u[i] >= 0x80) {
|
||||
has_high = 1;
|
||||
if ((u[i] & 0xE0) == 0xC0) {
|
||||
if (i+1 >= len || (u[i+1] & 0xC0) != 0x80)
|
||||
valid_utf8 = 0;
|
||||
else i += 1;
|
||||
} else if ((u[i] & 0xF0) == 0xE0) {
|
||||
if (i+2 >= len || (u[i+1] & 0xC0) != 0x80 ||
|
||||
(u[i+2] & 0xC0) != 0x80)
|
||||
valid_utf8 = 0;
|
||||
else i += 2;
|
||||
} else if ((u[i] & 0xF8) == 0xF0) {
|
||||
if (i+3 >= len || (u[i+1] & 0xC0) != 0x80 ||
|
||||
(u[i+2] & 0xC0) != 0x80 || (u[i+3] & 0xC0) != 0x80)
|
||||
valid_utf8 = 0;
|
||||
else i += 3;
|
||||
} else {
|
||||
valid_utf8 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!has_high)
|
||||
fprintf(logfp, "ASCII");
|
||||
else if (valid_utf8)
|
||||
fprintf(logfp, "UTF-8");
|
||||
else
|
||||
fprintf(logfp, "ISO-8859-1");
|
||||
|
||||
fprintf(logfp, "\n text: %s\n hex: ", line);
|
||||
for (size_t i = 0; i < len; i++)
|
||||
fprintf(logfp, "%02X ", u[i]);
|
||||
fprintf(logfp, "\n");
|
||||
fprintf(logfp, "[%02d:%02d:%02d] %s\n",
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec, line);
|
||||
fflush(logfp);
|
||||
}
|
||||
|
||||
@@ -1557,6 +1537,11 @@ static void handle_input(char *line)
|
||||
exit(0);
|
||||
} else if (strcasecmp(cmd, "raw") == 0 && args) {
|
||||
irc_send_raw("%s", args);
|
||||
} else if (strcasecmp(cmd, "clear") == 0) {
|
||||
win_buf[current_level].count = 0;
|
||||
win_buf[current_level].head = 0;
|
||||
scroll_offset = 0;
|
||||
redraw_window();
|
||||
} else {
|
||||
wprintf(current_level, "Unknown command: /%s\n", cmd);
|
||||
}
|
||||
@@ -1723,7 +1708,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
ai_config_load();
|
||||
|
||||
logfp = fopen("irc.log", "a");
|
||||
logfp = log_enabled ? fopen("irc.log", "a") : NULL;
|
||||
if (logfp)
|
||||
fprintf(logfp, "--- Session started ---\n");
|
||||
|
||||
@@ -1751,6 +1736,7 @@ int main(int argc, char *argv[])
|
||||
wprintf(WL_STATUS, "Connecting to %s:%s as %s...\n", host, port, nick);
|
||||
|
||||
sock_fd = irc_connect(host, port);
|
||||
last_recv = time(NULL);
|
||||
|
||||
wprintf(WL_STATUS, "Connected.\n");
|
||||
|
||||
@@ -1826,6 +1812,20 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
/* Detect dead connection: no data for 240s → send PING,
|
||||
no reply after 60 more seconds → disconnect */
|
||||
if (last_recv > 0) {
|
||||
time_t elapsed = time(NULL) - last_recv;
|
||||
if (!ping_sent && elapsed >= 240) {
|
||||
irc_send_raw("PING :keepalive");
|
||||
ping_sent = 1;
|
||||
} else if (ping_sent && elapsed >= 300) {
|
||||
wprintf(WL_STATUS,
|
||||
"* No response from server (timeout)\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check translation results */
|
||||
for (int ti = 0; ti < translate_count; ) {
|
||||
if (FD_ISSET(translate_pending[ti].fd, &fds)) {
|
||||
@@ -1989,6 +1989,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
recv_len += (size_t)n;
|
||||
recv_buf[recv_len] = '\0';
|
||||
last_recv = time(NULL);
|
||||
ping_sent = 0;
|
||||
process_recv();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user