diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/irc.c | 353 | ||||
| -rw-r--r-- | src/irc.h | 4 | ||||
| -rw-r--r-- | src/main.c | 10 | ||||
| -rw-r--r-- | src/screen.c | 13 | ||||
| -rw-r--r-- | src/screen.h | 8 |
5 files changed, 271 insertions, 117 deletions
@@ -8,15 +8,9 @@ #include "edbox.h" #include "numerics.h" -#ifdef __ATARI__ #include <atari.h> #include <conio.h> #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 <nick>", 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 : "<none>"); - printf("cmd: %s\n", msg_cmd ? msg_cmd : "<none>"); - 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 : "<none>"); - } -#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 @@ -25,6 +25,10 @@ void txbuf_append_str(const char *str); /* clears the transmit buffer, then appends a string to it. */ void txbuf_set_str(const char *str); +/* as txbuf_set_str2(), but multiple strings. */ +void txbuf_set_str2(const char *s1, const char *s2); +void txbuf_set_str3(const char *s1, const char *s2, const char *s3); + /* sends whatever's in the transmit buffer, then clears it. if nothing was in the buffer, nothing gets sent. */ void txbuf_send(void); @@ -69,6 +69,16 @@ void txbuf_set_str(const char *str) { txbuf_append_str(str); } +void txbuf_set_str2(const char *s1, const char *s2) { + txbuf_set_str(s1); + txbuf_append_str(s2); +} + +void txbuf_set_str3(const char *s1, const char *s2, const char *s3) { + txbuf_set_str2(s1, s2); + txbuf_append_str(s3); +} + void txbuf_send(void) { /* don't sent empty buffer */ if(!txbuflen) return; diff --git a/src/screen.c b/src/screen.c index 3e3f5df..b98a26a 100644 --- a/src/screen.c +++ b/src/screen.c @@ -66,10 +66,11 @@ char scr_create(const char *name, char display) { strcpy(scr_names[i], name); scr_status[i] = SCR_INACTIVE; scr_topics[i][0] = '\0'; - if(display) + if(display) { scr_display(i); - else + } else { scr_display(scr_current); + } return i; } } @@ -225,6 +226,14 @@ void scr_print_active(const char *text) { scr_print(scr_active, text); } +void scr_print_server(const char *text) { + scr_print(SCR_SERVER, text); +} + +void scr_print_priv(const char *text) { + scr_print(SCR_SERVER, text); +} + void scr_activate(char s) { if(s != scr_current) { scr_status[s] = SCR_ACTIVE; diff --git a/src/screen.h b/src/screen.h index 51bf090..fe8c928 100644 --- a/src/screen.h +++ b/src/screen.h @@ -18,6 +18,9 @@ /* the screen that's currently displaying */ extern char scr_current; +/* the screen that's currently being written to */ +extern char scr_active; + /* which screens are "active". the screen being displayed is never active. any screen that's not visible that's had anything written to it gets marked active. switching the display to an @@ -63,6 +66,8 @@ void scr_refresh(void); returns 0 (the server messages screen) */ char scr_getbyname(const char *name); +void scr_activate_name(const char *name); + /* print one character to a screen. handles scrolling. will not print an EOL at column 0 (just ignores it). */ void scr_putc(char s, char c); @@ -78,6 +83,9 @@ void scr_print_active(const char *text); /* print to the currently-displayed screen */ void scr_print_current(const char *text); +void scr_print_server(const char *text); +void scr_print_priv(const char *text); + /* set a screen's status to active, if it's not the currently-displayed one. scr_print() sets it already, but anything that uses scr_putc() will have to call this. */ |
