From d3a19b319e8ecdf111de44ffa9847474301edcbb Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Sat, 21 Feb 2026 22:11:10 -0500 Subject: WIP. --- src/irc.c | 353 ++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 238 insertions(+), 115 deletions(-) (limited to 'src/irc.c') diff --git a/src/irc.c b/src/irc.c index 5be1c85..8dfc6c5 100644 --- a/src/irc.c +++ b/src/irc.c @@ -8,15 +8,9 @@ #include "edbox.h" #include "numerics.h" -#ifdef __ATARI__ #include #include #include "nio.h" -#else -#define CH_EOL '|' -unsigned char rx_buf[MAX_IRC_MSG_LEN]; // RX buffer. -unsigned short bw=0; // # of bytes waiting. -#endif #define MAX_MSG 512 @@ -28,57 +22,125 @@ static char msgbuf[MAX_MSG] = { 0 }; static char *msg; /* with source removed */ static int msgbuf_len = 0, msg_len = 0; -static int joined = 0; +static char regged = 0; -#ifdef __ATARI__ static void join_channel(void) { - scr_create(channel, 1); - txbuf_set_str("JOIN "); - txbuf_append_str(channel); - txbuf_append_str("\n"); + txbuf_set_str2("JOIN ", channel); txbuf_send(); - joined = 1; +} + +static void print_reason(void) { + if(msg_text) { + scr_print_active(": "); + scr_print_active(msg_text); + } else { + scr_print_active("\n"); + } } static void do_pong(void) { - scr_print(SCR_SERVER, "PING/PONG\n"); /* make hiding this a preference, or just ditch it */ - txbuf_set_str("PONG "); - txbuf_append_str(msg_args[0]); + scr_print_server("PING/PONG\n"); /* make hiding this a preference, or just ditch it */ + txbuf_set_str2("PONG ", msg_args[0]); txbuf_send(); } -static char do_chantext(void) { - char s; - - s = scr_getbyname(msg_dest); - scr_putc(s, '<'); - scr_print(s, msg_src); - if(!s) { /* if we don't have a window for it */ - scr_putc(s, '/'); - scr_print(s, msg_dest); +static void do_chan_nick(void) { + scr_print_active("<"); + if(scr_active == SCR_SERVER) { + /* if we don't have a window for it */ + scr_print_active("/"); + scr_print_active(msg_dest); } - scr_putc(s, '>'); - return s; + scr_print_active("> "); } -static char do_private(void) { - char s; - - scr_putc(SCR_PRIV, '*'); - scr_print(SCR_PRIV, msg_src); - scr_putc(SCR_PRIV, '*'); - return s; +static void do_priv_nick(void) { + scr_print_active("*"); + scr_print_active(msg_src); + scr_print_active("* "); } static void do_privmsg(void) { - char s; - if(*msg_dest == '#') - s = do_chantext(); + do_chan_nick(); else - s = do_private(); + do_priv_nick(); - scr_print(s, msg_text); /* text ends with an EOL, don't print another */ + scr_print_active(msg_text); /* text ends with an EOL, don't print another */ +} + +static void do_join(void) { + if(streq_i(usernick, msg_src)) { + /* if our nick is the source, create the screen if needed. if a + screen can't be created, no harm done. */ + if(scr_active == SCR_SERVER) + scr_create(msg_dest, 1); + } else { + scr_print_active(msg_src); + scr_print_active(" has joined "); + scr_print_active(msg_dest); + scr_print_active("\n"); + } +} + +static void do_nick(void) { + if(streq_i(usernick, msg_src)) { + scr_print_active("You are "); + strncpy(usernick, msg_src, 32); + } else { + scr_print_active(msg_src); + scr_print_active(" is "); + } + scr_print_active(" now known as "); + scr_print_active(msg_dest); + scr_print_active("\n"); +} + +static void do_quit(void) { + scr_print_active(msg_src); + scr_print_active(" has quit IRC"); + print_reason(); +} + +static void do_part(void) { + scr_print_active(msg_src); + scr_print_active(" has left "); + scr_print_active(msg_dest); + if(msg_text) { + scr_print_active(": "); + scr_print_active(msg_text); + } else { + scr_print_active("\n"); + } +} + +static void do_topic(void) { + scr_print_active(msg_src); + scr_print_active(" has set the topic of "); + scr_print_active(msg_dest); + scr_print_active(" to: "); + scr_print_active(msg_text); + /* TODO: set topic in the screen! */ +} + +static void do_kick(void) { + scr_print_active(msg_src); + scr_print_active(" has kicked "); + scr_print_active(msg_args[2]); + scr_print_active(" from "); + scr_print_active(msg_dest); + print_reason(); +} + +static void do_mode(void) { + int i; + scr_print_active(msg_src); + scr_print_active(" sets mode: "); + for(i = 0; i < msg_argcount; i++) { + scr_print_active(" "); + scr_print_active(msg_args[i]); + } + scr_print_active("\n"); } /* numerics call this with arg==1, since arg 0 is always our nick. @@ -86,20 +148,42 @@ static void do_privmsg(void) { */ static void do_catchall(int arg) { if(msg_src) { - scr_print(SCR_SERVER, msg_src); - scr_putc(SCR_SERVER, ' '); + scr_print_active(msg_src); + scr_print_active(" "); } - scr_print(SCR_SERVER, msg_cmd); + scr_print_active(msg_cmd); for(; arg < msg_argcount; arg++) { - scr_putc(SCR_SERVER, ' '); - scr_print(SCR_SERVER, msg_args[arg]); + scr_print_active(" "); + scr_print_active(msg_args[arg]); } if(msg_text) { - scr_putc(SCR_SERVER, ' '); - scr_print(SCR_SERVER, msg_text); + scr_print_active(" "); + scr_print_active(msg_text); + } +} + +/* permutes last character (doesn't add one), so for "Bob" you get: + Bo_, Bo1 through Bo9, BoA through BoZ + Gives a total of 36 replacement nicks to try. + Eventually we run out and start repeating, but by then the IRC + server will have disconnected us. + */ +static void permute_nick(void) { + char *last; + + last = usernick + strlen(usernick) - 1; + + if((*last >= '1' && *last < '9') || (*last >= 'A' && *last < 'Z')) { + (*last)++; + } else { + switch(*last) { + case '_': *last = '1'; break; + case '9': *last = 'A'; break; + default: *last = '_'; break; + } } } @@ -108,10 +192,62 @@ static void do_numeric(void) { unsigned int num = atoi(msg_cmd); switch(num) { - /* don't print these, but they do trigger an action */ + /* use the server's idea of what our nick is, in case it got + truncated. */ + case RPL_WELCOME: + strcpy(usernick, msg_args[0]); + regged = 1; + do_catchall(1); + break; + + /* + case RPL_NAMREPLY: + "Users in ##channel", msg_text + + case RPL_TOPIC: + case RPL_NOTOPIC: + set the topic for the screen, if there is one + + case RPL_TOPICWHOTIME: + "Topic was set by ", don't try to parse the UNIX timestamp. + + case RPL_WHOISCERTFP: + case RPL_WHOISREGNICK: + case RPL_WHOISUSER: + case RPL_WHOISSERVER: + case RPL_WHOISOPERATOR: + case RPL_WHOISIDLE: + case RPL_WHOISCHANNELS: + case RPL_WHOISSPECIAL: + case RPL_WHOISACCOUNT: + case RPL_WHOISACTUALLY: + case RPL_WHOISHOST: + case RPL_WHOISMODES: + case RPL_WHOISSECURE: + case RPL_WHOWASUSER: + These always go to the server window. + + case RPL_ENDOFWHOIS: + case RPL_ENDOFWHOWAS: + Don't print. + */ + + case RPL_ENDOFNAMES: + /* don't print, just noise */ + break; + + case ERR_NICKNAMEINUSE: + do_catchall(0); + if(!regged) { + permute_nick(); + irc_register(); + } + break; + + /* don't print these, just noise */ case RPL_MOTDSTART: case RPL_ENDOFMOTD: - if(!joined) join_channel(); + case ERR_NOMOTD: break; case RPL_TOPIC: @@ -140,12 +276,45 @@ static void invalid_msg(char type) { scr_putc(SCR_SERVER, type); scr_putc(SCR_SERVER, '\n'); } -#else -static void do_pong(void) { } -static void invalid_msg(char type) { - printf("??? unknown, type %c\n", type); + +void select_screen(void) { + char s; + if(!msg_src || !msg_dest) { + s = SCR_SERVER; + } else { + s = scr_getbyname(msg_dest); + if(!s && msg_dest[0] != '#') + s = SCR_PRIV; + } + scr_activate(s); +} + +static void dispatch_msg(void) { + /* at this point, we know the message source and destination, so: */ + select_screen(); + + if(streq_i(msg_cmd, "PRIVMSG")) { + do_privmsg(); + } else if(streq_i(msg_cmd, "JOIN")) { + do_join(); + } else if(streq_i(msg_cmd, "NICK")) { + do_nick(); + } else if(streq_i(msg_cmd, "QUIT")) { + do_quit(); + } else if(streq_i(msg_cmd, "PART")) { + do_part(); + } else if(streq_i(msg_cmd, "TOPIC")) { + do_topic(); + } else if(streq_i(msg_cmd, "KICK")) { + do_kick(); + } else if(streq_i(msg_cmd, "MODE")) { + do_mode(); + } else if(isdigit(msg_cmd[0])) { + do_numeric(); + } else { + do_catchall(0); + } } -#endif /* msgbuf contains a complete message from the server, whose length is msgbuf_len. the last character *must* be CH_EOL, @@ -153,14 +322,6 @@ static void invalid_msg(char type) { static void parse_msg(void) { char *p; -#ifndef __ATARI__ - printf("\ngot message:\n"); - for(msg = msgbuf; *msg != CH_EOL; msg++) - putchar(*msg); - putchar('\n'); - putchar('\n'); -#endif - msg_cmd = msg_text = msg_src = msg_dest = 0; msg = msgbuf; @@ -222,38 +383,16 @@ static void parse_msg(void) { } } -#ifdef __ATARI__ - OS.crsinh = 1; - // ui_start_msg(); - if(streq_i(msg_cmd, "PRIVMSG")) { - do_privmsg(); - } else if(isdigit(msg_cmd[0])) { - do_numeric(); - } else { - do_catchall(0); - } - // ui_end_msg(); -#else - { - int i; - printf("src: %s\n", msg_src ? msg_src : ""); - printf("cmd: %s\n", msg_cmd ? msg_cmd : ""); - printf("args: %d\n", msg_argcount); - for(i = 0; i < msg_argcount; i++) - printf(" %d: %s\n", i, msg_args[i]); - printf("text: %s\n", msg_text ? msg_text : ""); - } -#endif + dispatch_msg(); } -static void irc_parse(void) { + +/* we read via block I/O, so split into lines and process each one + separately. */ +static void irc_split_Lines(void) { int i; char *p = rx_buf; -#ifndef __ATARI__ - printf("irc_parse() called, bw == %d\n", bw); -#endif - for(i = 0; i < bw; i++) { msgbuf[msgbuf_len] = *p; if(*p == CH_EOL) { @@ -277,7 +416,6 @@ void print_errnum(void) { scr_print_current(", press any key...\n"); } -#ifdef __ATARI__ int irc_read(void) { if(!trip) return 1; @@ -289,6 +427,7 @@ int irc_read(void) { return 0; } else if(err != 1) { print_errnum(); + cgetc(); return 0; } @@ -309,7 +448,7 @@ int irc_read(void) { trip = 0; PIA.pactl |= 1; // Flag interrupt as serviced, ready for next one. - irc_parse(); + irc_split_Lines(); } return 1; @@ -318,16 +457,15 @@ int irc_read(void) { /* modern.ircdocs.horse say to do this IMMEDIATELY upon TCP connection, without waiting for anything from the server. */ void irc_register(void) { - txbuf_init(); - txbuf_append_str("USER "); - txbuf_append_str(usernick); /* local (UNIX) username, just use the nick */ - txbuf_append_str(" 0 * :FujiNetChat User\n"); /* "real" name (make it a pref?) */ + if(regged) + return; + + /* 2nd arg: local (UNIX) username, just use the nick */ + /* 3rd arg: "real" name (make it a pref?) */ + txbuf_set_str3("USER ", usernick, " 0 * :FujiNetChat User"); txbuf_send(); - txbuf_init(); - txbuf_append_str("NICK "); - txbuf_append_str(usernick); - txbuf_append_str("\n"); + txbuf_set_str2("NICK ", usernick); txbuf_send(); } @@ -343,6 +481,7 @@ static void start_keystroke(void) { } static void keystroke(void) { + if(OS.ch == 0xff) return; if(GTIA_READ.consol == 6) { /* start pressed */ start_keystroke(); } else { @@ -354,22 +493,6 @@ static void keystroke(void) { void irc_loop(void) { while(1) { if(!irc_read()) return; - - if(OS.ch != 0xff) - if(joined) - keystroke(); - else join_channel(); + keystroke(); } } - -#else // !defined(__ATARI__) -/* parsetest */ -int main(int argc, char **argv) { - strcpy((char *)rx_buf, argv[1]); - bw = strlen(rx_buf); - irc_parse(); - /* - */ - return 0; -} -#endif -- cgit v1.2.3