Skip to content
Snippets Groups Projects
Commit 25a21ac2 authored by Rob Swindell's avatar Rob Swindell :speech_balloon:
Browse files

Merge branch 'mrc-mods-by-codefenix-20241020' into 'master'

MRC: Session stats, mentions, themes, indenting, buffer display, and more

See merge request !464
parents 1e9282d7 c3eba291
No related branches found
No related tags found
1 merge request!464MRC: Session stats, mentions, themes, indenting, buffer display, and more
...@@ -11,13 +11,24 @@ load('sbbsdefs.js'); ...@@ -11,13 +11,24 @@ load('sbbsdefs.js');
load('frame.js'); load('frame.js');
load('scrollbar.js'); load('scrollbar.js');
load('inputline.js'); load('inputline.js');
load("funclib.js"); // for getColor() function
load(js.startup_dir + 'mrc-session.js'); load(js.startup_dir + 'mrc-session.js');
js.on_exit("js.counter = 0"); js.on_exit("js.counter = 0");
js.time_limit=0; js.time_limit=0;
var input_state = 'chat'; var input_state = 'chat';
var show_nicks = false;
var stat_mode = 0; // 0 = Local Session stats (Chatters, Latency, & Mentions); 1 = Global MRC Stats
const MENTION_MARKER = ascii(15);
const INDENT_MARKER = ascii(28);
// default theme
var theme_bg_color = BG_BLUE;
var theme_fg_color = "\x01w\x01h";
var theme_2nd_color = "\x01b\x01h";
var theme_mrc_title = "\x01w\x01hMRC";
var f = new File(js.startup_dir + 'mrc-client.ini'); var f = new File(js.startup_dir + 'mrc-client.ini');
f.open('r'); f.open('r');
...@@ -25,13 +36,14 @@ const settings = { ...@@ -25,13 +36,14 @@ const settings = {
root: f.iniGetObject(), root: f.iniGetObject(),
startup: f.iniGetObject('startup'), startup: f.iniGetObject('startup'),
aliases: f.iniGetObject('aliases') || {}, aliases: f.iniGetObject('aliases') || {},
client: f.iniGetObject('client') || {} client: f.iniGetObject('client') || {},
show_nicks: f.iniGetObject('show_nicks') || {},
theme: f.iniGetObject('theme') || {}
}; };
f.close(); f.close();
f = undefined; f = undefined;
var show_nicks = (settings.client.show_nicks === true) ? true : false;
const NICK_COLOURS = [ const NICK_COLOURS = [
'\x01h\x01r', '\x01h\x01r',
...@@ -52,7 +64,14 @@ const NICK_COLOURS = [ ...@@ -52,7 +64,14 @@ const NICK_COLOURS = [
const PIPE_COLOURS = [2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 14, 15]; const PIPE_COLOURS = [2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 14, 15];
function pipe_to_ctrl_a(str) { const ACT_LVL = [
/* 0: NUL */ "\x01H\x01KNUL",
/* 1: LOW */ "\x01H\x01YLOW",
/* 2: MED */ "\x01H\x01GMED",
/* 3: HI */ "\x01H\x01RHI"
];
function pipe_to_ctrl_a(str) { // could use the pipeToCtrlA function in funclib.js instead
str = str.replace(/\|00/g, "\x01N\x01K"); str = str.replace(/\|00/g, "\x01N\x01K");
str = str.replace(/\|01/g, "\x01N\x01B"); str = str.replace(/\|01/g, "\x01N\x01B");
str = str.replace(/\|02/g, "\x01N\x01G"); str = str.replace(/\|02/g, "\x01N\x01G");
...@@ -84,11 +103,12 @@ function resize_nicklist(frames, nicks) { ...@@ -84,11 +103,12 @@ function resize_nicklist(frames, nicks) {
const maxlen = show_nicks ? Math.max(1, nicks.reduce(function (a, c) { const maxlen = show_nicks ? Math.max(1, nicks.reduce(function (a, c) {
return c.length > a ? c.length : a; return c.length > a ? c.length : a;
}, 0)) : 0; }, 0)) : 0;
frames.nicklist.transparent = !show_nicks;
frames.nicklist.moveTo(frames.top.x + frames.top.width - 1 - maxlen - 1, 2); frames.nicklist.moveTo(frames.top.x + frames.top.width - 1 - maxlen - 1, 2);
frames.nicks.moveTo(frames.nicklist.x + 1, 2); frames.nicks.moveTo(frames.nicklist.x + 1, 2);
frames.nicklist.width = maxlen + (show_nicks ? 2 : 1); frames.nicklist.width = maxlen + 1;
frames.nicks.width = maxlen + 1; frames.nicks.width = maxlen + 1;
frames.output.width = (frames.top.width - frames.nicklist.width) + 1; frames.output.width = (frames.top.width - (show_nicks ? frames.nicklist.width : 0));
} }
function redraw_nicklist(frames, nicks, colours) { function redraw_nicklist(frames, nicks, colours) {
...@@ -105,9 +125,9 @@ function init_display() { ...@@ -105,9 +125,9 @@ function init_display() {
const w = console.screen_columns; const w = console.screen_columns;
const h = console.screen_rows; const h = console.screen_rows;
const f = { top: new Frame(1, 1, w, h, BG_BLACK|LIGHTGRAY) }; const f = { top: new Frame(1, 1, w, h, BG_BLACK|LIGHTGRAY) };
f.title = new Frame(1, 1, w, 1, BG_BLUE|WHITE, f.top); f.title = new Frame(1, 1, w, 1, theme_bg_color|LIGHTGRAY, f.top);
f.output = new Frame(1, 2, 1, h - 3, BG_BLACK|LIGHTGRAY, f.top); f.output = new Frame(1, 2, 1, h - 3, BG_BLACK|LIGHTGRAY, f.top);
f.divider = new Frame(1, h - 1, w, 1, BG_BLUE|WHITE, f.top); f.divider = new Frame(1, h - 1, w, 1, theme_bg_color|LIGHTGRAY, f.top);
f.nicklist = new Frame(w - 2, 2, 2, h - 3, BG_BLACK|LIGHTGRAY, f.top); f.nicklist = new Frame(w - 2, 2, 2, h - 3, BG_BLACK|LIGHTGRAY, f.top);
f.nicks = new Frame(w - 1, 2, 1, h - 3, BG_BLACK|LIGHTGRAY, f.nicklist); f.nicks = new Frame(w - 1, 2, 1, h - 3, BG_BLACK|LIGHTGRAY, f.nicklist);
f.input = new Frame(1, h, w, 1, BG_BLACK|WHITE, f.top); f.input = new Frame(1, h, w, 1, BG_BLACK|WHITE, f.top);
...@@ -115,25 +135,41 @@ function init_display() { ...@@ -115,25 +135,41 @@ function init_display() {
f.nick_scroll = new ScrollBar(f.nicks, { autohide: true }); f.nick_scroll = new ScrollBar(f.nicks, { autohide: true });
f.output.word_wrap = true; f.output.word_wrap = true;
f.divider.gotoxy(f.divider.width - 5, 1); f.divider.gotoxy(f.divider.width - 5, 1);
f.divider.putmsg('/help'); f.divider.putmsg(theme_fg_color + '/help');
f.top.open(); f.top.open();
return f; return f;
} }
function refresh_stats(frames, stats) { function refresh_stats(frames, session) {
const activity = new Array( if (input_state == 'chat' ) {
/* 0: NUL */ "\x01H\x01KNUL",
/* 1: LOW */ "\x01H\x01YLOW",
/* 2: MED */ "\x01H\x01GMED",
/* 3: HI */ "\x01H\x01RHI"
);
frames.divider.clear(); frames.divider.clear();
frames.divider.putmsg(format("\x01w\x01hSTATS\x01b\x01h> \x01w\x01hBBSes \x01b\x01h[\x01w\x01h%d\x01b\x01h] \x01nRooms \x01b\x01h[\x01w\x01h%d\x01b\x01h] \x01nUsers \x01b\x01h[\x01w\x01h%d\x01b\x01h] \x01nLevel \x01b\x01h[%s\x01b\x01h]\x01n", stats[0], stats[1], stats[2], activity[Number(stats[3])])); if (stat_mode == 0) {
frames.divider.putmsg(format(theme_fg_color + "CLIENT STATS" + theme_2nd_color + "> " +
theme_fg_color + "Latency" + theme_2nd_color + " [" + theme_fg_color + "%d" + theme_2nd_color + "] " +
theme_fg_color + "Chatters" + theme_2nd_color + " [" + theme_fg_color + "%d" + theme_2nd_color + "] " +
theme_fg_color + "Mentions" + theme_2nd_color + " [" + theme_fg_color + "%d" + theme_2nd_color + "]",
session.latency,
session.nicks.length,
session.mention_count
));
} else {
frames.divider.putmsg(format(theme_fg_color + "GLOBAL STATS" + theme_2nd_color + "> " +
theme_fg_color + "BBSes" + theme_2nd_color + " [" + theme_fg_color + "%d" + theme_2nd_color + "] " +
theme_fg_color + "Rooms" + theme_2nd_color + " [" + theme_fg_color + "%d" + theme_2nd_color + "] " +
theme_fg_color + "Users" + theme_2nd_color + " [" + theme_fg_color + "%d" + theme_2nd_color + "] " +
theme_fg_color + "Activity" + theme_2nd_color + " [%s" + theme_2nd_color + "]",
session.stats[0],
session.stats[1],
session.stats[2],
ACT_LVL[Number(session.stats[3])]
));
}
frames.divider.gotoxy(frames.divider.width - 5, 1); frames.divider.gotoxy(frames.divider.width - 5, 1);
frames.divider.putmsg('\x01w\x01h/help'); frames.divider.putmsg(theme_fg_color + '/help');
}
} }
function append_message(frames, msg) { function append_message(frames, msg, mention) {
const top = frames.output.offset.y; const top = frames.output.offset.y;
if (frames.output.data_height > frames.output.height) { if (frames.output.data_height > frames.output.height) {
while (frames.output.down()) { while (frames.output.down()) {
...@@ -141,7 +177,18 @@ function append_message(frames, msg) { ...@@ -141,7 +177,18 @@ function append_message(frames, msg) {
} }
frames.output.gotoxy(1, frames.output.height); frames.output.gotoxy(1, frames.output.height);
} }
frames.output.putmsg("\x01k\x01h" + getShortTime(new Date()) + "\x01n " + msg + '\r\n');
// programmatically insert indent(s), if the message length exceeds the frame width.
if (strlen(msg) >= frames.output.width - 8) {
var indent = "\r\n" + (new Array(7).join( " " )) + INDENT_MARKER + " ";
msg = lfexpand(word_wrap(msg, frames.output.width - 9)).replace(/\r\n$/g, "").replace(/\r\n/g, indent).trim();
}
frames.output.putmsg(
(mention ? "\x01k\x017" : "\x01k\x01h") + getShortTime(new Date()) + // timestamp formatting
(mention ? ( "\x01n\x01r\x01h\x01i" + MENTION_MARKER ) : " ") + // mention formatting
"\x01n" + msg + '\r\n' // message itself
);
frames.output.scroll(0, -1); frames.output.scroll(0, -1);
if (input_state == 'scroll') frames.output.scrollTo(0, top); if (input_state == 'scroll') frames.output.scrollTo(0, top);
} }
...@@ -150,9 +197,9 @@ function getShortTime(d) { ...@@ -150,9 +197,9 @@ function getShortTime(d) {
return format( "%02d:%02d", d.getHours(), d.getMinutes() ); return format( "%02d:%02d", d.getHours(), d.getMinutes() );
} }
function display_message(frames, msg, colour) { function display_message(frames, msg, mention) { //, colour param was listed but not used..
const body = pipe_to_ctrl_a(truncsp(msg.body) || '').split(' '); const body = pipe_to_ctrl_a(truncsp(msg.body) || '').split(' ');
append_message(frames, body[0] + '\x01n\x01w ' + body.slice(1).join(' ') + '\x01n\x01w'); append_message(frames, body[0] + '\x01n\x01w ' + body.slice(1).join(' ') + '\x01n\x01w', mention);
} }
function display_server_message(frames, msg) { function display_server_message(frames, msg) {
...@@ -161,14 +208,11 @@ function display_server_message(frames, msg) { ...@@ -161,14 +208,11 @@ function display_server_message(frames, msg) {
function display_title(frames, room, title) { function display_title(frames, room, title) {
frames.title.clear(); frames.title.clear();
frames.title.putmsg('MRC\x01b\x01h>\x01w\x01h #' + room + ' - ' + title); frames.title.putmsg(theme_mrc_title + theme_fg_color + " " + theme_2nd_color + "#" + theme_fg_color + room + theme_2nd_color + ':' + theme_fg_color + title);
} }
function set_alias(alias) { function set_alias(alias) {
const f = new File(js.startup_dir + 'mrc-client.ini'); save_setting(user.alias, 'aliases', alias);
f.open('r+');
f.iniSetValue('aliases', user.alias, alias);
f.close();
} }
function new_alias() { function new_alias() {
...@@ -183,6 +227,36 @@ function new_alias() { ...@@ -183,6 +227,36 @@ function new_alias() {
settings.aliases[user.alias] = alias; settings.aliases[user.alias] = alias;
} }
function list_themes () {
var theme_list = [];
var theme_files = directory(backslash(js.startup_dir) + "mrc-theme-*.ini");
for (var t = 0; t < theme_files.length; t++) {
theme_list.push(file_getname(theme_files[t].replace("mrc-theme-", "").replace(".ini", "")));
}
return theme_list.join(", ");
}
function set_theme (theme_name) {
var f = new File(js.startup_dir + format("mrc-theme-%s.ini", theme_name));
if ( f.open('r') ) {
const theme = f.iniGetObject();
f.close();
f = undefined;
theme_bg_color = getColor(theme.theme_bg_color);
theme_fg_color = "\x01n" + getColor(getColor(theme.theme_fg_color)); // call 2x to get the CTRL_A color
theme_2nd_color = "\x01n" + getColor(getColor(theme.theme_2nd_color)); // for the fb and 2nd colors.
theme_mrc_title = theme.theme_mrc_title;
save_setting(user.alias, "theme", theme_name);
}
}
function save_setting (alias, setting_name, setting_value) {
const f = new File(js.startup_dir + 'mrc-client.ini');
f.open('r+');
f.iniSetValue(setting_name, alias, setting_value);
f.close();
}
function main() { function main() {
var msg; var msg;
...@@ -197,10 +271,18 @@ function main() { ...@@ -197,10 +271,18 @@ function main() {
settings.aliases[user.alias] || new_alias(user.alias) settings.aliases[user.alias] || new_alias(user.alias)
); );
if (settings.show_nicks[user.alias]) {
show_nicks = settings.show_nicks[user.alias];
}
if (settings.theme[user.alias]) {
set_theme(settings.theme[user.alias]);
}
const frames = init_display(); const frames = init_display();
const inputline = new InputLine(frames.input); const inputline = new InputLine(frames.input);
inputline.show_cursor = true; inputline.show_cursor = true;
inputline.max_buffer = 140 - settings.aliases[user.alias].length - 1; inputline.max_buffer = 140;
resize_nicklist(frames, []); resize_nicklist(frames, []);
redraw_nicklist(frames, []); redraw_nicklist(frames, []);
...@@ -235,13 +317,22 @@ function main() { ...@@ -235,13 +317,22 @@ function main() {
); );
display_server_message(frames, '\x01h\x01w/\x01h\x01cnick_suffix \x01h\x01w- \x01n\x01wSet an eight-character suffix for your handle, eg. /nick_suffix <poop>'); display_server_message(frames, '\x01h\x01w/\x01h\x01cnick_suffix \x01h\x01w- \x01n\x01wSet an eight-character suffix for your handle, eg. /nick_suffix <poop>');
display_server_message(frames, '\x01h\x01w/\x01h\x01ctoggle_nicks \x01h\x01w- \x01n\x01wShow/hide the nicklist'); display_server_message(frames, '\x01h\x01w/\x01h\x01ctoggle_nicks \x01h\x01w- \x01n\x01wShow/hide the nicklist');
display_server_message(frames, '\x01h\x01w/\x01h\x01ctoggle_stats \x01h\x01w- \x01n\x01wSwitch between global MRC stats and client/session stats.');
display_server_message(frames, "\x01h\x01w/\x01h\x01ctheme \x01n\x01w- \x01nSelect a theme: " + list_themes() );
display_server_message(frames, '\x01h\x01w/\x01h\x01cquit \x01n\x01w- \x01h\x01wExit the program'); display_server_message(frames, '\x01h\x01w/\x01h\x01cquit \x01n\x01w- \x01h\x01wExit the program');
}); });
session.on('message', function (msg) { session.on('message', function (msg) {
if (msg.from_user == 'SERVER') { if (msg.from_user == 'SERVER') {
display_server_message(frames, msg.body); display_server_message(frames, msg.body);
} else { } else {
display_message(frames, msg, nick_colours[msg.from_user] || ''); var mention = false;
if (msg.body.toUpperCase().indexOf(user.alias.toUpperCase()) >= 0 && msg.from_user !== user.alias) {
console.beep();
mention = true;
session.mention_count = session.mention_count + 1;
refresh_stats (frames, session);
}
display_message(frames, msg, mention); //, nick_colours[msg.from_user] || '');
} }
}); });
session.on('nicks', function (nicks) { session.on('nicks', function (nicks) {
...@@ -250,6 +341,7 @@ function main() { ...@@ -250,6 +341,7 @@ function main() {
}); });
resize_nicklist(frames, nicks); resize_nicklist(frames, nicks);
redraw_nicklist(frames, nicks, nick_colours); redraw_nicklist(frames, nicks, nick_colours);
refresh_stats (frames, session);
}); });
session.on('sent_privmsg', function (user, msg) { session.on('sent_privmsg', function (user, msg) {
display_message(frames, { body: '--> ' + (nick_colours[user] || '') + user + ' ' + msg }); display_message(frames, { body: '--> ' + (nick_colours[user] || '') + user + ' ' + msg });
...@@ -258,9 +350,10 @@ function main() { ...@@ -258,9 +350,10 @@ function main() {
display_title(frames, room, topic); display_title(frames, room, topic);
}); });
session.on('stats', function (stats) { session.on('stats', function (stats) {
if (input_state == 'chat') { refresh_stats(frames, session);
refresh_stats(frames, stats); });
} session.on('latency', function () {
refresh_stats(frames, session);
}); });
if (settings.startup.motd) session.motd(); if (settings.startup.motd) session.motd();
...@@ -270,6 +363,8 @@ function main() { ...@@ -270,6 +363,8 @@ function main() {
var cmd, line, user_input; var cmd, line, user_input;
while (!js.terminated && !break_loop) { while (!js.terminated && !break_loop) {
session.cycle(); session.cycle();
frames.divider.gotoxy(frames.divider.width - 16, 1);
frames.divider.putmsg(theme_2nd_color + "[" + theme_fg_color + ("000" + inputline.buffer.length).slice(-3) + theme_2nd_color + '/' + theme_fg_color + inputline.max_buffer + theme_2nd_color + "]");
user_input = inputline.getkey(); user_input = inputline.getkey();
if (typeof user_input == 'string') { if (typeof user_input == 'string') {
if (input_state == 'chat') { if (input_state == 'chat') {
...@@ -288,15 +383,14 @@ function main() { ...@@ -288,15 +383,14 @@ function main() {
case 'scroll': case 'scroll':
input_state = 'scroll'; input_state = 'scroll';
frames.divider.clear(); frames.divider.clear();
frames.divider.putmsg('UP/DOWN to scroll, ENTER to return'); frames.divider.putmsg(theme_fg_color + 'UP/DOWN, PGUP/PGDN, HOME/END to scroll, ENTER to return');
break; break;
case 'scroll_nicks': case 'scroll_nicks':
input_state = 'scroll_nicks'; input_state = 'scroll_nicks';
frames.divider.clear(); frames.divider.clear();
frames.divider.putmsg('UP/DOWN to scroll nicklist, ENTER to return'); frames.divider.putmsg(theme_fg_color + 'UP/DOWN to scroll nicklist, ENTER to return');
break; break;
case 'nick_prefix': case 'nick_prefix':
log(LOG_DEBUG, 'nick prefix ' + JSON.stringify(cmd));
if (cmd.length == 2) { if (cmd.length == 2) {
if (cmd[1].length == 1) { if (cmd[1].length == 1) {
settings.aliases[user.alias] = settings.aliases[user.alias].replace(/^(\|\d\d)*\S/, cmd[1]); settings.aliases[user.alias] = settings.aliases[user.alias].replace(/^(\|\d\d)*\S/, cmd[1]);
...@@ -313,7 +407,7 @@ function main() { ...@@ -313,7 +407,7 @@ function main() {
case 'nick_colour': case 'nick_colour':
if (cmd.length == 2) { if (cmd.length == 2) {
if (PIPE_COLOURS.indexOf(parseInt(cmd[1])) >= 0) { if (PIPE_COLOURS.indexOf(parseInt(cmd[1])) >= 0) {
var re = new RegExp('(\|\d\d)*' + user.alias, 'i'); var re = new RegExp('(\\|\\d\\d)*' + user.alias, 'i');
settings.aliases[user.alias] = settings.aliases[user.alias].replace(re, format('|%02d%s', cmd[1], user.alias)); settings.aliases[user.alias] = settings.aliases[user.alias].replace(re, format('|%02d%s', cmd[1], user.alias));
set_alias(settings.aliases[user.alias]); set_alias(settings.aliases[user.alias]);
session.alias = settings.aliases[user.alias]; session.alias = settings.aliases[user.alias];
...@@ -339,6 +433,18 @@ function main() { ...@@ -339,6 +433,18 @@ function main() {
show_nicks = !show_nicks; show_nicks = !show_nicks;
resize_nicklist(frames, session.nicks); resize_nicklist(frames, session.nicks);
redraw_nicklist(frames, session.nicks, nick_colours); redraw_nicklist(frames, session.nicks, nick_colours);
save_setting(user.alias, "show_nicks", show_nicks);
break;
case "toggle_stats":
stat_mode = stat_mode === 0 ? 1 : 0;
refresh_stats(frames, session);
break;
case "theme":
set_theme( cmd[1] );
frames.title.attr = theme_bg_color|theme_fg_color;
frames.divider.attr = theme_bg_color|theme_fg_color;
display_title(frames, session.room, session.room_topic);
refresh_stats(frames, session);
break; break;
default: default:
if (typeof session[cmd[0]] == 'function') { if (typeof session[cmd[0]] == 'function') {
...@@ -375,16 +481,27 @@ function main() { ...@@ -375,16 +481,27 @@ function main() {
} }
} else if (input_state == 'scroll' || input_state == 'scroll_nicks') { } else if (input_state == 'scroll' || input_state == 'scroll_nicks') {
var sframe = input_state == 'scroll' ? frames.output : frames.nicks; var sframe = input_state == 'scroll' ? frames.output : frames.nicks;
// to do: page up, page down
if (user_input == KEY_UP && sframe.offset.y > 0) { if (user_input == KEY_UP && sframe.offset.y > 0) {
sframe.scroll(0, -1); sframe.scroll(0, -1);
} else if (user_input == KEY_DOWN && sframe.offset.y + sframe.height < sframe.data_height) { } else if (user_input == KEY_DOWN && sframe.offset.y + sframe.height < sframe.data_height) {
sframe.scroll(0, 1); sframe.scroll(0, 1);
} else if (user_input == KEY_PAGEUP && sframe.offset.y > 0 ) {
sframe.scroll(0, -1 * sframe.height);
frames.output_scroll.cycle();
} else if (user_input == KEY_PAGEDN && sframe.offset.y + sframe.height < sframe.data_height ) {
sframe.scroll(0, sframe.height);
frames.output_scroll.cycle();
} else if (user_input == KEY_HOME) {
sframe.scrollTo(0, 0);
frames.output_scroll.cycle();
} else if (user_input == KEY_END) {
sframe.scrollTo(0, sframe.data_height-sframe.height-1);
frames.output_scroll.cycle();
} else if (user_input == '' || user_input == 'q') { } else if (user_input == '' || user_input == 'q') {
frames.output.scrollTo(1, frames.output.data_height - frames.output.height); frames.output.scrollTo(1, frames.output.data_height - frames.output.height-1);
frames.output_scroll.cycle(); frames.output_scroll.cycle();
refresh_stats(frames, session.stats);
input_state = 'chat'; input_state = 'chat';
refresh_stats(frames, session);
} }
} }
} }
...@@ -395,7 +512,6 @@ function main() { ...@@ -395,7 +512,6 @@ function main() {
} }
yield(); yield();
} }
} }
main(); main();
...@@ -28,13 +28,14 @@ f = undefined; ...@@ -28,13 +28,14 @@ f = undefined;
if (!settings.ssl) if (!settings.ssl)
settings.ssl=false; settings.ssl=false;
const PROTOCOL_VERSION = '1.3.0'; const PROTOCOL_VERSION = '1.3.1';
const MAX_LINE = 256; const MAX_LINE = 256;
const FROM_SITE = system.qwk_id.toLowerCase(); const FROM_SITE = system.name.replace(/ /g, "_");
const SYSTEM_NAME = system_info.system_name || system.name; const SYSTEM_NAME = system_info.system_name || system.name;
const clients = {}; const clients = {};
var last_connect = 0; var last_connect = 0;
var latency_tracker = [];
// User / site name must be ASCII 33-125, no MCI, 30 chars max, underscores // User / site name must be ASCII 33-125, no MCI, 30 chars max, underscores
function sanitize_name(str) { function sanitize_name(str) {
...@@ -205,6 +206,7 @@ function mrc_send(sock, from_user, from_room, to_user, to_site, to_room, msg) { ...@@ -205,6 +206,7 @@ function mrc_send(sock, from_user, from_room, to_user, to_site, to_room, msg) {
sanitize_room(to_room || ''), sanitize_room(to_room || ''),
m m
].join('~') + '~'; ].join('~') + '~';
latency_tracker.push({"line": line.trim(), "time": Date.now()});
log(LOG_DEBUG, 'To MRC: ' + line); log(LOG_DEBUG, 'To MRC: ' + line);
return sock.send(line + '\n'); return sock.send(line + '\n');
} }
...@@ -218,6 +220,12 @@ function mrc_receive(sock) { ...@@ -218,6 +220,12 @@ function mrc_receive(sock) {
while (sock.data_waiting) { while (sock.data_waiting) {
line = sock.recvline(MAX_LINE, settings.timeout); line = sock.recvline(MAX_LINE, settings.timeout);
if (!line || line == '') break; if (!line || line == '') break;
latency_tracker.forEach(function(m) {
if (m.line===line.trim()) {
client_send({ from_user: "SERVER", to_user: 'CLIENT', body: 'LATENCY:' + (Date.now() - m.time) });
latency_tracker = [];
}
});
log(LOG_DEBUG, 'From MRC: ' + line); log(LOG_DEBUG, 'From MRC: ' + line);
message = parse_message(line); message = parse_message(line);
if (!message) continue; if (!message) continue;
...@@ -248,7 +256,7 @@ function main() { ...@@ -248,7 +256,7 @@ function main() {
var mrc_sock; var mrc_sock;
var die = false; var die = false;
var loop = 1800; var last_stats = 0;
while (!die && !js.terminated) { while (!die && !js.terminated) {
yield(); yield();
...@@ -256,11 +264,10 @@ function main() { ...@@ -256,11 +264,10 @@ function main() {
mrc_sock = mrc_connect(settings.server, settings.port, settings.ssl); mrc_sock = mrc_connect(settings.server, settings.port, settings.ssl);
continue; continue;
} }
mswait(10);
loop += 1 if (time() - last_stats > 20) { // TODO: consider moving to settings
if (loop > 2000) {
request_stats(mrc_sock); request_stats(mrc_sock);
loop = 0; last_stats = time();
} }
client_accept(); client_accept();
......
...@@ -14,7 +14,9 @@ function MRC_Session(host, port, user, pass, alias) { ...@@ -14,7 +14,9 @@ function MRC_Session(host, port, user, pass, alias) {
last_ping: 0, last_ping: 0,
last_send: 0, last_send: 0,
alias: alias || user, alias: alias || user,
stats: ['-','-','-','0'] stats: ['-','-','-','0'],
mention_count: 0,
latency: '-'
}; };
const callbacks = { const callbacks = {
...@@ -37,8 +39,8 @@ function MRC_Session(host, port, user, pass, alias) { ...@@ -37,8 +39,8 @@ function MRC_Session(host, port, user, pass, alias) {
} }
function send_message(to_user, to_room, body) { function send_message(to_user, to_room, body) {
if (body.length + state.alias.length + 1 > 140) { if (body.length + state.alias.length + 1 > 250) {
word_wrap(body, 140 - 1 - state.alias.length).split(/\n/).forEach(function (e) { word_wrap(body, 250 - 1 - state.alias.length).split(/\n/).forEach(function (e) {
send(to_user, '', to_room, state.alias + ' ' + e); send(to_user, '', to_room, state.alias + ' ' + e);
}); });
} else { } else {
...@@ -69,6 +71,7 @@ function MRC_Session(host, port, user, pass, alias) { ...@@ -69,6 +71,7 @@ function MRC_Session(host, port, user, pass, alias) {
case 'ROOMTOPIC': case 'ROOMTOPIC':
const room = params.substr(0, params.indexOf(':')); // room is everything left of the first colon (:) const room = params.substr(0, params.indexOf(':')); // room is everything left of the first colon (:)
const topic = params.substr(params.indexOf(':')+1).trim(); // topic is everything right of the first colon (:), including any additional colons to follow const topic = params.substr(params.indexOf(':')+1).trim(); // topic is everything right of the first colon (:), including any additional colons to follow
state.room_topic = topic;
emit('topic', room, topic); emit('topic', room, topic);
break; break;
case 'USERLIST': case 'USERLIST':
...@@ -77,7 +80,11 @@ function MRC_Session(host, port, user, pass, alias) { ...@@ -77,7 +80,11 @@ function MRC_Session(host, port, user, pass, alias) {
break; break;
case 'STATS': case 'STATS':
state.stats = params.split(' '); state.stats = params.split(' ');
emit('stats', state.stats); emit('stats'); //, state.stats);
break;
case 'LATENCY':
state.latency = params;
emit('latency');
break; break;
default: default:
emit('message', msg); emit('message', msg);
...@@ -175,7 +182,7 @@ function MRC_Session(host, port, user, pass, alias) { ...@@ -175,7 +182,7 @@ function MRC_Session(host, port, user, pass, alias) {
const commands = { const commands = {
banners: { banners: {
help: 'List of banners from server' help: 'List of banners from server' // Doesn't do anything?
}, },
chatters: { chatters: {
help: 'List current users' help: 'List current users'
...@@ -266,7 +273,38 @@ function MRC_Session(host, port, user, pass, alias) { ...@@ -266,7 +273,38 @@ function MRC_Session(host, port, user, pass, alias) {
}, },
whoon: { whoon: {
help: 'Display list of users and BBSs' help: 'Display list of users and BBSs'
},
afk: {
help: "Set yourself AFK (Shortcut for STATUS AFK)",
callback: function (str) {
this.send_command('AFK ' + str);
}
},
register: {
help: "Register handle on server (MRC Trust)",
callback: function (str) {
this.send_command('REGISTER ' + str);
}
},
identify: {
help: "Identify as a registered user (MRC Trust)",
callback: function (str) {
this.send_command('IDENTIFY ' + str);
} }
},
update: {
help: "Update user registration (MRC Trust)",
callback: function (str) {
this.send_command('UPDATE ' + str);
}
},
trust: {
help: "MRC Trust Info (MRC Trust)",
callback: function (str) {
this.send_command('TRUST ' + str);
}
}
}; };
Object.keys(commands).forEach(function (e) { Object.keys(commands).forEach(function (e) {
......
; Aqua - An underwater blue & cyan theme
;
; author: Codefenix
;
;
; theme_bg_color = Background color of the top and bottom bars
; theme_fg_color = Foreground color of the primary text in the top and
; bottom bars
; theme_2nd_color = Foreground color of secondary text used for symbols
; and stuff
; theme_mrc_title = Text shown in the upper left corner of the terminal.
; Use CTRL-A codes and ASCII to decorate it to your liking.
;
theme_bg_color = BG_CYAN
theme_fg_color = WHITE
theme_2nd_color = LIGHTBLUE
theme_mrc_title = H6C.R®CøG,N5KÝ¿¿ÝÜÝÄ6ÝHCúR¯C,øù n
; Default - Classic, blue theme theme in the original echicken MRC mod.
;
;
; theme_bg_color = Background color of the top and bottom bars
; theme_fg_color = Foreground color of the primary text in the top and
; bottom bars
; theme_2nd_color = Foreground color of secondary text used for symbols
; and stuff
; theme_mrc_title = Text shown in the upper left corner of the terminal.
; Use CTRL-A codes and ASCII to decorate it to your liking.
;
theme_bg_color = BG_BLUE
theme_fg_color = WHITE
theme_2nd_color = LIGHTBLUE
theme_mrc_title = wHMRCN
; Garden - A theme using natural colors.
;
; author: Codefenix
;
;
; theme_bg_color = Background color of the top and bottom bars
; theme_fg_color = Foreground color of the primary text in the top and
; bottom bars
; theme_2nd_color = Foreground color of secondary text used for symbols
; and stuff
; theme_mrc_title = Text shown in the upper left corner of the terminal.
; Use CTRL-A codes and ASCII to decorate it to your liking.
;
theme_bg_color = BG_GREEN
theme_fg_color = WHITE
theme_2nd_color = LIGHTGREEN
theme_mrc_title = H2Y°±²ÛN3KÝ¿¿ÝÜÝÄH0YÞ2Û²±° n
; CAUTION: CONTENTS MAY BE HOT
;
; author: Codefenix
;
;
; theme_bg_color = Background color of the top and bottom bars
; theme_fg_color = Foreground color of the primary text in the top and
; bottom bars
; theme_2nd_color = Foreground color of secondary text used for symbols
; and stuff
; theme_mrc_title = Text shown in the upper left corner of the terminal.
; Use CTRL-A codes and ASCII to decorate it to your liking.
;
theme_bg_color = BG_RED
theme_fg_color = YELLOW
theme_2nd_color = LIGHTRED
theme_mrc_title = H1Y°±²ÛN1KÝ¿¿ÝÜÝÄH0YÞ1Û²±° R n
; Lilac - A magenta theme.
;
; author: Codefenix
;
;
; theme_bg_color = Background color of the top and bottom bars
; theme_fg_color = Foreground color of the primary text in the top and
; bottom bars
; theme_2nd_color = Foreground color of secondary text used for symbols
; and stuff
; theme_mrc_title = Text shown in the upper left corner of the terminal.
; Use CTRL-A codes and ASCII to decorate it to your liking.
;
theme_bg_color = BG_MAGENTA
theme_fg_color = WHITE
theme_2nd_color = LIGHTMAGENTA
theme_mrc_title = 2M5G2M5G2KÝ¿¿ÝÜÝÄ5Ý2M5G2M5G>>n
; Midnight - A dark, futuristic theme with blues.
;
; author: Codefenix
;
;
; theme_bg_color = Background color of the top and bottom bars
; theme_fg_color = Foreground color of the primary text in the top and
; bottom bars
; theme_2nd_color = Foreground color of secondary text used for symbols
; and stuff
; theme_mrc_title = Text shown in the upper left corner of the terminal.
; Use CTRL-A codes and ASCII to decorate it to your liking.
;
theme_bg_color = BG_BLACK
theme_fg_color = LIGHTCYAN
theme_2nd_color = LIGHTBLUE
theme_mrc_title = BÚH:NC:HW:N4KÝ¿¿ÝÜÝÄH0B W:NC:HB:úNBÄÄn
; Neon - A dark, futuristic theme with reds.
;
; author: Codefenix
;
;
; theme_bg_color = Background color of the top and bottom bars
; theme_fg_color = Foreground color of the primary text in the top and
; bottom bars
; theme_2nd_color = Foreground color of secondary text used for symbols
; and stuff
; theme_mrc_title = Text shown in the upper left corner of the terminal.
; Use CTRL-A codes and ASCII to decorate it to your liking.
;
theme_bg_color = BG_BLACK
theme_fg_color = LIGHTRED
theme_2nd_color = RED
theme_mrc_title = RÚþHþK]N1KÝ¿¿ÝÜÝÄH0 [RþNRþ-ù
; Rustic - A worn wooden theme.
;
; author: Codefenix
;
;
; theme_bg_color = Background color of the top and bottom bars
; theme_fg_color = Foreground color of the primary text in the top and
; bottom bars
; theme_2nd_color = Foreground color of secondary text used for symbols
; and stuff
; theme_mrc_title = Text shown in the upper left corner of the terminal.
; Use CTRL-A codes and ASCII to decorate it to your liking.
;
theme_bg_color = BG_BROWN
theme_fg_color = LIGHTGRAY
theme_2nd_color = DARKGRAY
theme_mrc_title = 3K²±°.7Ý¿¿ÝÜÝÄ3Ý.H~N3K=HÄN3K_H-n
; A gray, stone brick theme.
;
; author: Codefenix
;
;
; theme_bg_color = Background color of the top and bottom bars
; theme_fg_color = Foreground color of the primary text in the top and
; bottom bars
; theme_2nd_color = Foreground color of secondary text used for symbols
; and stuff
; theme_mrc_title = Text shown in the upper left corner of the terminal.
; Use CTRL-A codes and ASCII to decorate it to your liking.
;
theme_bg_color = BG_LIGHTGRAY
theme_fg_color = WHITE
theme_2nd_color = DARKGRAY
theme_mrc_title = WH7ÄÂÄ´N6KÝ¿¿ÝÜÝÄ7ÝHWÃÂÄÁÄ¿n
...@@ -6,7 +6,8 @@ echicken -at- bbs.electronicchicken.com ...@@ -6,7 +6,8 @@ echicken -at- bbs.electronicchicken.com
3) Customization 3) Customization
4) MRC Stats 4) MRC Stats
5) SSL Support 5) SSL Support
6) Support 6) Themes
7) Support
1) Quick Start 1) Quick Start
...@@ -85,14 +86,17 @@ mrc-client.ini: ...@@ -85,14 +86,17 @@ mrc-client.ini:
4) MRC Stats 4) MRC Stats
MRC-Connector makes requests for server stats every 20 seconds. These stats MRC-Connector makes requests for server stats every 20 seconds. These global
are displayed on the MRC-Client screen as well as stored in the mrcstats.dat stats are displayed on the MRC-Client screen by typing /toggle_stats as well
file for display elsewhere. as stored in the mrcstats.dat file for display elsewhere on the BBS.
The file "chat-with-mrc-stats-example.msg" is included as an exammple to For example (optional): The file "chat-with-mrc-stats-example.msg" is included
demonstrate how to display MRC stats on a menu file. The script file to demonstrate how to display MRC stats on a menu file. The script file
"mrc-display-menu-stats.js" must be copied to the /sbbs/mods directory in order "mrc-display-menu-stats.js" must be copied to the /sbbs/mods directory since
for this msg file to work, since it calls this script directly. the menu file calls this script to fetch the stats whenever it's displayed.
*** NOTE: If you are running mrc-display-menu-stats.js like a door
from your external programs menu, you're doing it wrong.
If you do decide to make use of this msg file, rename it as chat.msg and copy If you do decide to make use of this msg file, rename it as chat.msg and copy
it to your /sbbs/text/menu directory, replacing the old chat.msg file. Also be it to your /sbbs/text/menu directory, replacing the old chat.msg file. Also be
...@@ -116,7 +120,22 @@ shouldn't be difficult. Once connected to MRC you can type /BBSES and you should ...@@ -116,7 +120,22 @@ shouldn't be difficult. Once connected to MRC you can type /BBSES and you should
see "Yes" next to your BBS in the SSL column. see "Yes" next to your BBS in the SSL column.
6) Support 6) Themes
MRC comes with several customizable theme files. These can be added/edited as
the system wishes. The client automatically detects any available theme files
matching the pattern:
mrc-theme-<theme_name>.ini
Available themes are listed in /help. User selects a theme by typing
/theme <name>, and the selected theme gets saved to settings for future
sessions.
If a theme file is not available, the classic blue theme gets used by default.
7) Support
- Post a message to 'echicken' in the Synchronet Sysops area on DOVE-Net - Post a message to 'echicken' in the Synchronet Sysops area on DOVE-Net
- Find me on irc.synchro.net in #synchronet - Find me on irc.synchro.net in #synchronet
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment