aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2026-02-21 22:11:10 -0500
committerB. Watson <urchlay@slackware.uk>2026-02-21 22:11:10 -0500
commitd3a19b319e8ecdf111de44ffa9847474301edcbb (patch)
treed9586b54b3940c91debaea418b9711c0e94c7f5c /src
parent525a545e62c97c1ed5335d6ce5750341c5ba877e (diff)
downloadfujinet-chat-d3a19b319e8ecdf111de44ffa9847474301edcbb.tar.gz
WIP.
Diffstat (limited to 'src')
-rw-r--r--src/irc.c353
-rw-r--r--src/irc.h4
-rw-r--r--src/main.c10
-rw-r--r--src/screen.c13
-rw-r--r--src/screen.h8
5 files changed, 271 insertions, 117 deletions
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 <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
diff --git a/src/irc.h b/src/irc.h
index 5b9e81e..2c0680f 100644
--- a/src/irc.h
+++ b/src/irc.h
@@ -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);
diff --git a/src/main.c b/src/main.c
index df68eb0..be40d95 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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. */