mirror of
https://oauth2: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@github.com/m1ngsama/TNT.git
synced 2026-05-10 19:00:57 +08:00
fix: guard terminal width/height in all TUI renderers and harden edge cases
- Replace all direct client->width/height reads with local variables clamped to minimums (width>=10, height>=4) across tui_render_screen, tui_render_input, tui_render_command_output, and tui_render_help - Fix tui_render_input underflow when width < 3 (avail = max(rw-3, 1)) - Show username in title bar instead of generic label - Add /me action message support in exec_command_post for scripting parity - Reject empty usernames when loading messages from log file
This commit is contained in:
parent
848ad2e2a6
commit
14789cd1c8
3 changed files with 52 additions and 24 deletions
|
|
@ -134,10 +134,13 @@ read_messages:;
|
|||
char *username = strtok(NULL, "|");
|
||||
char *content = strtok(NULL, "\n");
|
||||
|
||||
/* Validate all fields exist */
|
||||
/* Validate all fields exist and are non-empty */
|
||||
if (!timestamp_str || !username || !content) {
|
||||
continue;
|
||||
}
|
||||
if (username[0] == '\0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Validate field lengths */
|
||||
if (strlen(username) >= MAX_USERNAME_LEN) {
|
||||
|
|
|
|||
|
|
@ -1006,10 +1006,16 @@ static int exec_command_post(client_t *client, const char *args) {
|
|||
|
||||
resolve_exec_username(client, username, sizeof(username));
|
||||
|
||||
if (strncmp(content, "/me ", 4) == 0 && content[4] != '\0') {
|
||||
msg.username[0] = '*';
|
||||
msg.username[1] = '\0';
|
||||
snprintf(msg.content, sizeof(msg.content), "%s %s", username, content + 4);
|
||||
} else {
|
||||
strncpy(msg.username, username, sizeof(msg.username) - 1);
|
||||
msg.username[sizeof(msg.username) - 1] = '\0';
|
||||
strncpy(msg.content, content, sizeof(msg.content) - 1);
|
||||
msg.content[sizeof(msg.content) - 1] = '\0';
|
||||
}
|
||||
|
||||
room_broadcast(g_room, &msg);
|
||||
if (message_save(&msg) < 0) {
|
||||
|
|
|
|||
57
src/tui.c
57
src/tui.c
|
|
@ -56,9 +56,12 @@ void tui_clear_screen(client_t *client) {
|
|||
void tui_render_screen(client_t *client) {
|
||||
if (!client || !client->connected) return;
|
||||
|
||||
/* Heap-allocated: worst case is ~200 messages * ~1100 bytes + separator + status.
|
||||
* 64 KiB covers all real terminal sizes without stack risk. */
|
||||
const size_t buf_size = 65536;
|
||||
int render_width = client->width;
|
||||
int render_height = client->height;
|
||||
if (render_width < 10) render_width = 10;
|
||||
if (render_height < 4) render_height = 4;
|
||||
|
||||
const size_t buf_size = (size_t)(render_height + 10) * (MAX_MESSAGE_LEN + 64) + 2048;
|
||||
char *buffer = malloc(buf_size);
|
||||
if (!buffer) return;
|
||||
size_t pos = 0;
|
||||
|
|
@ -71,7 +74,7 @@ void tui_render_screen(client_t *client) {
|
|||
pthread_rwlock_unlock(&g_room->lock);
|
||||
|
||||
/* Calculate which messages to show */
|
||||
int msg_height = client->height - 3;
|
||||
int msg_height = render_height - 3;
|
||||
if (msg_height < 1) msg_height = 1;
|
||||
|
||||
int start = 0;
|
||||
|
|
@ -129,11 +132,11 @@ void tui_render_screen(client_t *client) {
|
|||
|
||||
char title[256];
|
||||
snprintf(title, sizeof(title),
|
||||
" 聊天室 | 在线: %d | 模式: %s | Ctrl+C 退出 | ? 帮助 ",
|
||||
online, mode_str);
|
||||
" %s | 在线: %d | 模式: %s | ? 帮助 ",
|
||||
client->username, online, mode_str);
|
||||
|
||||
int title_width = utf8_string_width(title);
|
||||
int padding = client->width - title_width;
|
||||
int padding = render_width - title_width;
|
||||
if (padding < 0) padding = 0;
|
||||
|
||||
buffer_appendf(buffer, buf_size, &pos, ANSI_REVERSE "%s", title);
|
||||
|
|
@ -146,7 +149,7 @@ void tui_render_screen(client_t *client) {
|
|||
if (msg_snapshot) {
|
||||
for (int i = 0; i < snapshot_count; i++) {
|
||||
char msg_line[1024];
|
||||
message_format(&msg_snapshot[i], msg_line, sizeof(msg_line), client->width);
|
||||
message_format(&msg_snapshot[i], msg_line, sizeof(msg_line), render_width);
|
||||
buffer_appendf(buffer, buf_size, &pos, "%s\033[K\r\n", msg_line);
|
||||
}
|
||||
free(msg_snapshot);
|
||||
|
|
@ -158,7 +161,7 @@ void tui_render_screen(client_t *client) {
|
|||
}
|
||||
|
||||
/* Separator - use box drawing character */
|
||||
for (int i = 0; i < client->width; i++) {
|
||||
for (int i = 0; i < render_width; i++) {
|
||||
buffer_append_bytes(buffer, buf_size, &pos, "─", strlen("─"));
|
||||
}
|
||||
buffer_appendf(buffer, buf_size, &pos, "\033[K\r\n");
|
||||
|
|
@ -184,17 +187,23 @@ void tui_render_screen(client_t *client) {
|
|||
void tui_render_input(client_t *client, const char *input) {
|
||||
if (!client || !client->connected) return;
|
||||
|
||||
int rw = client->width;
|
||||
int rh = client->height;
|
||||
if (rw < 10) rw = 10;
|
||||
if (rh < 4) rh = 4;
|
||||
|
||||
char buffer[2048];
|
||||
int input_width = utf8_string_width(input);
|
||||
int avail = rw - 3;
|
||||
if (avail < 1) avail = 1;
|
||||
|
||||
/* Truncate from start if too long */
|
||||
char display[MAX_MESSAGE_LEN];
|
||||
strncpy(display, input, sizeof(display) - 1);
|
||||
display[sizeof(display) - 1] = '\0';
|
||||
|
||||
if (input_width > client->width - 3) {
|
||||
/* Find where to start displaying */
|
||||
int excess = input_width - (client->width - 3);
|
||||
if (input_width > avail) {
|
||||
int excess = input_width - avail;
|
||||
int skip_width = 0;
|
||||
const char *p = input;
|
||||
int bytes_read;
|
||||
|
|
@ -210,7 +219,7 @@ void tui_render_input(client_t *client, const char *input) {
|
|||
|
||||
/* Move to input line and clear it, then write input */
|
||||
snprintf(buffer, sizeof(buffer), "\033[%d;1H" ANSI_CLEAR_LINE "> %s",
|
||||
client->height, display);
|
||||
rh, display);
|
||||
|
||||
client_send(client, buffer, strlen(buffer));
|
||||
}
|
||||
|
|
@ -219,6 +228,11 @@ void tui_render_input(client_t *client, const char *input) {
|
|||
void tui_render_command_output(client_t *client) {
|
||||
if (!client || !client->connected) return;
|
||||
|
||||
int rw = client->width;
|
||||
int rh = client->height;
|
||||
if (rw < 10) rw = 10;
|
||||
if (rh < 4) rh = 4;
|
||||
|
||||
char buffer[4096];
|
||||
size_t pos = 0;
|
||||
buffer[0] = '\0';
|
||||
|
|
@ -229,7 +243,7 @@ void tui_render_command_output(client_t *client) {
|
|||
/* Title */
|
||||
const char *title = " COMMAND OUTPUT ";
|
||||
int title_width = strlen(title);
|
||||
int padding = client->width - title_width;
|
||||
int padding = rw - title_width;
|
||||
if (padding < 0) padding = 0;
|
||||
|
||||
buffer_appendf(buffer, sizeof(buffer), &pos, ANSI_REVERSE "%s", title);
|
||||
|
|
@ -245,15 +259,15 @@ void tui_render_command_output(client_t *client) {
|
|||
|
||||
char *line = strtok(output_copy, "\n");
|
||||
int line_count = 0;
|
||||
int max_lines = client->height - 2;
|
||||
int max_lines = rh - 2;
|
||||
|
||||
while (line && line_count < max_lines) {
|
||||
char truncated[1024];
|
||||
strncpy(truncated, line, sizeof(truncated) - 1);
|
||||
truncated[sizeof(truncated) - 1] = '\0';
|
||||
|
||||
if (utf8_string_width(truncated) > client->width) {
|
||||
utf8_truncate(truncated, client->width);
|
||||
if (utf8_string_width(truncated) > rw) {
|
||||
utf8_truncate(truncated, rw);
|
||||
}
|
||||
|
||||
buffer_appendf(buffer, sizeof(buffer), &pos, "%s\r\n", truncated);
|
||||
|
|
@ -369,6 +383,11 @@ const char* tui_get_help_text(help_lang_t lang) {
|
|||
void tui_render_help(client_t *client) {
|
||||
if (!client || !client->connected) return;
|
||||
|
||||
int rw = client->width;
|
||||
int rh = client->height;
|
||||
if (rw < 10) rw = 10;
|
||||
if (rh < 4) rh = 4;
|
||||
|
||||
char buffer[8192];
|
||||
size_t pos = 0;
|
||||
buffer[0] = '\0';
|
||||
|
|
@ -379,7 +398,7 @@ void tui_render_help(client_t *client) {
|
|||
/* Title */
|
||||
const char *title = " HELP ";
|
||||
int title_width = strlen(title);
|
||||
int padding = client->width - title_width;
|
||||
int padding = rw - title_width;
|
||||
if (padding < 0) padding = 0;
|
||||
|
||||
buffer_appendf(buffer, sizeof(buffer), &pos, ANSI_REVERSE "%s", title);
|
||||
|
|
@ -403,7 +422,7 @@ void tui_render_help(client_t *client) {
|
|||
line = strtok(NULL, "\n");
|
||||
}
|
||||
|
||||
int content_height = client->height - 2;
|
||||
int content_height = rh - 2;
|
||||
if (content_height < 1) content_height = 1;
|
||||
int max_scroll = line_count - content_height + 1;
|
||||
if (max_scroll < 0) max_scroll = 0;
|
||||
|
|
|
|||
Loading…
Reference in a new issue