diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/bell.s | 45 | ||||
| -rw-r--r-- | src/cmd.c | 148 | ||||
| -rw-r--r-- | src/irc.c | 272 | ||||
| -rw-r--r-- | src/irc.h | 5 | ||||
| -rw-r--r-- | src/main.c | 4 | ||||
| -rw-r--r-- | src/screen.c | 3 |
6 files changed, 409 insertions, 68 deletions
diff --git a/src/bell.s b/src/bell.s new file mode 100644 index 0000000..6a27503 --- /dev/null +++ b/src/bell.s @@ -0,0 +1,45 @@ + + .include "atari.inc" + + .import _bell_type + .export _bell + +DISTVOL = $a8 +PITCH = $40 +JIFFIES = $03 + +_bell: + lda #<bell_callback + sta CDTMA2 + lda #>bell_callback + sta CDTMA2+1 + lda _bell_type + beq done + lda #JIFFIES + sta CDTMV2 + lda _bell_type + and #1 + beq check_flash + lda #DISTVOL + sta AUDC1 + lda #PITCH + sta AUDF1 +check_flash: + lda _bell_type + and #2 + beq done + lda #$08 + sta COLOR4 + lda #JIFFIES + sta CDTMV2 +done: + rts + +bell_callback: + lda #0 + sta AUDC1 + sta AUDF1 + sta COLOR4 + lda #JIFFIES + sta CDTMV2 + rts @@ -12,17 +12,23 @@ char *command, *arg1, *arg2, *arg3; static char *target; +static void do_away(void); +static void do_bell(void); static void do_color(void); +static void do_ctcp(void); static void do_info(void); static void do_j(void); +static void do_j1(void); static void do_list(void); static void do_me(void); static void do_msg(void); +static void do_names(void); static void do_part(void); static void do_ping(void); static void do_query(void); static void do_quit(void); static void do_quote(void); +static void do_topic(void); static void do_ver(void); typedef struct { @@ -35,20 +41,27 @@ typedef struct { OP DEOP VOICE DEVOICE KICK BAN KB IGNORE UNIGNORE MODE */ cmd_t command_defs[] = { + { "AWAY", do_away, 1 }, + { "BELL", do_bell, 1 }, { "COLOR", do_color, 1 }, + { "CTCP", do_ctcp, 1 }, { "INFO", do_info, 0 }, { "J", do_j, 1 }, + { "J1", do_j1, 1 }, { "JOIN", do_j, 1 }, + { "JOIN1", do_j1, 1 }, { "LIST", do_list, 1 }, { "M", do_msg, 1 }, { "ME", do_me, 1 }, { "MSG", do_msg, 1 }, + { "NAMES", do_names, 0 }, { "PART", do_part, 0 }, { "PING", do_ping, 0 }, { "Q", do_query, 1 }, { "QUERY", do_query, 1 }, { "QUIT", do_quit, 0 }, { "QUOTE", do_quote, 1 }, + { "TOPIC", do_topic, 0 }, { "VER", do_ver, 0 }, { "VERSION", do_ver, 0 }, { 0, 0 } @@ -91,7 +104,7 @@ static void err_marker(void) { static void err_arg_req(void) { err_marker(); scr_print_current(cmd_def->cmd); - scr_print_current(" requires an argument\n"); + scr_print_current(": missing argument\n"); } static void err_no_scr_target(void) { @@ -99,12 +112,6 @@ static void err_no_scr_target(void) { scr_print_current("No channel/nick for screen\n"); } -static void err_target_req(void) { - err_marker(); - scr_print_current(cmd_def->cmd); - scr_print_current(" requires target channel/nick\n"); -} - /* arg points to something like: "part #channel I'm outta here\0" after nextarg(), arg points to "part\0" only, and ret points @@ -130,12 +137,17 @@ static char *nextarg(char *arg) { return 0; } -static void do_j(void) { - /* TODO: add to channel list, once we have one */ +static void do_j1(void) { txbuf_set_str2("JOIN ", arg1); txbuf_send(); } +static void do_j(void) { + if(!scr_getbyname(arg1)) + scr_create(arg1, 1); + do_j1(); +} + static void do_quit(void) { txbuf_set_str("QUIT"); if(arg1) @@ -152,7 +164,7 @@ static void do_part(void) { } if(!target) { - err_target_req(); + err_no_scr_target(); return; } @@ -162,6 +174,41 @@ static void do_part(void) { txbuf_send(); } +static void do_topic(void) { + if(arg1[0] == '#') { + target = arg1; + arg2 = nextarg(arg1); + } else { + arg2 = arg1; + } + + if(!target) { + err_no_scr_target(); + return; + } + + txbuf_set_str2("TOPIC ", target); + if(arg2) + txbuf_append_str2(" :", arg2); + txbuf_send(); +} + +static void do_names(void) { + if(arg1[0] == '#') { + target = arg1; + arg2 = nextarg(arg1); + } else { + arg2 = arg1; + } + + if(!target) { + err_no_scr_target(); + return; + } + txbuf_set_str2("NAMES ", target); + txbuf_send(); +} + static void do_server_info(void) { txbuf_send_str("INFO"); } @@ -170,27 +217,70 @@ static void do_server_ping(void) { txbuf_send_str("PING 0xdeadbeef"); } -static void do_ctcp_ping(void) { +/* arg1 = nick + arg2 = CTCP type + arg3 = optional data */ +static void send_ctcp(void) { txbuf_set_str3("PRIVMSG ", arg1, " :\x01"); - txbuf_append_str("PING 0xdeadbeef\x01"); + txbuf_append_str(arg2); + if(arg3) + txbuf_append_str2(" ", arg3); + txbuf_append_str("\x01"); txbuf_send(); } +long read_rtclok(void) { + long r; + + r = ((long)OS.rtclok[0] << 16); + r |= (OS.rtclok[1] << 8); + r |= OS.rtclok[2]; + + return r; +} + +static void rtclok_to_numbuf(void) { + long r; + r = read_rtclok(); + ltoa(r, numbuf, 10); +} + +static void do_ctcp_ping(void) { + arg2 = "PING"; + rtclok_to_numbuf(); + arg3 = numbuf; + send_ctcp(); +} + static void do_ctcp_info(void) { - txbuf_set_str3("PRIVMSG ", arg1, " :\x01"); - txbuf_append_str("CLIENTINFO\x01"); - txbuf_send(); + arg2 = "CLIENTINFO"; + arg3 = 0; + send_ctcp(); } static void do_ctcp_ver(void) { - txbuf_set_str3("PRIVMSG ", arg1, " :\x01"); - txbuf_append_str("VERSION\x01"); - txbuf_send(); + arg2 = "VERSION"; + arg3 = 0; + send_ctcp(); +} + +static void do_ctcp(void) { + if(!arg1) { + err_arg_req(); + return; + } + arg2 = nextarg(arg1); + if(!arg2) { + err_arg_req(); + return; + } + arg3 = nextarg(arg2); + send_ctcp(); } static void do_me(void) { if(!target) { - err_target_req(); + err_no_scr_target(); return; } @@ -243,6 +333,10 @@ static void do_color(void) { } static void do_query(void) { + /* don't create a query if we already got one! */ + if(scr_getbyname(arg1)) + return; + if(scr_create(arg1, 1) == 0xff) { err_marker(); scr_print_current("Can't create query, all screens in use\n"); @@ -271,6 +365,17 @@ static void do_msg(void) { } } +static void do_away(void) { + OS.atract = 0x80; + irc_away = 1; + txbuf_set_str2("AWAY :", arg1); + txbuf_send(); +} + +static void do_bell(void) { + bell_type = *arg1 - '0'; +} + static int cmd_local(void) { arg1 = nextarg(command); @@ -316,7 +421,10 @@ static void cmd_slash(void) { void cmd_command(char *cmd) { command = cmd; - target = scr_get_cur_name(); + if(scr_current > 1) + target = scr_get_cur_name(); + else + target = 0; if(cmd[0] == '/' && cmd[1] && cmd[1] != '/') cmd_slash(); @@ -15,15 +15,23 @@ #define MAX_MSG 512 +extern void __fastcall__ bell(void); /* see src/bell.s */ + char *msg_src, *msg_cmd, *msg_dest, *msg_text; char *msg_args[MAX_MSG_ARGS]; int msg_argcount; +char irc_away = 0; +char bell_type = 3; + static char msgbuf[MAX_MSG] = { 0 }; static char *msg; /* with source removed */ static int msgbuf_len = 0, msg_len = 0; static char regged = 0, hilite = 0; +static char scr_prev = SCR_PRIV; + +char numbuf[10]; /* static void join_channel(void) { @@ -56,6 +64,7 @@ static void hilite_bold(void) { } static void do_chan_nick(void) { + if(hilite) bell(); hilite_bold(); scr_print_active("<"); hilite_bold(); @@ -75,6 +84,107 @@ static void do_priv_nick(void) { scr_print_active("*"); scr_print_active(msg_src); scr_print_active("* "); + bell(); +} + +static void print_ping_time(char *p) { + static long now, pingtime; + static int sec, frac; + + now = read_rtclok(); + pingtime = atol(p); + + /* correct for rtclock rollover (every 77 hours) */ + if(now < pingtime) now |= 0x01000000L; + + pingtime = now - pingtime; + + sec = pingtime / hz; + frac = pingtime % hz; + frac *= 1000; + frac /= (hz * 10); + + scr_print_active("*** "); + scr_print_active(msg_src); + scr_print_active(" ping time: "); + itoa(sec, numbuf, 10); + scr_print_active(numbuf); + scr_print_active("."); + itoa(frac, numbuf, 10); + scr_print_active(numbuf); + scr_print_active(" sec"); + + /* for debugging: + scr_print_active(" "); + ltoa(pingtime, numbuf, 10); + scr_print_active(numbuf); + */ +} + +/* FIXME: this isn't very fast */ +static void do_ctcp(int is_notice) { + static char *p, *ctcp_type, *resp; + + resp = 0; + ctcp_type = ++msg_text; /* skip leading ^A */ + + if( (p = strchr(msg_text, '\x01')) ) { + /* kill trailing ^A */ + *p = 0; + } + + if( (p = strchr(msg_text, ' ')) ) { + *p++ = 0; + } + + if(is_notice) { + /* NOTICEs are responses */ + if(p && streq_i(ctcp_type, "PING")) { + print_ping_time(p); + } else { + scr_print_active("*** CTCP "); + scr_print_active(ctcp_type); + scr_print_active(" response from "); + scr_print_active(msg_src); + if(p) { + scr_print_active(": "); + scr_print_active(p); + } + } + scr_eol_active(); + } else { + /* this is a PRIVMSG (aka a request) */ + if(streq_i(ctcp_type, "ACTION")) { + scr_print_active("* "); + scr_print_active(msg_src); + scr_print_active(" "); + scr_print_active(p); + scr_eol_active(); + return; + } + + scr_print_active("*** CTCP "); + scr_print_active(ctcp_type); + scr_print_active(" request from "); + scr_print_active(msg_src); + scr_eol_active(); + + if(streq_i(ctcp_type, "PING")) { + resp = p; + } else if(streq_i(ctcp_type, "CLIENTINFO")) { + resp = "PING VERSION CLIENTINFO"; + } else if(streq_i(ctcp_type, "VERSION")) { + resp = "FujiNetChat pre-alpha on an Atari 8-bit"; + } else { + /* unknown CTCP type, ignore */ + return; + } + + txbuf_set_str3("NOTICE ", msg_src, " :\x01"); + txbuf_append_str3(ctcp_type, " ", resp); + txbuf_append_str("\x01"); + txbuf_send(); + } } static void do_privmsg(void) { @@ -84,6 +194,11 @@ static void do_privmsg(void) { else hilite = 0; + if(*msg_text == '\x01') { + do_ctcp(0); + return; + } + if(*msg_dest == '#') do_chan_nick(); else @@ -93,18 +208,25 @@ static void do_privmsg(void) { scr_eol_active(); } +static void do_notice(void) { + if(*msg_text == '\x01') { + do_ctcp(1); + } else { + scr_print_active("NOTICE "); + do_privmsg(); + } +} + 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); + scr_print_active("You have "); } else { scr_print_active(msg_src); - scr_print_active(" has joined "); - scr_print_active(msg_dest); - scr_eol_active(); + scr_print_active(" has "); } + scr_print_active("joined "); + scr_print_active(msg_dest); + scr_eol_active(); } static void do_nick(void) { @@ -158,11 +280,14 @@ static void do_kick(void) { static void do_mode(void) { int i; - scr_print_active(msg_src); + if(msg_src) + scr_print_active(msg_src); + else + scr_print_active("Server"); scr_print_active(" sets mode: "); for(i = 0; i < msg_argcount; i++) { - scr_print_active(" "); scr_print_active(msg_args[i]); + scr_print_active(" "); } if(msg_text) scr_print_active(msg_text); scr_eol_active(); @@ -227,16 +352,6 @@ static void do_numeric(void) { 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: @@ -252,16 +367,8 @@ static void do_numeric(void) { 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) { @@ -276,20 +383,29 @@ static void do_numeric(void) { case ERR_NOMOTD: break; + case RPL_NAMREPLY: + scr_print_active(msg_args[2]); + scr_print_active(" users: "); + scr_print_active(msg_text); + scr_print_active("\n"); + break; + + case RPL_ENDOFNAMES: + /* don't print, just noise */ + break; + case RPL_TOPIC: - s = scr_getbyname(msg_args[1]); - scr_print(s, "Topic for "); - scr_print(s, msg_args[1]); - scr_print(s, ": "); - scr_print(s, msg_text); - scr_putc(s, '\n'); + scr_print_active("Topic for "); + scr_print_active(msg_args[1]); + scr_print_active(": "); + scr_print_active(msg_text); + scr_print_active("\n"); break; case RPL_TOPICWHOTIME: - s = scr_getbyname(msg_args[1]); - scr_print(s, "Topic set by: "); - scr_print(s, msg_args[1]); - scr_putc(s, '\n'); + scr_print_active("Topic set by "); + scr_print_active(msg_args[2]); + scr_print_active("\n"); break; default: @@ -306,12 +422,19 @@ static void invalid_msg(char type) { void select_screen(void) { char s; - if(!msg_src || !msg_dest) { + if(!msg_dest) { s = SCR_SERVER; - } else { + } else if(*msg_dest == '#') { s = scr_getbyname(msg_dest); - if(!s && msg_dest[0] != '#') - s = SCR_PRIV; + if(!s) s = SCR_SERVER; + } else { + s = scr_getbyname(msg_src); + if(!s) { + if(streq_i(msg_cmd, "PRIVMSG")) /* or maybe NOTICE? */ + s = SCR_PRIV; + else + s = SCR_SERVER; + } } scr_activate(s); } @@ -322,6 +445,8 @@ static void dispatch_msg(void) { if(streq_i(msg_cmd, "PRIVMSG")) { do_privmsg(); + } else if(streq_i(msg_cmd, "NOTICE")) { + do_notice(); } else if(streq_i(msg_cmd, "JOIN")) { do_join(); } else if(streq_i(msg_cmd, "NICK")) { @@ -460,10 +585,9 @@ static void irc_split_Lines(void) { /* TODO: there needs to be a scr_printnum() */ void print_errnum(void) { extern unsigned char err; - char tmp[10]; scr_print_current("Error #"); - itoa(err, tmp, 10); - scr_print_current(tmp); + itoa(err, numbuf, 10); + scr_print_current(numbuf); scr_print_current(", press any key...\n"); } @@ -473,11 +597,13 @@ int irc_read(void) { err = nstatus(url); if(err != 1) { + regged = 0; if(err == 136) { scr_print_current("Disconnected, press any key...\n"); } else { print_errnum(); } + bell(); cgetc(); scr_display(0); return 0; @@ -530,23 +656,71 @@ static void scrollback() { scr_end_scrollback(); } +static void hunt_screen(signed char dir) { + signed char s = scr_current; + + do { + s += dir; + if(s < 0) + s = MAX_SCREENS - 1; + s %= MAX_SCREENS; + } while(scr_status[s] == SCR_UNUSED); + + scr_display(s); +} + +void switch_to_active() { + char i; + + for(i = 0; i < MAX_SCREENS; i++) { + if(scr_status[i] == SCR_ACTIVE) { + scr_prev = scr_current; + scr_display(i); + return; + } + } +} + static void start_keystroke(void) { char i, s; i = cgetc(); if(i >= '1' && i <= '7') { s = i - '1'; - if(scr_status[s] != SCR_UNUSED) - scr_display(s); + if(s != scr_current) { + if(scr_status[s] != SCR_UNUSED) { + scr_prev = scr_current; + scr_display(s); + } + } } else if(i == CH_CURS_UP || i == '-') { scrollback(); - } else if(i == 0x1b) { /* escape */ + } else if(i == CH_ESC) { + scr_prev = SCR_PRIV; scr_destroy(scr_current); + } else if(i == CH_CURS_LEFT || i == '+') { + scr_prev = scr_current; + hunt_screen(-1); + } else if(i == CH_CURS_RIGHT || i == '*') { + scr_prev = scr_current; + hunt_screen(1); + } else if(i == CH_TAB) { + i = scr_current; + scr_display(scr_prev); + scr_prev = i; + } else if(i == 'a' || i == 'A') { + switch_to_active(); + } else if(i == 's' || i == 'S') { + edbox_hide(); } } static void keystroke(void) { if(OS.ch == 0xff) return; + if(irc_away) { + txbuf_send_str("AWAY"); + irc_away = 0; + } if(GTIA_READ.consol == 6) { /* start pressed */ start_keystroke(); } else { @@ -557,6 +731,10 @@ static void keystroke(void) { /* only exits on error (e.g. connection closed, which might be via /QUIT). */ void irc_loop(void) { while(1) { + if(!irc_away && (OS.atract & 0x80)) { + irc_away = 1; + txbuf_send_str("AWAY :ATRACT mode"); + } if(!irc_read()) return; keystroke(); } @@ -11,6 +11,7 @@ extern char *rx_buf; extern unsigned short rxbuflen; extern unsigned char err; extern unsigned char trip; +extern char hz; extern unsigned int txbuflen; extern char *tx_buf; @@ -41,9 +42,12 @@ void print_error(unsigned char err); /**** irc.c */ #define MAX_MSG_ARGS 8 +extern char numbuf[10]; extern char *msg_src, *msg_cmd, *msg_dest, *msg_text; extern char *msg_args[MAX_MSG_ARGS]; extern int msg_argcount; +extern char irc_away; +extern char bell_type; /* call this once, right after TCP connection is established. */ void irc_register(void); @@ -57,3 +61,4 @@ void print_errnum(void); /**** cmd.c */ void cmd_command(char *cmd); void cmd_execute(void); +long read_rtclok(void); /* irc.c needs this one so it's not static */ @@ -23,13 +23,13 @@ char url[256] = DEF_URL; // URL char usernick[32] = DEF_NICK; -char tmp[8]; // temporary # to string unsigned char err; // error code of last operation. unsigned char trip=0; // if trip=1, fujinet is asking us for attention. bool old_enabled=false; // were interrupts enabled for old vector void* old_vprced; // old PROCEED vector, restored on exit. unsigned short rxbuflen; unsigned int txbuflen; // TX buffer length +char hz; /* 50 for PAL, 60 for NSTC */ /* TODO: user modes (default +iw), fg/bg color... */ @@ -142,6 +142,8 @@ int main(void) { OS.color2 = 0xc0; /* darkest green background */ OS.color1 = 0x0c; /* bright text */ + hz = (GTIA_READ.pal & 0x0e) ? 60 : 50; + scr_init(); while(1) { diff --git a/src/screen.c b/src/screen.c index f442e66..617ea2f 100644 --- a/src/screen.c +++ b/src/screen.c @@ -61,6 +61,7 @@ void scr_init(void) { scr_display(0); } +/* TODO: don't create screen if it already exists! */ char scr_create(const char *name, char display) { int i; @@ -164,6 +165,8 @@ void scr_refresh(void) { char scr_getbyname(const char *name) { char i; + if(!name) return 0; + for(i = 2; i < MAX_SCREENS; i++) { if(strcasecmp(name, scr_names[i]) == 0) return i; |
