diff --git a/exec/load/fido.js b/exec/load/fido.js
index 30a2113621db47995c4aa207c3d7215626a05fa7..d1e449668087ed99731b0c71e1bfa57931218e86 100644
--- a/exec/load/fido.js
+++ b/exec/load/fido.js
@@ -27,6 +27,11 @@
  * 		
  * FIDO.parse_flo_file_path(path, default_zone, domain)
  * 		Parses a flo filename and path into the returned FIDO.Addr object.
+ * 
+ * FIDO.parse_nodelist(path, warn)
+ * 		Parses a nodelist and returns an object with an entries array in
+ * 		it containing all the nodelist entries.  If warn is true, will
+ * 		warn on "illegal" values.
  */
 
 var FIDO = {
@@ -236,6 +241,152 @@ var FIDO = {
 			}, this);
 			f.close();
 		}
+	},
+	Node:function(addr, hub) {
+		this.addr = addr.str;
+		this.hub = hub.str;
+		this.private = this.hold = this.down = false;
+	},
+	parse_nodelist:function(filename, warn)
+	{
+		var f = new File(filename);
+		var ret = {};
+
+		if (warn === undefined)
+			warn = false;
+
+		if (!f.open("r"))
+			throw("Unable to open '"+f.name+"'.");
+
+		// Validate first line...
+		var line = f.readln(2048);
+		if (line == undefined)
+			throw("Unable to read first line in '"+f.name+"'");
+		var m;
+		if ((m=line.match(/^;A (.*) Nodelist for (.*) -- Day number ([0-9]+) : ([0-9]{5})$/)) !== null) {
+			ret.domain = m[1];
+			ret.date = m[2];	// TODO: Parse date into a Date()
+			ret.daynum = parseInt(m[3], 10);
+			ret.crc = parseInt(m[4], 10);
+			f.rewind();
+			// TODO: Must exclude the EOF character...
+			/* if (ret.crc !== f.crc16)
+				log(LOG_WARNING, "CRC mismatch on '"+f.name+"'.  Got "+f.crc16+" expected "+ret.crc);
+			*/
+			f.rewind();
+		}
+		else
+			f.rewind();
+
+		var hub = new FIDO.Addr('0:0/0');
+		var node = new FIDO.Addr('0:0/0');
+		var fields;
+		var lineno = 0;
+		var entry;
+		var flags;
+		var flag;
+		var value;
+		ret.entries = [];
+
+		while ((line = f.readln(2048))) {
+			lineno++;
+			if (line[0] === ';')
+				continue;
+			fields = line.split(/,/);
+			switch(fields[0]) {
+				case 'Zone':
+					node.zone = parseInt(fields[1], 10);
+					node.net = 0;
+					node.node = 0;
+					hub.zone = node.zone;
+					hub.net = 0;
+					hub.node = 0;
+					break;
+				case 'Region':
+					node.net = parseInt(fields[1], 10);
+					node.node = 0;
+					hub.net = node.net;
+					hub.node = 0;
+					break;
+				case 'Host':
+					node.net = parseInt(fields[1], 10);
+					node.node = 0;
+					hub.net = node.net;
+					hub.node = 0;
+					break;
+				case 'Hub':
+					hub.node = parseInt(fields[1], 10);
+					node.node = parseInt(fields[1], 10);
+					break;
+				case 'Pvt':
+					node.node = parseInt(fields[1], 10);
+					break;
+				case 'Hold':
+					node.node = parseInt(fields[1], 10);
+					break;
+				case 'Down':
+					node.node = parseInt(fields[1], 10);
+					break;
+				case '':
+					node.node = parseInt(fields[1], 10);
+					break;
+				case '\x1a':	// EOF
+					continue;
+				default:
+					if (warn)
+						log(LOG_WARNING, "Unhandled nodelist Keyword line "+lineno+" of '"+f.name+"'");
+					continue;
+			}
+			entry = new Node(node, hub);
+			switch(fields[0]) {
+				case 'Pvt':
+					entry.private = true;
+					break;
+				case 'Hold':
+					entry.hold = true;
+					break;
+				case 'Down':
+					entry.down = true;
+					break;
+			}
+			entry.name = fields[2].replace(/_/g, ' ');
+			entry.location = fields[3].replace(/_/g, ' ');
+			entry.sysop = fields[4].replace(/_/g, ' ');
+			entry.phone = fields[5];
+			entry.baud = parseInt(fields[6]);
+			if (warn) {
+				switch(fields[6]) {
+					case '300':
+					case '1200':
+					case '2400':
+					case '9600':
+					case '19200':
+					case '38400':
+						break;
+					default:
+						log(LOG_WARNING, "Illegal nodelist baud rate '"+fields[6]+"' line "+lineno+" of '"+f.name+"'");
+				}
+			}
+			flags = fields.slice(7);
+			entry.flags = {};
+			while(flags.length > 0) {
+				flag = flags.shift();
+				if (warn) {
+					if (flag.length > 32)
+						log(LOG_WARNING, "Illegal nodelist flag '"+flag+"' longer than 32 characters");
+				}
+				if ((m = flag.match(/^(.*?):(.*)$/))) {
+					flag = m[1];
+					value = m[2];
+					entry.flags[flag] = value;
+				}
+				else
+					value = true;
+				entry.flags[flag] = value;
+			}
+			ret.entries.push(entry);
+		}
+		return ret;
 	}
 };
 Object.defineProperties(FIDO.Addr.prototype, {
@@ -297,5 +448,53 @@ FIDO.Addr.prototype.flo_outbound = function(default_zone, default_domain)
 	ret += format("%04x%04x.", this.net, this.node);
 	return ret.substr(1);
 };
-FIDO.ReadDomainMap();
+Object.defineProperties(FIDO.Node.prototype, {
+	'binkp_host': {
+		get: function() {
+			var iflags = ['INA', 'IFC', 'ITN', 'IVM', 'IFT', 'IP'];
+			var i;
 
+			if (this.flags.IBN === undefined)
+				return undefined;
+			if (this.flags.IBN !== true) {
+				// Address or port number included here...
+				if (this.flags.IBN.search(/^[0-9]+$/) == -1) {
+					if (this.flags.IBN.indexOf(':' !== -1))
+						return this.flags.IBN.replace(/:.*$/,'');
+					return this.flags.IBN;
+				}
+			}
+			for (i in iflags) {
+				if (this.flags[iflags[i]] === undefined)
+					continue;
+				if (this.flags[iflags[i]] === true)
+					continue;
+				if (this.flags[iflags[i]].search(/^[0-9]+$/) == 0)
+					continue;
+				if (this.flags[iflags[i]].indexOf(':') !== -1)
+					return this.flags[iflags[i]].replace(/:.*$/,'');
+				return this.flags[iflags[i]];
+			}
+			if (this.name.indexOf('.') !== -1)
+				return this.name.replace(/ /, '_');
+		}
+	},
+	'binkp_port': {
+		get: function() {
+			if (this.flags.IBN === undefined)
+				return undefined;
+			if (this.flags.IBN !== true) {
+				// Address or port number included here...
+				if (this.flags.IBN.search(/^[0-9]+$/) == -1) {
+					if (this.flags.IBN.indexOf(':') === -1)
+						return 24554;
+					return parseInt(this.flags.IBN.replace(/^.*:([0-9]+)$/, '$1'));
+				}
+				return parseInt(this.flags.IBN, 10);
+			}
+			return 24554;
+		}
+	}
+});
+
+FIDO.ReadDomainMap();