Skip to content
Snippets Groups Projects
Select Git revision
  • master default protected
  • dailybuild_linux-x64
  • dailybuild_win32
  • sqlite
  • rip_abstraction
  • dailybuild_macos-armv8
  • dd_file_lister_filanem_in_desc_color
  • mode7
  • dd_msg_reader_are_you_there_warning_improvement
  • c23-playing
  • syncterm-1.3
  • syncterm-1.2
  • test-build
  • hide_remote_connection_with_telgate
  • 638-can-t-control-c-during-a-file-search
  • add_body_to_pager_email
  • mingw32-build
  • cryptlib-3.4.7
  • ree/mastermind
  • new_user_dat
  • sbbs320d
  • syncterm-1.6
  • syncterm-1.5
  • syncterm-1.4
  • sbbs320b
  • syncterm-1.3
  • syncterm-1.2
  • syncterm-1.2rc6
  • syncterm-1.2rc5
  • push
  • syncterm-1.2rc4
  • syncterm-1.2rc2
  • syncterm-1.2rc1
  • sbbs319b
  • sbbs318b
  • goodbuild_linux-x64_Sep-01-2020
  • goodbuild_win32_Sep-01-2020
  • goodbuild_linux-x64_Aug-31-2020
  • goodbuild_win32_Aug-31-2020
  • goodbuild_win32_Aug-30-2020
40 results

fido-nodelist-browser.js

