aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO30
-rw-r--r--commands.txt27
-rw-r--r--src/bell.s45
-rw-r--r--src/cmd.c148
-rw-r--r--src/irc.c272
-rw-r--r--src/irc.h5
-rw-r--r--src/main.c4
-rw-r--r--src/screen.c3
-rw-r--r--ui_keys.txt12
9 files changed, 461 insertions, 85 deletions
diff --git a/TODO b/TODO
index 293f1b2..755f5f0 100644
--- a/TODO
+++ b/TODO
@@ -1,23 +1,33 @@
FujiChat features:
-- respond to incoming CTCPs
- handle incoming PONG (with latency)
-- visual and audible bell
-- nick tab completion
+- nick tab completion (FujiChat's was very lame)
+- option to not show ping/pong
+- hide motd
+- settable real name (currently hardcoded "FujiNetChat User")
Other stuff:
+- at least one keyboard macro (for ChanServ auth)
- error numerics should go to the current screen
-- the server's spontaneous MODE at connect should go to screen 0
+- autojoin on startup
+- add an optional 2nd parameter to /join (key). spec calls for it,
+ I've never seen it used.
+- decide whether to allow mass joins: /join #chan1,#chan2,#chan3
+ not sure how widely supported it is on various networks. right
+ now, it works with libera, but only the first channel gets a
+ screen. better to do it client-side, /join #chan1 #chan2 #chan3,
+ accept lots of arguments (but don't support keys).
+- /join also supports "/join 0", which parts all channels. don't
+ have to do anything special for it, but do document it.
+- 'dead' screens (channels we've parted) should show some kind of
+ indicator, and not accept input.
+- use GR.1 for the activity indicators, so they can be colorful.
+
+See also: ideas.txt
...
-Don't create channel screen until we receive a message from the
-channel. /join ##foo won't create the screen... and if there are no
-screens available, we don't have to check for it.
-
-Don't create query windows unless user explicitly does so.
-
Config file. At minimum, these:
Server
diff --git a/commands.txt b/commands.txt
index 9641d6d..cba40ef 100644
--- a/commands.txt
+++ b/commands.txt
@@ -16,6 +16,11 @@ Joins a channel, creates a new screen if possible. If a screen can't
be created, channel text will be sent to the [server] screen, and
"/m #channel" must be used, to send to the channel.
+/j1 <channel>
+/join1 <channel>
+Joins a channel without creating a new screen. Channel test will be
+sent to the [server] screen. Use "/m #channel" to send to the channel.
+
/m <nick|channel> <text>
/msg <nick|channel> <text>
PRIVMSG to nick or channel.
@@ -36,11 +41,21 @@ Parts (leaves) a channel. If no #chan is given, the current screen's
channel is parted (if you're in a channel screen). If there's a screen
for the channel, it gets closed.
+/names [<channel>]
+Shows the list of users in a channel. Uses the current screen's channel,
+if no <channel> given. On most networks, it's not very useful to use
+/names on a channel you haven't joined.
+
+/topic [<channel>]
+Shows the channel topic and its creator. With no <channel>, uses the
+current screen's channel.
+
/ping [<nick>]
With no argument: ping the server. With arg: CTCP ping the nick.
The contents of RTCLOK are sent as the ping data, so when the
PONG response is received, the round-trip time can be shown, with
up to 1/60 (NTSC) or 1/50 (PAL) second accuracy.
+TODO: not implemented yet.
/me <action>
CTCP ACTION. Only works in a channel or query screen (eventually
@@ -53,6 +68,9 @@ CTCP VERSION.
With <nick>, CTCP CLIENTINFO. Without <nick>, INFO command for the
server.
+/ctcp <nick> <command> [<text>]
+Send arbitrary CTCP commands.
+
/list <arg(s)>
This command will be sent to the server as-is. The only reason it's a
local command is so the argument can be required: sending LIST without
@@ -60,10 +78,17 @@ any arguments lists every channel on the server, which isn't useful.
/color <bg> [<fg>] [<status-active>] [<status-highlight>]
Set colors. This should be on a per-screen basis, eventually.
+TODO: this only takes bg and fg arguments, currently.
/chans
List all channels we've joined. This will actually be limited to
something like 20 (who joins more than 20 channels anyway?)
+TODO: not implemented yet.
/quote <cmd>
-Send raw IRC protocol.
+Send raw IRC protocol to the server. This bypasses local command
+parsing.
+
+/bell <number>
+Set the type of alert that happens when you're PMed or highlighted
+in a channel. 0 = none, 1 = beep, 2 = flash, 3 = beep and flash.
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
diff --git a/src/cmd.c b/src/cmd.c
index ea3f9fa..ba66d2a 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -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();
diff --git a/src/irc.c b/src/irc.c
index 6a66f24..8343897 100644
--- a/src/irc.c
+++ b/src/irc.c
@@ -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();
}
diff --git a/src/irc.h b/src/irc.h
index 8590314..b6791ad 100644
--- a/src/irc.h
+++ b/src/irc.h
@@ -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 */
diff --git a/src/main.c b/src/main.c
index 664b0ed..3f12e00 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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;
diff --git a/ui_keys.txt b/ui_keys.txt
index ddc467d..a6b8dd9 100644
--- a/ui_keys.txt
+++ b/ui_keys.txt
@@ -1,13 +1,13 @@
Hold down Start and:
1-7 - switch screens
-Up Arrow or "-" - scroll current screen up
+Up Arrow (without Control) - scroll current screen up
+Escape - close screen (but do not part channel)
+Tab - switch to last displayed screen
+Left/Right (without Control) - previous/next screen.
+A - switch to active screen
+S - show status (hide edit box)
Future plans:
-A - switch to active screen
-Tab - switch to previous screen
-S - show status (hide edit box)
-Escape - close screen (end query, or part channel). needs confirmation!
-Left/Right - previous/next screen.
? - Show help (also the Help key by itself will do this).