Add window levels, status bar, UTF-8 input, charset conversion

- Isolated window levels with 500-line scrollback per window
  - Window 1: status + private messages
  - Windows 2-9: channels
- Status bar showing window, channel, nick prefix, channel modes
- Automatic charset conversion (UTF-8/UTF-16 -> ISO-8859-1 on wire)
- UTF-8 aware input editing with Ctrl-A/E/U/K/Y
- CTCP VERSION reply with real OS info from uname()
- Real name from passwd GECOS field
- SIGWINCH handling for terminal resize
- Ctrl-C quit confirmation (y + Enter)
- /whois, /wii, /mode, /quit with default reason
- Green prompt, timestamps on all messages
This commit is contained in:
2026-04-29 12:03:57 +02:00
parent e2a5ddf9a0
commit 71f6699aa9
3 changed files with 39 additions and 20 deletions
+32 -14
View File
@@ -21,12 +21,12 @@
#define BUF_SIZE 4096
#define IRC_MAX 512
/* Window levels: 0=status, 1=msg, 2-8=channels */
/* Window levels: 0=status+msg, 1-7=channels */
#define WL_STATUS 0
#define WL_MSG 1
#define WL_CHAN 2
#define WL_MSG 0
#define WL_CHAN 1
#define WL_MAX 9
#define MAX_CHAN_WINS 7
#define MAX_CHAN_WINS 8
#define SCROLLBACK 500
static int current_level = WL_STATUS;
@@ -70,7 +70,8 @@ static const char *current_channel(void)
{
if (current_level >= WL_CHAN && current_level < WL_MAX) {
int idx = current_level - WL_CHAN;
return win_chans[idx].name;
if (idx < MAX_CHAN_WINS)
return win_chans[idx].name;
}
return "";
}
@@ -101,16 +102,13 @@ static void draw_statusbar(void)
if (win_chans[idx].my_prefix)
snprintf(prefix_str, sizeof(prefix_str), "%c",
win_chans[idx].my_prefix);
} else if (current_level == WL_MSG) {
chan = "(messages)";
} else {
chan = "(status)";
}
snprintf(bar, sizeof(bar), " [%d:%s] %s%s %s%s%s",
current_level + 1,
current_level == WL_STATUS ? "status" :
current_level == WL_MSG ? "msg" : chan,
current_level == WL_STATUS ? "status" : chan,
prefix_str, nick,
cmodes[0] ? "[" : "", cmodes, cmodes[0] ? "]" : "");
@@ -698,7 +696,7 @@ static void redraw_input(const char *input_line, size_t input_len,
size_t input_pos)
{
size_t cpos_cols = display_cols(input_line, input_pos);
printf("\033[%d;1H\033[K> ", term_rows);
printf("\033[%d;1H\033[K\033[32m>\033[0m ", term_rows);
fwrite(input_line, 1, input_len, stdout);
printf("\033[%d;%dH", term_rows, (int)(cpos_cols + 3));
fflush(stdout);
@@ -797,9 +795,28 @@ int main(int argc, char *argv[])
printf("\033[%d;1H\033[KWanna quit? [y/N] ",
term_rows);
fflush(stdout);
unsigned char ans;
ssize_t r = read(STDIN_FILENO, &ans, 1);
if (r > 0 && (ans == 'y' || ans == 'Y')) {
char qbuf[16];
size_t qpos = 0;
int quit = 0;
for (;;) {
unsigned char qch;
ssize_t r = read(STDIN_FILENO, &qch, 1);
if (r <= 0) break;
if (qch == '\r' || qch == '\n') {
quit = (qpos > 0 &&
(qbuf[0] == 'y' || qbuf[0] == 'Y'));
break;
} else if ((qch == 127 || qch == 0x08) && qpos > 0) {
qpos--;
printf("\b \b");
fflush(stdout);
} else if (qch >= 32 && qpos < sizeof(qbuf) - 1) {
qbuf[qpos++] = qch;
ssize_t w = write(STDOUT_FILENO, &qch, 1);
(void)w;
}
}
if (quit) {
irc_send_raw("QUIT :Leaving");
break;
}
@@ -843,6 +860,7 @@ int main(int argc, char *argv[])
if (lvl < WL_MAX) {
current_level = lvl;
redraw_window();
redraw_input(input_line, input_len, input_pos);
}
continue;
}
@@ -857,7 +875,7 @@ int main(int argc, char *argv[])
handle_input(input_line);
input_pos = 0;
input_len = 0;
printf("\033[%d;1H> ", term_rows);
printf("\033[%d;1H\033[32m>\033[0m ", term_rows);
fflush(stdout);
} else if (ch == 0x01) {
/* Ctrl-A: beginning of line */