Blame
  • fido-nodelist-browser.js 9.79 KiB
    require('frame.js', 'Frame');
    require('tree.js', 'Tree');
    require('scrollbar.js', 'ScrollBar');
    require('typeahead.js', 'Typeahead');
    require('fido_syscfg.js', 'FTNDomains');
    require('ftn_nodelist.js', 'NodeList');
    
    function node_info_popup(node, frame, settings) {
    	const fmt = "%10s: \1+\1h\1c%s\1-\r\n";
    	const popup = new Frame(
    		frame.x + 1,
    		Math.floor((frame.y + frame.height - 17) / 2),
    		frame.width - 2,
    		17,
    		BG_BLUE|WHITE,
    		frame
    	);
    	popup.putmsg('\r\n Node Details');
    	popup.gotoxy(1, 4);
    	popup.putmsg(format(fmt, 'Address', node.addr));
    	popup.putmsg(format(fmt, 'Name', node.name));
    	popup.putmsg(format(fmt, 'Sysop', node.sysop));
    	popup.putmsg(format(fmt, 'Location', node.location));
    	popup.putmsg(format(fmt, 'Hub', node.hub));
    	if (node.flags.INA || node.flags.IP) {
    		popup.putmsg(format(fmt, 'Internet', node.flags.INA || node.flags.IP));
    	}
    	const protocol = [];
    	if (node.flags.IBN) protocol.push('Binkp');
    	if (node.flags.IFC) protocol.push('ifcico');
    	if (node.flags.ITN) protocol.push('Telnet');
    	if (node.flags.IVM) protocol.push('Vmodem');
    	if (protocol.length) {
    		popup.putmsg(format(fmt, 'Protocol', protocol.join(', ')));
    	}
    	protocol = undefined;
    	const email = [];
    	if (node.flags.IEM) email.push(node.flags.IEM);
    	if (node.flags.ITX) email.push('TransX');
    	if (node.flags.IUC) email.push('UUEncode');
    	if (node.flags.IMI) email.push('MIME');
    	if (node.flags.ISE) email.push('SEAT');
    	if (email.length) popup.putmsg(format(fmt, 'Email', email.join(', ')));
    	email = undefined;
    	if (node.flags.PING) popup.putmsg('Accepts PING\r\n');
    	var other = [
    		'ZEC', 'REC', 'NEC', 'NC', 'SDS', 'SMH', 'RPK', 'NPK', 'ENC', 'CDP'
    	].filter(function (e) {
    		return typeof node.flags[e] != 'undefined';
    	});
    	if (other.length) popup.putmsg(format(fmt, 'Flags', other.join(', ')));
    	other = ['Private', 'Hold', 'Down'].reduce(function (a, c) {
    		if (node[c.toLowerCase()]) a.push(c);
    		return a;
    	}, []);
    	if (other.length) popup.putmsg(format(fmt, 'Status', other.join(', ')));
    	other = undefined;
    	popup.gotoxy(1, 16);
    	popup.putmsg(' \1h\1cS\1h\1wend netmail  \1h\1cC\1h\1wlose');
    	popup.open();
    	frame.cycle();
    	console.gotoxy(console.screen_columns, console.screen_rows);
    	var user_input;
    	while((user_input = console.inkey(K_NONE).toLowerCase()) == '') {
    		yield();
    	}
    	popup.close();
    	if (user_input == 's') {
    		console.clear(LIGHTGRAY);
    		bbs.netmail(node.sysop + '@' + node.addr, WM_NETMAIL);
    		console.clear(LIGHTGRAY);
    		settings.frame.invalidate();
    	}
    }
    
    function populate_node_tree(filename, zone, net, tree, settings) {
    	const nodelist = new NodeList(filename);
    	nodelist.entries.forEach(function (e) {
    		const z = e.addr.split(':')[0];
    		if (z != zone) return;
    		const n = e.addr.match(/\d+:(\d+)\//)[1];
    		if (n != net) return;
    		const w = Math.floor(((tree.frame.width - 15 - 3) / 2) - 1);
    		tree.addItem(format(
    			'%-15s%-' + w + 's%-' + w + 's',
    			e.addr, e.name.substr(0, w), e.location.substr(0, w)
    		), node_info_popup, e, tree.frame, settings);
    	});
    	// Not sure if it's worth sorting this tree
    	// Nodes probably could be out of order but they generally appear to be in
    	// sequence by the time we get here.
    }
    
    function populate_net_tree(filename, zone, tree, settings) {
    	const nodelist = new NodeList(filename);
    	const nets = [];
    	nodelist.entries.forEach(function (e) {
    		const zn = e.addr.match(/(\d+):(\d+)\//);
    		if (zn[1] != zone) return;
    		if (nets.indexOf(zn[2]) > -1) return;
    		nets.push(zn[2]);
    		const net_tree = tree.addTree('Net ' + zn[2]);
    		const idx = tree.items.length - 1;
    		net_tree.onOpen = function () {
    			populate_node_tree(filename, zone, zn[2], net_tree, settings);
    			if (settings.auto_close_net) {
    				tree.items.forEach(function (e) {
    			    	if (e.text != net_tree.text) {
    			    		e.close();
    			    		e.index = -1;
    			    	}
    			  	});
    			}
    			tree.refresh();
    		}
    		net_tree.onClose = function () {
    			net_tree.items = [];
    		}
    	});
    	tree.items.sort(function (a, b) {
    		if (parseInt(a.text.split(' ')[1]) < parseInt(b.text.split(' ')[1])) {
    			return -1;
    		} else {
    			return 1;
    		}
    	});
    }
    
    function populate_zone_tree(filename, tree, settings) {
    	const nodelist = new NodeList(filename);
    	const zones = [];
    	nodelist.entries.forEach(function (e) {
    		const zone = e.addr.split(':')[0];
    		if (zones.indexOf(zone) > -1) return;
    		zones.push(zone);
    		const zone_tree = tree.addTree('Zone ' + zone);
    		const idx = tree.items.length - 1;
    		zone_tree.onOpen = function () {
    			populate_net_tree(filename, zone, zone_tree, settings);
    			if (settings.auto_close_zone) {
    				tree.items.forEach(function (e) {
    			    	if (e.text != zone_tree.text) {
    			    		e.close();
    			    		e.index = -1;
    			    	}
    			  	});
    			}
    			tree.refresh();
    		}
    		zone_tree.onClose = function () {
    			zone_tree.items = [];
    		}
    	});
    	tree.items.sort(function (a, b) {
    		if (parseInt(a.text.split(' ')[1]) < parseInt(b.text.split(' ')[1])) {
    			return -1;
    		} else {
    			return 1;
    		}
    	});
    }
    
    function populate_domain_tree(filename, domain, tree, settings, frame) {
    	try {
    		const nodelist = new NodeList(filename);
    	} catch (err) {
    		log(LOG_ERR, format('Error parsing %s: %s', filename, err));
    		return;
    	}
    	const domain_tree = tree.addTree(domain);
    	const idx = tree.items.length - 1;
    	// var sframe;
    	domain_tree.onOpen = function () {
    		populate_zone_tree(filename, domain_tree, settings);
    		if (settings.auto_close_domain) {
    			tree.items.forEach(function (e) {
    				if (e.text != domain_tree.text) {
    			    	e.close();
    			    	e.index = -1;
    				}
    			});
    		}
    		// if (nodelist.domain && nodelist.date) {
    		// 	sframe = new Frame(frame.x, frame.y + 1, frame.width, 1, frame.attr, frame);
    		// 	sframe.open();
    		// 	sframe.putmsg(nodelist.domain + ' nodelist for ' + nodelist.date);
    		// }
    		tree.refresh();
    	}
    	domain_tree.onClose = function () {
    		domain_tree.items = [];
    		// if (sframe instanceof Frame) sframe.delete();
    	}
    }
    
    function populate_tree(tree, settings, frame) {
    	const ftn_domains = new FTNDomains();
    	Object.keys(ftn_domains.nodeListFN).forEach(function (e) {
    		if (!file_exists(ftn_domains.nodeListFN[e])) return;
    		const dn = settings['domain_' + e] || e;
    		populate_domain_tree(ftn_domains.nodeListFN[e], dn, tree, settings, frame);
    	});
    	Object.keys(settings).forEach(function (e) {
    		if (e.search(/^nodelist_/) > -1 && file_exists(settings[e])) {
    			const dn = e.replace(/^nodelist_/, '');
    			populate_domain_tree(settings[e], dn, tree, settings, frame);
    		}
    	});
    	tree.items.sort(function (a, b) {
    		return a.text.toLowerCase() < b.text.toLowerCase() ? -1 : 1;
    	});
    	tree.refresh();
    }
    
    function search(frame, settings) {
    	const sframe = new Frame(frame.x, frame.y + 4, frame.width, 3, BG_BLUE|WHITE, frame);
    	sframe.putmsg('Search by address, system name, sysop, or location:');
    	sframe.gotoxy(1, 3);
    	sframe.putmsg("Type a query and wait for results, don't hit enter.");
    	sframe.open();
    	const typeahead = new Typeahead({
    		x: 1,
    		y: sframe.y + 1,
    		bg: 0,
    		prompt: '',
    		frame: sframe,
    		datasources: [
    			function (str) {
    				const w = (Math.floor((frame.width - 9 - 15) / 3) - 1);
    				const ret = [];
    				const ftn_domains = new FTNDomains();
    				const files = Object.keys(ftn_domains.nodeListFN).map(function (e) {
    				    return ftn_domains.nodeListFN[e];
    				});
    				Object.keys(settings).forEach(function (e) {
    					if (e.search(/^nodelist_/) > -1) files.push(settings[e]);
    				});
    				files.forEach(function (e) {
    					if (!file_exists(e)) return
    					const nodelist = new NodeList(e);
    					nodelist.entries.forEach(function (e) {
    						var r = ['addr', 'sysop', 'name', 'location'].some(function (ee) {
    							if (e[ee].search(new RegExp(str, 'i')) > -1) {
    								ret.push({
    									node: e,
    									text: format(
    										'%-15s%-' + w + 's %-' + w + 's %-' + w + 's',
    										e.addr, e.name.substr(0, w), e.location.substr(0, w), e.sysop.substr(0, w)
    									),
    								});
    								return true;
    							}
    							return false;
    						});
    			    	});
    				});
    				return ret;
    			}
    		],
    	});
    	var user_input;
    	while (typeof user_input == 'boolean' || typeof user_input == 'undefined') {
    		user_input = typeahead.inkey(console.inkey(K_NONE));
    		typeahead.cycle();
    		if (frame.cycle()) {
    			console.gotoxy(console.screen_columns, console.screen_rows);
    			typeahead.updateCursor();
    		}
    		yield();
    	}
    	typeahead.close();
    	sframe.close();
    	if (typeof user_input == 'object') {
    		node_info_popup(user_input.node, frame, settings);
    	}
    
    }
    
    function main() {
    	const ca = console.attributes;
    	const bss = bbs.sys_status;
    	bbs.sys_status|=SS_MOFF;
    	const frame = new Frame(1, 1, console.screen_columns, console.screen_rows, BG_BLUE|WHITE);
    	const tree_frame = new Frame(frame.x, frame.y + 2, frame.width, frame.height - 4, BG_BLACK, frame);
    	const tree = new Tree(tree_frame);
    	tree.colors.lfg = WHITE;
    	tree.colors.lbg = BG_CYAN;
    	tree.colors.tfg = LIGHTCYAN;
    	tree.colors.kfg = WHITE;
    	tree.colors.xfg = LIGHTCYAN;
    	const scrollbar = new ScrollBar(tree, { autohide: true });
    	// Valid settings:
    	// auto_close_domain t/f
    	// auto_close_zone t/f
    	// auto_close_net t/f
    	// nodelist_xxx /path/to/some/nodelist
    	const defaults = {
    		auto_close_domain: true,
    		auto_close_zone: true,
    		auto_close_net: true
    	};
    	const settings = load({}, 'modopts.js', 'fido_nodelist_browser') || {};
    	Object.keys(defaults).forEach(function (e) {
    		if (typeof settings[e] == 'undefined') settings[e] = defaults[e];
    	});
    	settings.frame = frame;
    	frame.putmsg('Nodelist Browser');
    	frame.gotoxy(1, frame.height);
    	frame.putmsg('\1h\1cS\1h\1wearch  \1h\1cQ\1h\1wuit');
    	populate_tree(tree, settings, frame);
    	console.clear(LIGHTGRAY);
    	frame.open();
    	tree.open();
    	frame.cycle();
    	scrollbar.cycle();
    	var user_input;
    	while ((user_input = console.getkey(K_NOSPIN).toLowerCase()) != 'q') {
    		if (user_input == 's') {
    			search(frame, settings);
    		} else {
    			tree.getcmd(user_input);
    			scrollbar.cycle();
    		}
    		if (frame.cycle()) console.gotoxy(console.screen_columns, console.screen_rows);
    	}
    	frame.close();
    	bbs.sys_status = bss;
    	console.clear(ca);
    }
    
    main();