var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name2 in all) __defProp(target, name2, { get: all[name2], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // node_modules/zmodem.js/src/zmlib.js var require_zmlib = __commonJS({ "node_modules/zmodem.js/src/zmlib.js"(exports2, module2) { "use strict"; var Zmodem2 = module2.exports; var ZDLE = 24; var XON = 17; var XOFF = 19; var XON_HIGH = 128 | XON; var XOFF_HIGH = 128 | XOFF; var CAN = 24; Zmodem2.ZMLIB = { /** * @property {number} The ZDLE constant, which ZMODEM uses for escaping */ ZDLE, /** * @property {number} XON - ASCII XON */ XON, /** * @property {number} XOFF - ASCII XOFF */ XOFF, /** * @property {number[]} ABORT_SEQUENCE - ZMODEM’s abort sequence */ ABORT_SEQUENCE: [CAN, CAN, CAN, CAN, CAN], /** * Remove octet values from the given array that ZMODEM always ignores. * This will mutate the given array. * * @param {number[]} octets - The octet values to transform. * Each array member should be an 8-bit unsigned integer (0-255). * This object is mutated in the function. * * @returns {number[]} The passed-in array. This is the same object that is * passed in. */ strip_ignored_bytes: function strip_ignored_bytes(octets) { for (var o = octets.length - 1; o >= 0; o--) { switch (octets[o]) { case XON: case XON_HIGH: case XOFF: case XOFF_HIGH: octets.splice(o, 1); continue; } } return octets; }, /** * Like Array.prototype.indexOf, but searches for a subarray * rather than just a particular value. * * @param {Array} haystack - The array to search, i.e., the bigger. * * @param {Array} needle - The array whose values to find, * i.e., the smaller. * * @returns {number} The position in “haystack” where “needle” * first appears—or, -1 if “needle” doesn’t appear anywhere * in “haystack”. */ find_subarray: function find_subarray(haystack, needle) { var h = 0, n; var start = Date.now(); HAYSTACK: while (h !== -1) { h = haystack.indexOf(needle[0], h); if (h === -1) break HAYSTACK; for (n = 1; n < needle.length; n++) { if (haystack[h + n] !== needle[n]) { h++; continue HAYSTACK; } } return h; } return -1; } }; } }); // node_modules/zmodem.js/src/encode.js var require_encode = __commonJS({ "node_modules/zmodem.js/src/encode.js"(exports2, module2) { "use strict"; var Zmodem2 = module2.exports; var HEX_DIGITS = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102]; var HEX_OCTET_VALUE = {}; for (hd = 0; hd < HEX_DIGITS.length; hd++) { HEX_OCTET_VALUE[HEX_DIGITS[hd]] = hd; } var hd; Zmodem2.ENCODELIB = { /** * Return an array with the given number as 2 big-endian bytes. * * @param {number} number - The number to encode. * * @returns {number[]} The octet values. */ pack_u16_be: function pack_u16_be(number) { if (number > 65535) throw "Number cannot exceed 16 bits: " + number; return [number >> 8, number & 255]; }, /** * Return an array with the given number as 4 little-endian bytes. * * @param {number} number - The number to encode. * * @returns {number[]} The octet values. */ pack_u32_le: function pack_u32_le(number) { var high_bytes = number / 65536; return [ number & 255, (number & 65535) >> 8, high_bytes & 255, high_bytes >> 8 ]; }, /** * The inverse of pack_u16_be() - i.e., take in 2 octet values * and parse them as an unsigned, 2-byte big-endian number. * * @param {number[]} octets - The octet values (2 of them). * * @returns {number} The decoded number. */ unpack_u16_be: function unpack_u16_be(bytes_arr) { return (bytes_arr[0] << 8) + bytes_arr[1]; }, /** * The inverse of pack_u32_le() - i.e., take in a 4-byte sequence * and parse it as an unsigned, 4-byte little-endian number. * * @param {number[]} octets - The octet values (4 of them). * * @returns {number} The decoded number. */ unpack_u32_le: function unpack_u32_le(octets) { return octets[0] + (octets[1] << 8) + (octets[2] << 16) + octets[3] * 16777216; }, /** * Encode a series of octet values to be the octet values that * correspond to the ASCII hex characters for each octet. The * returned array is suitable for use as binary data. * * For example: * * Original Hex Returned * 254 fe 102, 101 * 12 0c 48, 99 * 129 81 56, 49 * * @param {number[]} octets - The original octet values. * * @returns {number[]} The octet values that correspond to an ASCII * representation of the given octets. */ octets_to_hex: function octets_to_hex(octets) { var hex = []; for (var o = 0; o < octets.length; o++) { hex.push( HEX_DIGITS[octets[o] >> 4], HEX_DIGITS[octets[o] & 15] ); } return hex; }, /** * The inverse of octets_to_hex(): takes an array * of hex octet pairs and returns their octet values. * * @param {number[]} hex_octets - The hex octet values. * * @returns {number[]} The parsed octet values. */ parse_hex_octets: function parse_hex_octets(hex_octets) { var octets = new Array(hex_octets.length / 2); for (var i = 0; i < octets.length; i++) { octets[i] = (HEX_OCTET_VALUE[hex_octets[2 * i]] << 4) + HEX_OCTET_VALUE[hex_octets[1 + 2 * i]]; } return octets; } }; } }); // node_modules/zmodem.js/src/text.js var require_text = __commonJS({ "node_modules/zmodem.js/src/text.js"(exports2, module2) { var _my_TextEncoder = class { encode(text) { text = unescape(encodeURIComponent(text)); var bytes = new Array(text.length); for (var b = 0; b < text.length; b++) { bytes[b] = text.charCodeAt(b); } return new Uint8Array(bytes); } }; var _my_TextDecoder = class { decode(bytes) { return decodeURIComponent(escape(String.fromCharCode.apply(String, bytes))); } }; var Zmodem2 = module2.exports; Zmodem2.Text = { Encoder: typeof TextEncoder !== "undefined" ? TextEncoder : _my_TextEncoder, Decoder: typeof TextDecoder !== "undefined" ? TextDecoder : _my_TextDecoder }; } }); // node_modules/zmodem.js/src/zdle.js var require_zdle = __commonJS({ "node_modules/zmodem.js/src/zdle.js"(exports2, module2) { "use strict"; var Zmodem2 = module2.exports; Object.assign( Zmodem2, require_zmlib() ); var encode_cur; var encode_todo; var ZDLE = Zmodem2.ZMLIB.ZDLE; Zmodem2.ZDLE = class ZmodemZDLE { /** * Create a ZDLE encoder. * * @param {object} [config] - The initial configuration. * @param {object} config.escape_ctrl_chars - Whether the ZDLE encoder * should escape control characters. */ constructor(config) { this._config = {}; if (config) { this.set_escape_ctrl_chars(!!config.escape_ctrl_chars); } } /** * Enable or disable control-character escaping. * You should probably enable this for sender sessions. * * @param {boolean} value - Whether to enable (true) or disable (false). */ set_escape_ctrl_chars(value) { if (typeof value !== "boolean") throw "need boolean!"; if (value !== this._config.escape_ctrl_chars) { this._config.escape_ctrl_chars = value; this._setup_zdle_table(); } } /** * Whether or not control-character escaping is enabled. * * @return {boolean} Whether the escaping is on (true) or off (false). */ escapes_ctrl_chars() { return !!this._config.escape_ctrl_chars; } //I don’t know of any Zmodem implementations that use ZESC8 //(“escape_8th_bit”)?? /* ZMODEM software escapes ZDLE, 020, 0220, 021, 0221, 023, and 0223. If preceded by 0100 or 0300 (@), 015 and 0215 are also escaped to protect the Telenet command escape CR-@-CR. */ /** * Encode an array of octet values and return it. * This will mutate the given array. * * @param {number[]} octets - The octet values to transform. * Each array member should be an 8-bit unsigned integer (0-255). * This object is mutated in the function. * * @returns {number[]} The passed-in array, transformed. This is the * same object that is passed in. */ encode(octets) { if (!this._zdle_table) throw "No ZDLE encode table configured!"; var zdle_table = this._zdle_table; var last_code = this._lastcode; var arrbuf = new ArrayBuffer(2 * octets.length); var arrbuf_uint8 = new Uint8Array(arrbuf); var escctl_yn = this._config.escape_ctrl_chars; var arrbuf_i = 0; for (encode_cur = 0; encode_cur < octets.length; encode_cur++) { encode_todo = zdle_table[octets[encode_cur]]; if (!encode_todo) { console.trace(); console.error("bad encode() call:", JSON.stringify(octets)); this._lastcode = last_code; throw "Invalid octet: " + octets[encode_cur]; } last_code = octets[encode_cur]; if (encode_todo === 1) { } else if (escctl_yn || encode_todo === 2 || (last_code & 127) === 64) { arrbuf_uint8[arrbuf_i] = ZDLE; arrbuf_i++; last_code ^= 64; } arrbuf_uint8[arrbuf_i] = last_code; arrbuf_i++; } this._lastcode = last_code; octets.splice(0); octets.push.apply(octets, new Uint8Array(arrbuf, 0, arrbuf_i)); return octets; } /** * Decode an array of octet values and return it. * This will mutate the given array. * * @param {number[]} octets - The octet values to transform. * Each array member should be an 8-bit unsigned integer (0-255). * This object is mutated in the function. * * @returns {number[]} The passed-in array. * This is the same object that is passed in. */ static decode(octets) { for (var o = octets.length - 1; o >= 0; o--) { if (octets[o] === ZDLE) { octets.splice(o, 2, octets[o + 1] - 64); } } return octets; } /** * Remove, ZDLE-decode, and return bytes from the passed-in array. * If the requested number of ZDLE-encoded bytes isn’t available, * then the passed-in array is unmodified (and the return is undefined). * * @param {number[]} octets - The octet values to transform. * Each array member should be an 8-bit unsigned integer (0-255). * This object is mutated in the function. * * @param {number} offset - The number of (undecoded) bytes to skip * at the beginning of the “octets” array. * * @param {number} count - The number of bytes (octet values) to return. * * @returns {number[]|undefined} An array with the requested number of * decoded octet values, or undefined if that number of decoded * octets isn’t available (given the passed-in offset). */ static splice(octets, offset, count) { var so_far = 0; if (!offset) offset = 0; for (var i = offset; i < octets.length && so_far < count; i++) { so_far++; if (octets[i] === ZDLE) i++; } if (so_far === count) { if (octets.length === i - 1) return; octets.splice(0, offset); return ZmodemZDLE.decode(octets.splice(0, i - offset)); } return; } _setup_zdle_table() { var zsendline_tab = new Array(256); for (var i = 0; i < zsendline_tab.length; i++) { if (i & 96) { zsendline_tab[i] = 1; } else { switch (i) { case ZDLE: //NB: no (ZDLE | 0x80) case Zmodem2.ZMLIB.XOFF: case Zmodem2.ZMLIB.XON: case Zmodem2.ZMLIB.XOFF | 128: case Zmodem2.ZMLIB.XON | 128: zsendline_tab[i] = 2; break; case 16: // 020 case 144: zsendline_tab[i] = this._config.turbo_escape ? 1 : 2; break; case 13: // 015 case 141: zsendline_tab[i] = this._config.escape_ctrl_chars ? 2 : !this._config.turbo_escape ? 3 : 1; break; default: zsendline_tab[i] = this._config.escape_ctrl_chars ? 2 : 1; } } } this._zdle_table = zsendline_tab; } }; } }); // node_modules/crc-32/crc32.js var require_crc32 = __commonJS({ "node_modules/crc-32/crc32.js"(exports2) { var CRC32; (function(factory) { if (typeof DO_NOT_EXPORT_CRC === "undefined") { if ("object" === typeof exports2) { factory(exports2); } else if ("function" === typeof define && define.amd) { define(function() { var module3 = {}; factory(module3); return module3; }); } else { factory(CRC32 = {}); } } else { factory(CRC32 = {}); } })(function(CRC322) { CRC322.version = "1.2.2"; function signed_crc_table() { var c = 0, table = new Array(256); for (var n = 0; n != 256; ++n) { c = n; c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1; c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1; c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1; c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1; c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1; c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1; c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1; c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1; table[n] = c; } return typeof Int32Array !== "undefined" ? new Int32Array(table) : table; } var T0 = signed_crc_table(); function slice_by_16_tables(T) { var c = 0, v = 0, n = 0, table = typeof Int32Array !== "undefined" ? new Int32Array(4096) : new Array(4096); for (n = 0; n != 256; ++n) table[n] = T[n]; for (n = 0; n != 256; ++n) { v = T[n]; for (c = 256 + n; c < 4096; c += 256) v = table[c] = v >>> 8 ^ T[v & 255]; } var out = []; for (n = 1; n != 16; ++n) out[n - 1] = typeof Int32Array !== "undefined" ? table.subarray(n * 256, n * 256 + 256) : table.slice(n * 256, n * 256 + 256); return out; } var TT = slice_by_16_tables(T0); var T1 = TT[0], T2 = TT[1], T3 = TT[2], T4 = TT[3], T5 = TT[4]; var T6 = TT[5], T7 = TT[6], T8 = TT[7], T9 = TT[8], Ta = TT[9]; var Tb = TT[10], Tc = TT[11], Td = TT[12], Te = TT[13], Tf = TT[14]; function crc32_bstr(bstr, seed) { var C = seed ^ -1; for (var i = 0, L = bstr.length; i < L; ) C = C >>> 8 ^ T0[(C ^ bstr.charCodeAt(i++)) & 255]; return ~C; } function crc32_buf(B, seed) { var C = seed ^ -1, L = B.length - 15, i = 0; for (; i < L; ) C = Tf[B[i++] ^ C & 255] ^ Te[B[i++] ^ C >> 8 & 255] ^ Td[B[i++] ^ C >> 16 & 255] ^ Tc[B[i++] ^ C >>> 24] ^ Tb[B[i++]] ^ Ta[B[i++]] ^ T9[B[i++]] ^ T8[B[i++]] ^ T7[B[i++]] ^ T6[B[i++]] ^ T5[B[i++]] ^ T4[B[i++]] ^ T3[B[i++]] ^ T2[B[i++]] ^ T1[B[i++]] ^ T0[B[i++]]; L += 15; while (i < L) C = C >>> 8 ^ T0[(C ^ B[i++]) & 255]; return ~C; } function crc32_str(str, seed) { var C = seed ^ -1; for (var i = 0, L = str.length, c = 0, d = 0; i < L; ) { c = str.charCodeAt(i++); if (c < 128) { C = C >>> 8 ^ T0[(C ^ c) & 255]; } else if (c < 2048) { C = C >>> 8 ^ T0[(C ^ (192 | c >> 6 & 31)) & 255]; C = C >>> 8 ^ T0[(C ^ (128 | c & 63)) & 255]; } else if (c >= 55296 && c < 57344) { c = (c & 1023) + 64; d = str.charCodeAt(i++) & 1023; C = C >>> 8 ^ T0[(C ^ (240 | c >> 8 & 7)) & 255]; C = C >>> 8 ^ T0[(C ^ (128 | c >> 2 & 63)) & 255]; C = C >>> 8 ^ T0[(C ^ (128 | d >> 6 & 15 | (c & 3) << 4)) & 255]; C = C >>> 8 ^ T0[(C ^ (128 | d & 63)) & 255]; } else { C = C >>> 8 ^ T0[(C ^ (224 | c >> 12 & 15)) & 255]; C = C >>> 8 ^ T0[(C ^ (128 | c >> 6 & 63)) & 255]; C = C >>> 8 ^ T0[(C ^ (128 | c & 63)) & 255]; } } return ~C; } CRC322.table = T0; CRC322.bstr = crc32_bstr; CRC322.buf = crc32_buf; CRC322.str = crc32_str; }); } }); // node_modules/zmodem.js/src/zerror.js var require_zerror = __commonJS({ "node_modules/zmodem.js/src/zerror.js"(exports2, module2) { "use strict"; var Zmodem2 = module2.exports; function _crc_message(got, expected) { this.got = got.slice(0); this.expected = expected.slice(0); return "CRC check failed! (got: " + got.join() + "; expected: " + expected.join() + ")"; } function _pass(val) { return val; } var TYPE_MESSAGE = { aborted: "Session aborted", peer_aborted: "Peer aborted session", already_aborted: "Session already aborted", crc: _crc_message, validation: _pass }; function _generate_message(type) { const msg = TYPE_MESSAGE[type]; switch (typeof msg) { case "string": return msg; case "function": var args_after_type = [].slice.call(arguments).slice(1); return msg.apply(this, args_after_type); } return null; } Zmodem2.Error = class ZmodemError extends Error { constructor(msg_or_type) { super(); var generated = _generate_message.apply(this, arguments); if (generated) { this.type = msg_or_type; this.message = generated; } else { this.message = msg_or_type; } } }; } }); // node_modules/zmodem.js/src/zcrc.js var require_zcrc = __commonJS({ "node_modules/zmodem.js/src/zcrc.js"(exports2, module2) { "use strict"; var CRC32_MOD = require_crc32(); var Zmodem2 = module2.exports; Object.assign( Zmodem2, require_zerror(), require_encode() ); var _crctab; var crc_width = 16; var crc_polynomial = 4129; var crc_castmask = 65535; var crc_msbmask = 1 << crc_width - 1; function _compute_crctab() { _crctab = new Array(256); var divident_shift = crc_width - 8; for (var divident = 0; divident < 256; divident++) { var currByte = divident << divident_shift & crc_castmask; for (var bit = 0; bit < 8; bit++) { if ((currByte & crc_msbmask) !== 0) { currByte <<= 1; currByte ^= crc_polynomial; } else { currByte <<= 1; } } _crctab[divident] = currByte & crc_castmask; } } function _updcrc(cp, crc) { if (!_crctab) _compute_crctab(); return _crctab[crc >> 8 & 255] ^ (255 & crc) << 8 ^ cp; } function __verify(expect, got) { var err; if (expect.join() !== got.join()) { throw new Zmodem2.Error("crc", got, expect); } } Zmodem2.CRC = { //https://www.lammertbies.nl/comm/info/crc-calculation.html //CRC-CCITT (XModem) /** * Deduce a given set of octet values’ CRC16, as per the CRC16 * variant that ZMODEM uses (CRC-CCITT/XModem). * * @param {Array} octets - The array of octet values. * Each array member should be an 8-bit unsigned integer (0-255). * * @returns {Array} crc - The CRC, expressed as an array of octet values. */ crc16: function crc16(octet_nums) { var crc = octet_nums[0]; for (var b = 1; b < octet_nums.length; b++) { crc = _updcrc(octet_nums[b], crc); } crc = _updcrc(0, _updcrc(0, crc)); return Zmodem2.ENCODELIB.pack_u16_be(crc); }, /** * Deduce a given set of octet values’ CRC32. * * @param {Array} octets - The array of octet values. * Each array member should be an 8-bit unsigned integer (0-255). * * @returns {Array} crc - The CRC, expressed as an array of octet values. */ crc32: function crc32(octet_nums) { return Zmodem2.ENCODELIB.pack_u32_le( CRC32_MOD.buf(octet_nums) >>> 0 //bit-shift to get unsigned ); }, /** * Verify a given set of octet values’ CRC16. * An exception is thrown on failure. * * @param {Array} bytes_arr - The array of octet values. * Each array member should be an 8-bit unsigned integer (0-255). * * @param {Array} crc - The CRC to check against, expressed as * an array of octet values. */ verify16: function verify16(bytes_arr, got) { return __verify(this.crc16(bytes_arr), got); }, /** * Verify a given set of octet values’ CRC32. * An exception is thrown on failure. * * @param {Array} bytes_arr - The array of octet values. * Each array member should be an 8-bit unsigned integer (0-255). * * @param {Array} crc - The CRC to check against, expressed as * an array of octet values. */ verify32: function verify32(bytes_arr, crc) { try { __verify(this.crc32(bytes_arr), crc); } catch (err) { err.input = bytes_arr.slice(0); throw err; } } }; } }); // node_modules/zmodem.js/src/zheader.js var require_zheader = __commonJS({ "node_modules/zmodem.js/src/zheader.js"(exports2, module2) { "use strict"; var Zmodem2 = module2.exports; Object.assign( Zmodem2, require_encode(), require_zdle(), require_zmlib(), require_zcrc(), require_zerror() ); var ZPAD = "*".charCodeAt(0); var ZBIN = "A".charCodeAt(0); var ZHEX = "B".charCodeAt(0); var ZBIN32 = "C".charCodeAt(0); var HEX_HEADER_CRLF = [13, 10]; var HEX_HEADER_CRLF_XON = HEX_HEADER_CRLF.slice(0).concat([Zmodem2.ZMLIB.XON]); var HEX_HEADER_PREFIX = [ZPAD, ZPAD, Zmodem2.ZMLIB.ZDLE, ZHEX]; var BINARY16_HEADER_PREFIX = [ZPAD, Zmodem2.ZMLIB.ZDLE, ZBIN]; var BINARY32_HEADER_PREFIX = [ZPAD, Zmodem2.ZMLIB.ZDLE, ZBIN32]; Zmodem2.Header = class ZmodemHeader { //lrzsz’s “sz” command sends a random (?) CR/0x0d byte //after ZEOF. Let’s accommodate 0x0a, 0x0d, 0x8a, and 0x8d. // //Also, when you skip a file, sz outputs a message about it. // //It appears that we’re supposed to ignore anything until //[ ZPAD, ZDLE ] when we’re looking for a header. /** * Weed out the leading bytes that aren’t valid to start a ZMODEM header. * * @param {number[]} ibuffer - The octet values to parse. * Each array member should be an 8-bit unsigned integer (0-255). * This object is mutated in the function. * * @returns {number[]} The octet values that were removed from the start * of “ibuffer”. Order is preserved. */ static trim_leading_garbage(ibuffer) { var garbage = []; var discard_all, parser, next_ZPAD_at_least = 0; TRIM_LOOP: while (ibuffer.length && !parser) { var first_ZPAD = ibuffer.indexOf(ZPAD); if (first_ZPAD === -1) { discard_all = true; break TRIM_LOOP; } else { garbage.push.apply(garbage, ibuffer.splice(0, first_ZPAD)); if (ibuffer.length < 2) { break TRIM_LOOP; } else if (ibuffer[1] === ZPAD) { if (ibuffer.length < HEX_HEADER_PREFIX.length) { if (ibuffer.join() === HEX_HEADER_PREFIX.slice(0, ibuffer.length).join()) { break TRIM_LOOP; } } else if (ibuffer[2] === HEX_HEADER_PREFIX[2] && ibuffer[3] === HEX_HEADER_PREFIX[3]) { parser = _parse_hex; } } else if (ibuffer[1] === Zmodem2.ZMLIB.ZDLE) { if (ibuffer.length < BINARY16_HEADER_PREFIX.length) { break TRIM_LOOP; } if (ibuffer[2] === BINARY16_HEADER_PREFIX[2]) { parser = _parse_binary16; } else if (ibuffer[2] === BINARY32_HEADER_PREFIX[2]) { parser = _parse_binary32; } } if (!parser) { garbage.push(ibuffer.shift()); } } } if (discard_all) { garbage.push.apply(garbage, ibuffer.splice(0)); } return garbage; } /** * Parse out a Header object from a given array of octet values. * * An exception is thrown if the given bytes are definitively invalid * as header values. * * @param {number[]} octets - The octet values to parse. * Each array member should be an 8-bit unsigned integer (0-255). * This object is mutated in the function. * * @returns {Header|undefined} An instance of the appropriate Header * subclass, or undefined if not enough octet values are given * to determine whether there is a valid header here or not. */ static parse(octets) { var hdr; if (octets[1] === ZPAD) { hdr = _parse_hex(octets); return hdr && [hdr, 16]; } else if (octets[2] === ZBIN) { hdr = _parse_binary16(octets, 3); return hdr && [hdr, 16]; } else if (octets[2] === ZBIN32) { hdr = _parse_binary32(octets); return hdr && [hdr, 32]; } if (octets.length < 3) return; throw "Unrecognized/unsupported octets: " + octets.join(); } /** * Build a Header subclass given a name and arguments. * * @param {string} name - The header type name, e.g., “ZRINIT”. * * @param {...*} args - The arguments to pass to the appropriate * subclass constructor. These aren’t documented currently * but are pretty easy to glean from the code. * * @returns {Header} An instance of the appropriate Header subclass. */ static build(name2) { var args = arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments); var Ctr = FRAME_NAME_CREATOR[name2]; if (!Ctr) throw "No frame class \u201C" + name2 + "\u201D is defined!"; args.shift(); var hdr = new (Ctr.bind.apply(Ctr, [null].concat(args)))(); return hdr; } /** * Return the octet values array that represents the object * in ZMODEM hex encoding. * * @returns {number[]} An array of octet values suitable for sending * as binary data. */ to_hex() { var to_crc = this._crc_bytes(); return HEX_HEADER_PREFIX.concat( Zmodem2.ENCODELIB.octets_to_hex(to_crc.concat(Zmodem2.CRC.crc16(to_crc))), this._hex_header_ending ); } /** * Return the octet values array that represents the object * in ZMODEM binary encoding with a 16-bit CRC. * * @param {ZDLE} zencoder - A ZDLE instance to use for * ZDLE encoding. * * @returns {number[]} An array of octet values suitable for sending * as binary data. */ to_binary16(zencoder) { return this._to_binary(zencoder, BINARY16_HEADER_PREFIX, Zmodem2.CRC.crc16); } /** * Return the octet values array that represents the object * in ZMODEM binary encoding with a 32-bit CRC. * * @param {ZDLE} zencoder - A ZDLE instance to use for * ZDLE encoding. * * @returns {number[]} An array of octet values suitable for sending * as binary data. */ to_binary32(zencoder) { return this._to_binary(zencoder, BINARY32_HEADER_PREFIX, Zmodem2.CRC.crc32); } //This is never called directly, but only as super(). constructor() { if (!this._bytes4) { this._bytes4 = [0, 0, 0, 0]; } } _to_binary(zencoder, prefix, crc_func) { var to_crc = this._crc_bytes(); var octets = prefix.concat( zencoder.encode(to_crc.concat(crc_func(to_crc))) ); return octets; } _crc_bytes() { return [this.TYPENUM].concat(this._bytes4); } }; Zmodem2.Header.prototype._hex_header_ending = HEX_HEADER_CRLF_XON; var ZRQINIT_HEADER = class extends Zmodem2.Header { }; var ZRINIT_FLAG = { //---------------------------------------------------------------------- // Bit Masks for ZRINIT flags byte ZF0 //---------------------------------------------------------------------- CANFDX: 1, // Rx can send and receive true FDX CANOVIO: 2, // Rx can receive data during disk I/O CANBRK: 4, // Rx can send a break signal CANCRY: 8, // Receiver can decrypt -- nothing does this CANLZW: 16, // Receiver can uncompress -- nothing does this CANFC32: 32, // Receiver can use 32 bit Frame Check ESCCTL: 64, // Receiver expects ctl chars to be escaped ESC8: 128 // Receiver expects 8th bit to be escaped }; function _get_ZRINIT_flag_num(fl) { if (!ZRINIT_FLAG[fl]) { throw new Zmodem2.Error("Invalid ZRINIT flag: " + fl); } return ZRINIT_FLAG[fl]; } var ZRINIT_HEADER = class extends Zmodem2.Header { constructor(flags_arr, bufsize) { super(); var flags_num = 0; if (!bufsize) bufsize = 0; flags_arr.forEach(function(fl) { flags_num |= _get_ZRINIT_flag_num(fl); }); this._bytes4 = [ bufsize & 255, bufsize >> 8, 0, flags_num ]; } //undefined if nonstop I/O is allowed get_buffer_size() { return Zmodem2.ENCODELIB.unpack_u16_be(this._bytes4.slice(0, 2)) || void 0; } //Unimplemented: // can_decrypt // can_decompress //---------------------------------------------------------------------- //function names taken from Jacques Mattheij’s implementation, //as used in syncterm. can_full_duplex() { return !!(this._bytes4[3] & ZRINIT_FLAG.CANFDX); } can_overlap_io() { return !!(this._bytes4[3] & ZRINIT_FLAG.CANOVIO); } can_break() { return !!(this._bytes4[3] & ZRINIT_FLAG.CANBRK); } can_fcs_32() { return !!(this._bytes4[3] & ZRINIT_FLAG.CANFC32); } escape_ctrl_chars() { return !!(this._bytes4[3] & ZRINIT_FLAG.ESCCTL); } //Is this used? I don’t see it used in lrzsz or syncterm //Looks like it was a “foreseen” feature that Forsberg //never implemented. (The need for it went away, maybe?) escape_8th_bit() { return !!(this._bytes4[3] & ZRINIT_FLAG.ESC8); } }; var ZSINIT_FLAG = { ESCCTL: 64, // Transmitter will escape ctl chars ESC8: 128 // Transmitter will escape 8th bit }; function _get_ZSINIT_flag_num(fl) { if (!ZSINIT_FLAG[fl]) { throw "Invalid ZSINIT flag: " + fl; } return ZSINIT_FLAG[fl]; } var ZSINIT_HEADER = class extends Zmodem2.Header { constructor(flags_arr, attn_seq_arr) { super(); var flags_num = 0; flags_arr.forEach(function(fl) { flags_num |= _get_ZSINIT_flag_num(fl); }); this._bytes4 = [0, 0, 0, flags_num]; if (attn_seq_arr) { if (attn_seq_arr.length > 31) { throw "Attn sequence must be <= 31 bytes"; } if (attn_seq_arr.some(function(num) { return num > 255; })) { throw "Attn sequence (" + attn_seq_arr + ") must be <256"; } this._data = attn_seq_arr.concat([0]); } } escape_ctrl_chars() { return !!(this._bytes4[3] & ZSINIT_FLAG.ESCCTL); } //Is this used? I don’t see it used in lrzsz or syncterm escape_8th_bit() { return !!(this._bytes4[3] & ZSINIT_FLAG.ESC8); } }; var ZACK_HEADER = class extends Zmodem2.Header { constructor(payload4) { super(); if (payload4) { this._bytes4 = payload4.slice(); } } }; ZACK_HEADER.prototype._hex_header_ending = HEX_HEADER_CRLF; var ZFILE_VALUES = { //ZF3 (i.e., first byte) extended: { sparse: 64 //ZXSPARS }, //ZF2 transport: [ void 0, "compress", //ZTLZW "encrypt", //ZTCRYPT "rle" //ZTRLE ], //ZF1 management: [ void 0, "newer_or_longer", //ZF1_ZMNEWL "crc", //ZF1_ZMCRC "append", //ZF1_ZMAPND "clobber", //ZF1_ZMCLOB "newer", //ZF1_ZMNEW "mtime_or_length", //ZF1_ZMNEW "protect", //ZF1_ZMPROT "rename" //ZF1_ZMPROT ], //ZF0 (i.e., last byte) conversion: [ void 0, "binary", //ZCBIN "text", //ZCNL "resume" //ZCRESUM ] }; var ZFILE_ORDER = ["extended", "transport", "management", "conversion"]; var ZMSKNOLOC = 128; var MANAGEMENT_MASK = 31; var ZXSPARS = 64; var ZFILE_HEADER = class extends Zmodem2.Header { //TODO: allow options on instantiation get_options() { var opts = { sparse: !!(this._bytes4[0] & ZXSPARS) }; var bytes_copy = this._bytes4.slice(0); ZFILE_ORDER.forEach(function(key, i) { if (ZFILE_VALUES[key] instanceof Array) { if (key === "management") { opts.skip_if_absent = !!(bytes_copy[i] & ZMSKNOLOC); bytes_copy[i] &= MANAGEMENT_MASK; } opts[key] = ZFILE_VALUES[key][bytes_copy[i]]; } else { for (var extkey in ZFILE_VALUES[key]) { opts[extkey] = !!(bytes_copy[i] & ZFILE_VALUES[key][extkey]); if (opts[extkey]) { bytes_copy[i] ^= ZFILE_VALUES[key][extkey]; } } } if (!opts[key] && bytes_copy[i]) { opts[key] = "unknown:" + bytes_copy[i]; } }); return opts; } }; var ZSKIP_HEADER = class extends Zmodem2.Header { }; var ZABORT_HEADER = class extends Zmodem2.Header { }; var ZFIN_HEADER = class extends Zmodem2.Header { }; var ZFERR_HEADER = class extends Zmodem2.Header { }; ZFIN_HEADER.prototype._hex_header_ending = HEX_HEADER_CRLF; var ZOffsetHeader = class extends Zmodem2.Header { constructor(offset) { super(); this._bytes4 = Zmodem2.ENCODELIB.pack_u32_le(offset); } get_offset() { return Zmodem2.ENCODELIB.unpack_u32_le(this._bytes4); } }; var ZRPOS_HEADER = class extends ZOffsetHeader { }; var ZDATA_HEADER = class extends ZOffsetHeader { }; var ZEOF_HEADER = class extends ZOffsetHeader { }; var FRAME_CLASS_TYPES = [ [ZRQINIT_HEADER, "ZRQINIT"], [ZRINIT_HEADER, "ZRINIT"], [ZSINIT_HEADER, "ZSINIT"], [ZACK_HEADER, "ZACK"], [ZFILE_HEADER, "ZFILE"], [ZSKIP_HEADER, "ZSKIP"], void 0, // [ ZNAK_HEADER, "ZNAK" ], [ZABORT_HEADER, "ZABORT"], [ZFIN_HEADER, "ZFIN"], [ZRPOS_HEADER, "ZRPOS"], [ZDATA_HEADER, "ZDATA"], [ZEOF_HEADER, "ZEOF"], [ZFERR_HEADER, "ZFERR"], //see note void 0, //[ ZCRC_HEADER, "ZCRC" ], void 0, //[ ZCHALLENGE_HEADER, "ZCHALLENGE" ], void 0, //[ ZCOMPL_HEADER, "ZCOMPL" ], void 0, //[ ZCAN_HEADER, "ZCAN" ], void 0, //[ ZFREECNT_HEADER, "ZFREECNT" ], void 0, //[ ZCOMMAND_HEADER, "ZCOMMAND" ], void 0 //[ ZSTDERR_HEADER, "ZSTDERR" ], ]; var FRAME_NAME_CREATOR = {}; for (fc = 0; fc < FRAME_CLASS_TYPES.length; fc++) { if (!FRAME_CLASS_TYPES[fc]) continue; FRAME_NAME_CREATOR[FRAME_CLASS_TYPES[fc][1]] = FRAME_CLASS_TYPES[fc][0]; Object.assign( FRAME_CLASS_TYPES[fc][0].prototype, { TYPENUM: fc, NAME: FRAME_CLASS_TYPES[fc][1] } ); } var fc; var CREATORS = [ ZRQINIT_HEADER, ZRINIT_HEADER, ZSINIT_HEADER, ZACK_HEADER, ZFILE_HEADER, ZSKIP_HEADER, "ZNAK", ZABORT_HEADER, ZFIN_HEADER, ZRPOS_HEADER, ZDATA_HEADER, ZEOF_HEADER, ZFERR_HEADER, "ZCRC", //ZCRC_HEADER, -- leaving unimplemented? "ZCHALLENGE", "ZCOMPL", "ZCAN", "ZFREECNT", // ZFREECNT_HEADER, "ZCOMMAND", "ZSTDERR" ]; function _get_blank_header(typenum) { var creator = CREATORS[typenum]; if (typeof creator === "string") { throw "Received unsupported header: " + creator; } return _get_blank_header_from_constructor(creator); } function _get_blank_header_from_constructor(creator) { if (creator.prototype instanceof ZOffsetHeader) { return new creator(0); } return new creator([]); } function _parse_binary16(bytes_arr) { var zdle_decoded = Zmodem2.ZDLE.splice(bytes_arr, BINARY16_HEADER_PREFIX.length, 7); return zdle_decoded && _parse_non_zdle_binary16(zdle_decoded); } function _parse_non_zdle_binary16(decoded) { Zmodem2.CRC.verify16( decoded.slice(0, 5), decoded.slice(5) ); var typenum = decoded[0]; var hdr = _get_blank_header(typenum); hdr._bytes4 = decoded.slice(1, 5); return hdr; } function _parse_binary32(bytes_arr) { var zdle_decoded = Zmodem2.ZDLE.splice( bytes_arr, //omit the leading "*", ZDLE, and "C" BINARY32_HEADER_PREFIX.length, 9 ); if (!zdle_decoded) return; Zmodem2.CRC.verify32( zdle_decoded.slice(0, 5), zdle_decoded.slice(5) ); var typenum = zdle_decoded[0]; var hdr = _get_blank_header(typenum); hdr._bytes4 = zdle_decoded.slice(1, 5); return hdr; } function _parse_hex(bytes_arr) { var lf_pos = bytes_arr.indexOf(138); if (-1 === lf_pos) { lf_pos = bytes_arr.indexOf(10); } var hdr_err, hex_bytes; if (-1 === lf_pos) { if (bytes_arr.length > 11) { hdr_err = "Invalid hex header - no LF detected within 12 bytes!"; } return; } else { hex_bytes = bytes_arr.splice(0, lf_pos); bytes_arr.shift(); if (hex_bytes.length === 19) { var preceding = hex_bytes.pop(); if (preceding !== 13 && preceding !== 141) { hdr_err = "Invalid hex header: (CR/)LF doesn\u2019t have CR!"; } } else if (hex_bytes.length !== 18) { hdr_err = "Invalid hex header: invalid number of bytes before LF!"; } } if (hdr_err) { hdr_err += " (" + hex_bytes.length + " bytes: " + hex_bytes.join() + ")"; throw hdr_err; } hex_bytes.splice(0, 4); var octets = Zmodem2.ENCODELIB.parse_hex_octets(hex_bytes); return _parse_non_zdle_binary16(octets); } Zmodem2.Header.parse_hex = _parse_hex; } }); // node_modules/zmodem.js/src/zsubpacket.js var require_zsubpacket = __commonJS({ "node_modules/zmodem.js/src/zsubpacket.js"(exports2, module2) { "use strict"; var Zmodem2 = module2.exports; Object.assign( Zmodem2, require_zcrc(), require_zdle(), require_zmlib(), require_zerror() ); var ZCRCE = 104; var ZCRCG = 105; var ZCRCQ = 106; var ZCRCW = 107; var SUBPACKET_BUILDER; Zmodem2.Subpacket = class ZmodemSubpacket { /** * Build a Subpacket subclass given a payload and frame end string. * * @param {Array} octets - The octet values to parse. * Each array member should be an 8-bit unsigned integer (0-255). * * @param {string} frameend - One of: * - `no_end_no_ack` * - `end_no_ack` * - `no_end_ack` (unused currently) * - `end_ack` * * @returns {Subpacket} An instance of the appropriate Subpacket subclass. */ static build(octets, frameend) { var Ctr = SUBPACKET_BUILDER[frameend]; if (!Ctr) { throw "No subpacket type \u201C" + frameend + "\u201D is defined! Try one of: " + Object.keys(SUBPACKET_BUILDER).join(", "); } return new Ctr(octets); } /** * Return the octet values array that represents the object * encoded with a 16-bit CRC. * * @param {ZDLE} zencoder - A ZDLE instance to use for ZDLE encoding. * * @returns {number[]} An array of octet values suitable for sending * as binary data. */ encode16(zencoder) { return this._encode(zencoder, Zmodem2.CRC.crc16); } /** * Return the octet values array that represents the object * encoded with a 32-bit CRC. * * @param {ZDLE} zencoder - A ZDLE instance to use for ZDLE encoding. * * @returns {number[]} An array of octet values suitable for sending * as binary data. */ encode32(zencoder) { return this._encode(zencoder, Zmodem2.CRC.crc32); } /** * Return the subpacket payload’s octet values. * * NOTE: For speed, this returns the actual data in the subpacket; * if you mutate this return value, you alter the Subpacket object * internals. This is OK if you won’t need the Subpacket anymore, but * just be careful. * * @returns {number[]} The subpacket’s payload, represented as an * array of octet values. **DO NOT ALTER THIS ARRAY** unless you * no longer need the Subpacket. */ get_payload() { return this._payload; } /** * Parse out a Subpacket object from a given array of octet values, * assuming a 16-bit CRC. * * An exception is thrown if the given bytes are definitively invalid * as subpacket values with 16-bit CRC. * * @param {number[]} octets - The octet values to parse. * Each array member should be an 8-bit unsigned integer (0-255). * This object is mutated in the function. * * @returns {Subpacket|undefined} An instance of the appropriate Subpacket * subclass, or undefined if not enough octet values are given * to determine whether there is a valid subpacket here or not. */ static parse16(octets) { return ZmodemSubpacket._parse(octets, 2); } //parse32 test: //[102, 105, 108, 101, 110, 97, 109, 101, 119, 105, 116, 104, 115, 112, 97, 99, 101, 115, 0, 49, 55, 49, 51, 49, 52, 50, 52, 51, 50, 49, 55, 50, 49, 48, 48, 54, 52, 52, 48, 49, 49, 55, 0, 43, 8, 63, 115, 23, 17] /** * Same as parse16(), but assuming a 32-bit CRC. * * @param {number[]} octets - The octet values to parse. * Each array member should be an 8-bit unsigned integer (0-255). * This object is mutated in the function. * * @returns {Subpacket|undefined} An instance of the appropriate Subpacket * subclass, or undefined if not enough octet values are given * to determine whether there is a valid subpacket here or not. */ static parse32(octets) { return ZmodemSubpacket._parse(octets, 4); } /** * Not used directly. */ constructor(payload) { this._payload = payload; } _encode(zencoder, crc_func) { return zencoder.encode(this._payload.slice(0)).concat( [Zmodem2.ZMLIB.ZDLE, this._frameend_num], zencoder.encode(crc_func(this._payload.concat(this._frameend_num))) ); } //Because of ZDLE encoding, we’ll never see any of the frame-end octets //in a stream except as the ends of data payloads. static _parse(bytes_arr, crc_len) { var end_at; var creator; var _frame_ends_lookup = { 104: ZEndNoAckSubpacket, 105: ZNoEndNoAckSubpacket, 106: ZNoEndAckSubpacket, 107: ZEndAckSubpacket }; var zdle_at = 0; while (zdle_at < bytes_arr.length) { zdle_at = bytes_arr.indexOf(Zmodem2.ZMLIB.ZDLE, zdle_at); if (zdle_at === -1) return; var after_zdle = bytes_arr[zdle_at + 1]; creator = _frame_ends_lookup[after_zdle]; if (creator) { end_at = zdle_at + 1; break; } zdle_at++; } if (!creator) return; var frameend_num = bytes_arr[end_at]; if (bytes_arr[end_at - 1] !== Zmodem2.ZMLIB.ZDLE) { throw "Byte before frame end should be ZDLE, not " + bytes_arr[end_at - 1]; } var zdle_encoded_payload = bytes_arr.splice(0, end_at - 1); var got_crc = Zmodem2.ZDLE.splice(bytes_arr, 2, crc_len); if (!got_crc) { bytes_arr.unshift.apply(bytes_arr, zdle_encoded_payload); return; } var payload = Zmodem2.ZDLE.decode(zdle_encoded_payload); Zmodem2.CRC[crc_len === 2 ? "verify16" : "verify32"]( payload.concat([frameend_num]), got_crc ); return new creator(payload, got_crc); } }; var ZEndSubpacketBase = class extends Zmodem2.Subpacket { frame_end() { return true; } }; var ZNoEndSubpacketBase = class extends Zmodem2.Subpacket { frame_end() { return false; } }; var ZEndNoAckSubpacket = class extends ZEndSubpacketBase { ack_expected() { return false; } }; ZEndNoAckSubpacket.prototype._frameend_num = ZCRCE; var ZEndAckSubpacket = class extends ZEndSubpacketBase { ack_expected() { return true; } }; ZEndAckSubpacket.prototype._frameend_num = ZCRCW; var ZNoEndNoAckSubpacket = class extends ZNoEndSubpacketBase { ack_expected() { return false; } }; ZNoEndNoAckSubpacket.prototype._frameend_num = ZCRCG; var ZNoEndAckSubpacket = class extends ZNoEndSubpacketBase { ack_expected() { return true; } }; ZNoEndAckSubpacket.prototype._frameend_num = ZCRCQ; SUBPACKET_BUILDER = { end_no_ack: ZEndNoAckSubpacket, end_ack: ZEndAckSubpacket, no_end_no_ack: ZNoEndNoAckSubpacket, no_end_ack: ZNoEndAckSubpacket }; } }); // node_modules/zmodem.js/src/zvalidation.js var require_zvalidation = __commonJS({ "node_modules/zmodem.js/src/zvalidation.js"(exports2, module2) { "use strict"; var Zmodem2 = module2.exports; Object.assign( Zmodem2, require_zerror() ); var LOOKS_LIKE_ZMODEM_HEADER = /\*\x18[AC]|\*\*\x18B/; function _validate_number(key, value) { if (value < 0) { throw new Zmodem2.Error("validation", "\u201C" + key + "\u201D (" + value + ") must be nonnegative."); } if (value !== Math.floor(value)) { throw new Zmodem2.Error("validation", "\u201C" + key + "\u201D (" + value + ") must be an integer."); } } Zmodem2.Validation = { /** * Validates and normalizes a set of parameters for an offer to send. * NOTE: This returns “mtime” as epoch seconds, not a Date. This is * inconsistent with the get_details() method in Session, but it’s * more useful for sending over the wire. * * @param {FileDetails} params - The file details. Some fairly trivial * variances from the specification are allowed. * * @return {FileDetails} The parameters that should be sent. `mtime` * will be a Date rather than a number. */ offer_parameters: function offer_parameters(params) { if (!params.name) { throw new Zmodem2.Error("validation", "Need \u201Cname\u201D!"); } if (typeof params.name !== "string") { throw new Zmodem2.Error("validation", "\u201Cname\u201D (" + params.name + ") must be a string!"); } params = Object.assign({}, params); if (LOOKS_LIKE_ZMODEM_HEADER.test(params.name)) { console.warn("The filename " + JSON.stringify(name) + " contains characters that look like a ZMODEM header. This could corrupt the ZMODEM session; consider renaming it so that the filename doesn\u2019t contain control characters."); } if (params.serial !== null && params.serial !== void 0) { throw new Zmodem2.Error("validation", "\u201Cserial\u201D is meaningless."); } params.serial = null; ["size", "mode", "files_remaining", "bytes_remaining"].forEach( function(k) { var ok; switch (typeof params[k]) { case "object": ok = params[k] === null; break; case "undefined": params[k] = null; ok = true; break; case "number": _validate_number(k, params[k]); ok = true; break; } if (!ok) { throw new Zmodem2.Error("validation", "\u201C" + k + "\u201D (" + params[k] + ") must be null, undefined, or a number."); } } ); if (typeof params.mode === "number") { params.mode |= 32768; } if (params.files_remaining === 0) { throw new Zmodem2.Error("validation", "\u201Cfiles_remaining\u201D, if given, must be positive."); } var mtime_ok; switch (typeof params.mtime) { case "object": mtime_ok = true; if (params.mtime instanceof Date) { var date_obj = params.mtime; params.mtime = Math.floor(date_obj.getTime() / 1e3); if (params.mtime < 0) { throw new Zmodem2.Error("validation", "\u201Cmtime\u201D (" + date_obj + ") must not be earlier than 1970."); } } else if (params.mtime !== null) { mtime_ok = false; } break; case "undefined": params.mtime = null; mtime_ok = true; break; case "number": _validate_number("mtime", params.mtime); mtime_ok = true; break; } if (!mtime_ok) { throw new Zmodem2.Error("validation", "\u201Cmtime\u201D (" + params.mtime + ") must be null, undefined, a Date, or a number."); } return params; } }; } }); // node_modules/zmodem.js/src/zsession.js var require_zsession = __commonJS({ "node_modules/zmodem.js/src/zsession.js"(exports2, module2) { "use strict"; var Zmodem2 = module2.exports; Zmodem2.DEBUG = false; Object.assign( Zmodem2, require_encode(), require_text(), require_zdle(), require_zmlib(), require_zheader(), require_zsubpacket(), require_zvalidation(), require_zerror() ); var KEEPALIVE_INTERVAL = 5e3; var ZRINIT_FLAGS = [ "CANFDX", //full duplex "CANOVIO", //overlap I/O //lsz has a buffer overflow bug that shows itself when: // // - 16-bit CRC is used, and // - lsz receives the abort sequence while sending a file // //To avoid this, we just tell lsz to use 32-bit CRC //even though there is otherwise no reason. This ensures that //unfixed lsz versions will avoid the buffer overflow. "CANFC32" ]; var FORCE_ESCAPE_CTRL_CHARS = true; var DEFAULT_RECEIVE_INPUT_MODE = "spool_uint8array"; var MAX_CHUNK_LENGTH = 8192; var BS = 8; var OVER_AND_OUT = [79, 79]; var ABORT_SEQUENCE = Zmodem2.ZMLIB.ABORT_SEQUENCE; var _Eventer = class { /** * Not called directly. */ constructor() { this._on_evt = {}; this._evt_once_index = {}; } _Add_event(evt_name) { this._on_evt[evt_name] = []; this._evt_once_index[evt_name] = []; } _get_evt_queue(evt_name) { if (!this._on_evt[evt_name]) { throw "Bad event: " + evt_name; } return this._on_evt[evt_name]; } /** * Register a callback for a given event. * * @param {string} evt_name - The name of the event. * * @param {Function} todo - The function to execute when the event happens. */ on(evt_name, todo) { var queue = this._get_evt_queue(evt_name); queue.push(todo); return this; } /** * Unregister a callback for a given event. * * @param {string} evt_name - The name of the event. * * @param {Function} [todo] - The function to execute when the event * happens. If not given, the last event registered for the event * is unregistered. */ off(evt_name, todo) { var queue = this._get_evt_queue(evt_name); if (todo) { var at = queue.indexOf(todo); if (at === -1) { throw "\u201C" + todo + "\u201D is not in the \u201C" + evt_name + "\u201D queue."; } queue.splice(at, 1); } else { queue.pop(); } return this; } _Happen(evt_name) { var queue = this._get_evt_queue(evt_name); var args = Array.apply(null, arguments); args.shift(); var sess = this; queue.forEach(function(cb) { cb.apply(sess, args); }); return queue.length; } }; Zmodem2.Session = class ZmodemSession extends _Eventer { /** * Parse out a hex header from the given array. * If there’s a ZRQINIT or ZRINIT at the beginning, * we’ll return it. If the input isn’t a header, * for whatever reason, we return undefined. * * @param {number[]} octets - The bytes to parse. * * @return {Session|undefined} A Session object if the beginning * of a session was parsable in “octets”; otherwise undefined. */ static parse(octets) { var hdr; try { hdr = Zmodem2.Header.parse_hex(octets); } catch (e) { return; } if (!hdr) return; switch (hdr.NAME) { case "ZRQINIT": return new Zmodem2.Session.Receive(); case "ZRINIT": return new Zmodem2.Session.Send(hdr); } } /** * Sets the sender function that a Session object will use. * * @param {Function} sender_func - The function to call. * It will receive an Array with the relevant octets. * * @return {Session} The session object (for chaining). */ set_sender(sender_func) { this._sender = sender_func; return this; } /** * Whether the current Session has ended. * * @returns {boolean} The ended state. */ has_ended() { return this._has_ended(); } /** * Consumes an array of octets as ZMODEM session input. * * @param {number[]} octets - The input octets. */ consume(octets) { this._before_consume(octets); if (this._aborted) throw new Zmodem2.Error("already_aborted"); if (!octets.length) return; this._strip_and_enqueue_input(octets); if (!this._check_for_abort_sequence(octets)) { this._consume_first(); } return; } /** * Whether the current Session has been `abort()`ed. * * @returns {boolean} The aborted state. */ aborted() { return !!this._aborted; } /** * Not called directly. */ constructor() { super(); this._config = {}; this._input_buffer = []; this._Add_event("receive"); this._Add_event("garbage"); this._Add_event("session_end"); } /** * Returns the Session object’s role. * * @returns {string} One of: * - `receive` * - `send` */ get_role() { return this.type; } _trim_leading_garbage_until_header() { var garbage = Zmodem2.Header.trim_leading_garbage(this._input_buffer); if (garbage.length) { if (this._Happen("garbage", garbage) === 0) { console.debug( "Garbage: ", String.fromCharCode.apply(String, garbage), garbage ); } } } _parse_and_consume_header() { this._trim_leading_garbage_until_header(); var new_header_and_crc = Zmodem2.Header.parse(this._input_buffer); if (!new_header_and_crc) return; if (Zmodem2.DEBUG) { this._log_header("RECEIVED HEADER", new_header_and_crc[0]); } this._consume_header(new_header_and_crc[0]); this._last_header_name = new_header_and_crc[0].NAME; this._last_header_crc = new_header_and_crc[1]; return new_header_and_crc[0]; } _log_header(label, header) { console.debug(this.type, label, header.NAME, header._bytes4.join()); } _consume_header(new_header) { this._on_receive(new_header); var handler = this._next_header_handler && this._next_header_handler[new_header.NAME]; if (!handler) { console.error("Unhandled header!", new_header, this._next_header_handler); throw new Zmodem2.Error("Unhandled header: " + new_header.NAME); } this._next_header_handler = null; handler.call(this, new_header); } //TODO: strip out the abort sequence _check_for_abort_sequence() { var abort_at = Zmodem2.ZMLIB.find_subarray(this._input_buffer, ABORT_SEQUENCE); if (abort_at !== -1) { this._input_buffer.splice(0, abort_at + ABORT_SEQUENCE.length); this._aborted = true; this._on_session_end(); throw new Zmodem2.Error("peer_aborted"); } } _send_header(name2) { if (!this._sender) throw "Need sender!"; var args = Array.apply(null, arguments); var bytes_hdr = this._create_header_bytes(args); if (Zmodem2.DEBUG) { this._log_header("SENDING HEADER", bytes_hdr[1]); } this._sender(bytes_hdr[0]); this._last_sent_header = bytes_hdr[1]; } _create_header_bytes(name_and_args) { var hdr = Zmodem2.Header.build.apply(Zmodem2.Header, name_and_args); var formatter = this._get_header_formatter(name_and_args[0]); return [ hdr[formatter](this._zencoder), hdr ]; } _strip_and_enqueue_input(input) { Zmodem2.ZMLIB.strip_ignored_bytes(input); this._input_buffer.push.apply(this._input_buffer, input); } /** * **STOP!** You probably want to `skip()` an Offer rather than * `abort()`. See below. * * Abort the current session by sending the ZMODEM abort sequence. * This function will cause the Session object to refuse to send * any further data. * * Zmodem.Sentry is configured to send all output to the terminal * after a session’s `abort()`. That could result in lots of * ZMODEM garble being sent to the JavaScript terminal, which you * probably don’t want. * * `skip()` on an Offer is better because Session will continue to * discard data until we reach either another file or the * sender-initiated end of the ZMODEM session. So no ZMODEM garble, * and the session will end successfully. * * The behavior of `abort()` is subject to change since it’s not * very useful as currently implemented. */ abort() { this._sender( ABORT_SEQUENCE.concat([BS, BS, BS, BS, BS]) ); this._aborted = true; this._sender = function() { throw new Zmodem2.Error("already_aborted"); }; this._on_session_end(); return; } //---------------------------------------------------------------------- _on_session_end() { this._Happen("session_end"); } _on_receive(hdr_or_pkt) { this._Happen("receive", hdr_or_pkt); } _before_consume() { } }; function _trim_OO(array) { if (0 === Zmodem2.ZMLIB.find_subarray(array, OVER_AND_OUT)) { array.splice(0, OVER_AND_OUT.length); } else if (array[0] === OVER_AND_OUT[OVER_AND_OUT.length - 1]) { array.splice(0, 1); } return array; } Zmodem2.Session.Receive = class ZmodemReceiveSession extends Zmodem2.Session { //We only get 1 file at a time, so on each consume() either //continue state for the current file or start a new one. /** * Not called directly. */ constructor() { super(); this._Add_event("offer"); this._Add_event("data_in"); this._Add_event("file_end"); } /** * Consume input bytes from the sender. * * @private * @param {number[]} octets - The bytes to consume. */ _before_consume(octets) { if (this._bytes_after_OO) { throw "PROTOCOL: Session is completed!"; } this._bytes_being_consumed = octets; } /** * Return any bytes that have been `consume()`d but * came after the end of the ZMODEM session. * * @returns {number[]} The trailing bytes. */ get_trailing_bytes() { if (this._aborted) return []; if (!this._bytes_after_OO) { throw "PROTOCOL: Session is not completed!"; } return this._bytes_after_OO.slice(0); } _has_ended() { return this.aborted() || !!this._bytes_after_OO; } //Receiver always sends hex headers. _get_header_formatter() { return "to_hex"; } _parse_and_consume_subpacket() { var parse_func; if (this._last_header_crc === 16) { parse_func = "parse16"; } else { parse_func = "parse32"; } var subpacket = Zmodem2.Subpacket[parse_func](this._input_buffer); if (subpacket) { if (Zmodem2.DEBUG) { console.debug(this.type, "RECEIVED SUBPACKET", subpacket); } this._consume_data(subpacket); if (subpacket.frame_end()) { this._next_subpacket_handler = null; } } return subpacket; } _consume_first() { if (this._got_ZFIN) { if (this._input_buffer.length < 2) return; if (Zmodem2.ZMLIB.find_subarray(this._input_buffer, OVER_AND_OUT) === 0) { this._bytes_after_OO = _trim_OO(this._bytes_being_consumed.slice(0)); this._on_session_end(); return; } else { throw "PROTOCOL: Only thing after ZFIN should be \u201COO\u201D (79,79), not: " + this._input_buffer.join(); } } var parsed; do { if (this._next_subpacket_handler) { parsed = this._parse_and_consume_subpacket(); } else { parsed = this._parse_and_consume_header(); } } while (parsed && this._input_buffer.length); } _consume_data(subpacket) { this._on_receive(subpacket); if (!this._next_subpacket_handler) { throw "PROTOCOL: Received unexpected data packet after " + this._last_header_name + " header: " + subpacket.get_payload().join(); } this._next_subpacket_handler.call(this, subpacket); } _octets_to_string(octets) { if (!this._textdecoder) { this._textdecoder = new Zmodem2.Text.Decoder(); } return this._textdecoder.decode(new Uint8Array(octets)); } _consume_ZFILE_data(hdr, subpacket) { if (this._file_info) { throw "PROTOCOL: second ZFILE data subpacket received"; } var packet_payload = subpacket.get_payload(); var nul_at = packet_payload.indexOf(0); var fname = this._octets_to_string(packet_payload.slice(0, nul_at)); var the_rest = this._octets_to_string(packet_payload.slice(1 + nul_at)).split(" "); var mtime = the_rest[1] && parseInt(the_rest[1], 8) || void 0; if (mtime) { mtime = new Date(mtime * 1e3); } this._file_info = { name: fname, size: the_rest[0] ? parseInt(the_rest[0], 10) : null, mtime: mtime || null, mode: the_rest[2] && parseInt(the_rest[2], 8) || null, serial: the_rest[3] && parseInt(the_rest[3], 10) || null, files_remaining: the_rest[4] ? parseInt(the_rest[4], 10) : null, bytes_remaining: the_rest[5] ? parseInt(the_rest[5], 10) : null }; var xfer = new Offer( hdr.get_options(), this._file_info, this._accept.bind(this), this._skip.bind(this) ); this._current_transfer = xfer; } _consume_ZDATA_data(subpacket) { if (!this._accepted_offer) { throw "PROTOCOL: Received data without accepting!"; } if (!this._offset_ok) { console.warn("offset not ok!"); _send_ZRPOS(); return; } this._file_offset += subpacket.get_payload().length; this._on_data_in(subpacket); if (subpacket.ack_expected() && !subpacket.frame_end()) { this._send_header("ZACK", Zmodem2.ENCODELIB.pack_u32_le(this._file_offset)); } } _make_promise_for_between_files() { var sess = this; return new Promise(function(res) { var between_files_handler = { ZFILE: function(hdr) { this._next_subpacket_handler = function(subpacket) { this._next_subpacket_handler = null; this._consume_ZFILE_data(hdr, subpacket); this._Happen("offer", this._current_transfer); res(this._current_transfer); }; }, //We use this as a keep-alive. Maybe other //implementations do, too? ZSINIT: function(hdr) { sess._next_subpacket_handler = function(spkt) { sess._next_subpacket_handler = null; sess._consume_ZSINIT_data(spkt); sess._send_header("ZACK"); sess._next_header_handler = between_files_handler; }; }, ZFIN: function() { this._consume_ZFIN(); res(); } }; sess._next_header_handler = between_files_handler; }); } _consume_ZSINIT_data(spkt) { this._attn = spkt.get_payload(); } /** * Start the ZMODEM session by signaling to the sender that * we are ready for the first file offer. * * @returns {Promise} A promise that resolves with an Offer object * or, if the sender closes the session immediately without offering * anything, nothing. */ start() { if (this._started) throw "Already started!"; this._started = true; var ret = this._make_promise_for_between_files(); this._send_ZRINIT(); return ret; } //Returns a promise that’s fulfilled when the file //transfer is done. // // That ZEOF promise return is another promise that’s // fulfilled when we get either ZFIN or another ZFILE. _accept(offset) { this._accepted_offer = true; this._file_offset = offset || 0; var sess = this; var ret = new Promise(function(resolve_accept) { var last_ZDATA; sess._next_header_handler = { ZDATA: function on_ZDATA(hdr) { this._consume_ZDATA(hdr); this._next_subpacket_handler = this._consume_ZDATA_data; this._next_header_handler = { ZEOF: function on_ZEOF(hdr2) { this._consume_ZEOF(hdr2); this._next_subpacket_handler = null; this._make_promise_for_between_files(); resolve_accept(); this._send_ZRINIT(); } }; } }; }); this._send_ZRPOS(); return ret; } _skip() { var ret = this._make_promise_for_between_files(); if (this._accepted_offer) { if (!this._current_transfer) return; var bound_make_promise_for_between_files = function() { this._accepted_offer = false; this._next_subpacket_handler = null; this._make_promise_for_between_files(); }.bind(this); Object.assign( this._next_header_handler, { ZEOF: bound_make_promise_for_between_files, ZDATA: function() { bound_make_promise_for_between_files(); this._next_header_handler.ZEOF = bound_make_promise_for_between_files; }.bind(this) } ); } this._file_info = null; this._send_header("ZSKIP"); return ret; } _send_ZRINIT() { this._send_header("ZRINIT", ZRINIT_FLAGS); } _consume_ZFIN() { this._got_ZFIN = true; this._send_header("ZFIN"); } _consume_ZEOF(header) { if (this._file_offset !== header.get_offset()) { throw "ZEOF offset mismatch; unimplemented (local: " + this._file_offset + "; ZEOF: " + header.get_offset() + ")"; } this._on_file_end(); this._file_info = null; this._current_transfer = null; } _consume_ZDATA(header) { if (this._file_offset === header.get_offset()) { this._offset_ok = true; } else { throw "Error correction is unimplemented."; } } _send_ZRPOS() { this._send_header("ZRPOS", this._file_offset); } //---------------------------------------------------------------------- //events _on_file_end() { this._Happen("file_end"); if (this._current_transfer) { this._current_transfer._Happen("complete"); this._current_transfer = null; } } _on_data_in(subpacket) { this._Happen("data_in", subpacket); if (this._current_transfer) { this._current_transfer._Happen("input", subpacket.get_payload()); } } }; Object.assign( Zmodem2.Session.Receive.prototype, { type: "receive" } ); var Transfer_Offer_Mixin = { /** * Returns the file details object. * @returns {FileDetails} `mtime` is a Date. */ get_details: function get_details() { return Object.assign({}, this._file_info); }, /** * Returns a parse of the ZFILE header’s payload. * * @returns {Object} Members are: * * - `conversion` (string | undefined) * - `management` (string | undefined) * - `transfer` (string | undefined) * - `sparse` (boolean) */ get_options: function get_options() { return Object.assign({}, this._zfile_opts); }, /** * Returns the offset based on the last transferred chunk. * @returns {number} The file offset (i.e., number of bytes after * the start of the file). */ get_offset: function get_offset() { return this._file_offset; } }; var Transfer = class { /** * Not called directly. */ constructor(file_info, offset, send_func, end_func) { this._file_info = file_info; this._file_offset = offset || 0; this._send = send_func; this._end = end_func; } /** * Send a (non-terminal) piece of the file. * * @param { number[] | Uint8Array } array_like - The bytes to send. */ send(array_like) { this._send(array_like); this._file_offset += array_like.length; } /** * Complete the file transfer. * * @param { number[] | Uint8Array } [array_like] - The last bytes to send. * * @return { Promise } Resolves when the receiver has indicated * acceptance of the end of the file transfer. */ end(array_like) { var ret = this._end(array_like || []); if (array_like) this._file_offset += array_like.length; return ret; } }; Object.assign(Transfer.prototype, Transfer_Offer_Mixin); var Offer = class extends _Eventer { /** * Not called directly. */ constructor(zfile_opts, file_info, accept_func, skip_func) { super(); this._zfile_opts = zfile_opts; this._file_info = file_info; this._accept_func = accept_func; this._skip_func = skip_func; this._Add_event("input"); this._Add_event("complete"); this.on("input", this._input_handler); } _verify_not_skipped() { if (this._skipped) { throw new Zmodem2.Error("Already skipped!"); } } /** * Tell the sender that you don’t want the offered file. * * You can send this in lieu of `accept()` or after it, e.g., * if you find that the transfer is taking too long. Note that, * if you `skip()` after you `accept()`, you’ll likely have to * wait for buffers to clear out. * */ skip() { this._verify_not_skipped(); this._skipped = true; return this._skip_func.apply(this, arguments); } /** * Tell the sender to send the offered file. * * @param {Object} [opts] - Can be: * @param {string} [opts.oninput=spool_uint8array] - Can be: * * - `spool_uint8array`: Stores the ZMODEM * packet payloads as Uint8Array instances. * This makes for an easy transition to a Blob, * which JavaScript can use to save the file to disk. * * - `spool_array`: Stores the ZMODEM packet payloads * as Array instances. Each value is an octet value. * * - (function): A handler that receives each payload * as it arrives. The Offer object does not store * the payloads internally when thus configured. * * @return { Promise } Resolves when the file is fully received. * If the Offer has been spooling * the packet payloads, the promise resolves with an Array * that contains those payloads. */ accept(opts) { this._verify_not_skipped(); if (this._accepted) { throw new Zmodem2.Error("Already accepted!"); } this._accepted = true; if (!opts) opts = {}; this._file_offset = opts.offset || 0; switch (opts.on_input) { case null: case void 0: case "spool_array": case DEFAULT_RECEIVE_INPUT_MODE: this._spool = []; break; default: if (typeof opts.on_input !== "function") { throw "Invalid \u201Con_input\u201D: " + opts.on_input; } } this._input_handler_mode = opts.on_input || DEFAULT_RECEIVE_INPUT_MODE; return this._accept_func(this._file_offset).then(this._get_spool.bind(this)); } _input_handler(payload) { this._file_offset += payload.length; if (typeof this._input_handler_mode === "function") { this._input_handler_mode(payload); } else { if (this._input_handler_mode === DEFAULT_RECEIVE_INPUT_MODE) { payload = new Uint8Array(payload); } else if (this._input_handler_mode !== "spool_array") { throw new Zmodem2.Error("WTF?? _input_handler_mode = " + this._input_handler_mode); } this._spool.push(payload); } } _get_spool() { return this._spool; } }; Object.assign(Offer.prototype, Transfer_Offer_Mixin); var SENDER_BINARY_HEADER = { ZFILE: true, ZDATA: true }; Zmodem2.Session.Send = class ZmodemSendSession extends Zmodem2.Session { /** * Not called directly. */ constructor(zrinit_hdr) { super(); if (!zrinit_hdr) { throw "Need first header!"; } else if (zrinit_hdr.NAME !== "ZRINIT") { throw "First header should be ZRINIT, not " + zrinit_hdr.NAME; } this._last_header_name = "ZRINIT"; this._subpacket_encode_func = "encode16"; this._zencoder = new Zmodem2.ZDLE(); this._consume_ZRINIT(zrinit_hdr); this._file_offset = 0; var zrqinit_count = 0; this._start_keepalive_on_set_sender = true; } /** * Sets the sender function. The first time this is called, * it will also initiate a keepalive using ZSINIT until the * first file is sent. * * @param {Function} func - The function to call. * It will receive an Array with the relevant octets. * * @return {Session} The session object (for chaining). */ set_sender(func) { super.set_sender(func); if (this._start_keepalive_on_set_sender) { this._start_keepalive_on_set_sender = false; this._start_keepalive(); } return this; } //7.3.3 .. The sender also uses hex headers when they are //not followed by binary data subpackets. // //FG: … or when the header is ZSINIT? That’s what lrzsz does, anyway. //Then it sends a single NUL byte as the payload to an end_ack subpacket. _get_header_formatter(name2) { return SENDER_BINARY_HEADER[name2] ? "to_binary16" : "to_hex"; } //In order to keep lrzsz from timing out, we send ZSINIT every 5 seconds. //Maybe make this configurable? _start_keepalive() { if (!this._keepalive_promise) { var sess = this; this._keepalive_promise = new Promise(function(resolve) { sess._keepalive_timeout = setTimeout(resolve, KEEPALIVE_INTERVAL); }).then(function() { sess._next_header_handler = { ZACK: function() { sess._got_ZSINIT_ZACK = true; } }; sess._send_ZSINIT(); sess._keepalive_promise = null; sess._start_keepalive(); }); } } _stop_keepalive() { if (this._keepalive_promise) { clearTimeout(this._keepalive_timeout); this._keep_alive_promise = null; } } _send_ZSINIT() { var zsinit_flags = []; if (this._zencoder.escapes_ctrl_chars()) { zsinit_flags.push("ESCCTL"); } this._send_header_and_data( ["ZSINIT", zsinit_flags], [0], "end_ack" ); } _consume_ZRINIT(hdr) { this._last_ZRINIT = hdr; if (hdr.get_buffer_size()) { throw "Buffer size (" + hdr.get_buffer_size() + ") is unsupported!"; } if (!hdr.can_full_duplex()) { throw "Half-duplex I/O is unsupported!"; } if (!hdr.can_overlap_io()) { throw "Non-overlap I/O is unsupported!"; } if (hdr.escape_8th_bit()) { throw "8-bit escaping is unsupported!"; } if (FORCE_ESCAPE_CTRL_CHARS) { this._zencoder.set_escape_ctrl_chars(true); if (!hdr.escape_ctrl_chars()) { console.debug("Peer didn\u2019t request escape of all control characters. Will send ZSINIT to force recognition of escaped control characters."); } } else { this._zencoder.set_escape_ctrl_chars(hdr.escape_ctrl_chars()); } } //https://stackoverflow.com/questions/23155939/missing-0xf-and-0x16-when-binary-data-through-virtual-serial-port-pair-created-b //^^ Because of that, we always escape control characters. //The alternative would be that lrz would never receive those //two bytes from zmodem.js. _ensure_receiver_escapes_ctrl_chars() { var promise; var needs_ZSINIT = !this._last_ZRINIT.escape_ctrl_chars() && !this._got_ZSINIT_ZACK; if (needs_ZSINIT) { var sess = this; promise = new Promise(function(res) { sess._next_header_handler = { ZACK: (hdr) => { res(); } }; sess._send_ZSINIT(); }); } else { promise = Promise.resolve(); } return promise; } _convert_params_to_offer_payload_array(params) { params = Zmodem2.Validation.offer_parameters(params); var subpacket_payload = params.name + "\0"; var subpacket_space_pieces = [ (params.size || 0).toString(10), params.mtime ? params.mtime.toString(8) : "0", params.mode ? (32768 | params.mode).toString(8) : "0", "0" //serial ]; if (params.files_remaining) { subpacket_space_pieces.push(params.files_remaining); if (params.bytes_remaining) { subpacket_space_pieces.push(params.bytes_remaining); } } subpacket_payload += subpacket_space_pieces.join(" "); return this._string_to_octets(subpacket_payload); } /** * Send an offer to the receiver. * * @param {FileDetails} params - All about the file you want to transfer. * * @returns {Promise} If the receiver accepts the offer, then the * resolution is a Transfer object; otherwise the resolution is * undefined. */ send_offer(params) { if (Zmodem2.DEBUG) { console.debug("SENDING OFFER", params); } if (!params) throw "need file params!"; if (this._sending_file) throw "Already sending file!"; var payload_array = this._convert_params_to_offer_payload_array(params); this._stop_keepalive(); var sess = this; function zrpos_handler_setter_func() { sess._next_header_handler = { // The receiver may send ZRPOS in at least two cases: // // 1) A malformed subpacket arrived, so we need to // “rewind” a bit and continue from the receiver’s // last-successful location in the file. // // 2) The receiver hasn’t gotten any data for a bit, // so it sends ZRPOS as a “ping”. // // Case #1 shouldn’t happen since zmodem.js requires a // reliable transport. Case #2, though, can happen due // to either normal network congestion or errors in // implementation. In either case, there’s nothing for // us to do but to ignore the ZRPOS, with an optional // warning. // ZRPOS: function(hdr) { if (Zmodem2.DEBUG) { console.warn("Mid-transfer ZRPOS \u2026 implementation error?"); } zrpos_handler_setter_func(); } }; } ; var doer_func = function() { var handler_setter_promise = new Promise(function(res) { sess._next_header_handler = { ZSKIP: function() { sess._start_keepalive(); res(); }, ZRPOS: function(hdr) { sess._sending_file = true; zrpos_handler_setter_func(); res( new Transfer( params, hdr.get_offset(), sess._send_interim_file_piece.bind(sess), sess._end_file.bind(sess) ) ); } }; }); sess._send_header_and_data(["ZFILE"], payload_array, "end_ack"); delete sess._sent_ZDATA; return handler_setter_promise; }; if (FORCE_ESCAPE_CTRL_CHARS) { return this._ensure_receiver_escapes_ctrl_chars().then(doer_func); } return doer_func(); } _send_header_and_data(hdr_name_and_args, data_arr, frameend) { var bytes_hdr = this._create_header_bytes(hdr_name_and_args); var data_bytes = this._build_subpacket_bytes(data_arr, frameend); bytes_hdr[0].push.apply(bytes_hdr[0], data_bytes); if (Zmodem2.DEBUG) { this._log_header("SENDING HEADER", bytes_hdr[1]); console.debug(this.type, "-- HEADER PAYLOAD:", frameend, data_bytes.length); } this._sender(bytes_hdr[0]); this._last_sent_header = bytes_hdr[1]; } _build_subpacket_bytes(bytes_arr, frameend) { var subpacket = Zmodem2.Subpacket.build(bytes_arr, frameend); return subpacket[this._subpacket_encode_func](this._zencoder); } _build_and_send_subpacket(bytes_arr, frameend) { this._sender(this._build_subpacket_bytes(bytes_arr, frameend)); } _string_to_octets(string) { if (!this._textencoder) { this._textencoder = new Zmodem2.Text.Encoder(); } var uint8arr = this._textencoder.encode(string); return Array.prototype.slice.call(uint8arr); } /* Potential future support for responding to ZRPOS: send_file_offset(offset) { } */ /* Sending logic works thus: - ASSUME the receiver can overlap I/O (CANOVIO) (so fail if !CANFDX || !CANOVIO) - Sender opens the firehose … all ZCRCG (!end/!ack) until the end, when we send a ZCRCE (end/!ack) NB: try 8k/32k/64k chunk sizes? Looks like there’s no need to change the packet otherwise. */ //TODO: Put this on a Transfer object similar to what Receive uses? _send_interim_file_piece(bytes_obj) { this._send_file_part(bytes_obj, "no_end_no_ack"); return Promise.resolve(); } _ensure_we_are_sending() { if (!this._sending_file) throw "Not sending a file currently!"; } //This resolves once we receive ZEOF. _end_file(bytes_obj) { this._ensure_we_are_sending(); this._send_file_part(bytes_obj, "end_no_ack"); var sess = this; var ret = new Promise(function(res) { sess._sending_file = false; sess._prepare_to_receive_ZRINIT(res); }); this._send_header("ZEOF", this._file_offset); this._file_offset = 0; return ret; } //Called at the beginning of our session //and also when we’re done sending a file. _prepare_to_receive_ZRINIT(after_consume) { this._next_header_handler = { ZRINIT: function(hdr) { this._consume_ZRINIT(hdr); if (after_consume) after_consume(); } }; } /** * Signal to the receiver that the ZMODEM session is wrapping up. * * @returns {Promise} Resolves when the receiver has responded to * our signal that the session is over. */ close() { var ok_to_close = this._last_header_name === "ZRINIT"; if (!ok_to_close) { ok_to_close = this._last_header_name === "ZSKIP"; } if (!ok_to_close) { ok_to_close = this._last_sent_header.name === "ZSINIT" && this._last_header_name === "ZACK"; } if (!ok_to_close) { throw "Can\u2019t close; last received header was \u201C" + this._last_header_name + "\u201D"; } var sess = this; var ret = new Promise(function(res, rej) { sess._next_header_handler = { ZFIN: function() { sess._sender(OVER_AND_OUT); sess._sent_OO = true; sess._on_session_end(); res(); } }; }); this._send_header("ZFIN"); return ret; } _has_ended() { return this.aborted() || !!this._sent_OO; } _send_file_part(bytes_obj, final_packetend) { if (!this._sent_ZDATA) { this._send_header("ZDATA", this._file_offset); this._sent_ZDATA = true; } var obj_offset = 0; var bytes_count = bytes_obj.length; while (true) { var chunk_size = Math.min(obj_offset + MAX_CHUNK_LENGTH, bytes_count) - obj_offset; var at_end = chunk_size + obj_offset >= bytes_count; var chunk = bytes_obj.slice(obj_offset, obj_offset + chunk_size); if (!(chunk instanceof Array)) { chunk = Array.prototype.slice.call(chunk); } this._build_and_send_subpacket( chunk, at_end ? final_packetend : "no_end_no_ack" ); this._file_offset += chunk_size; obj_offset += chunk_size; if (obj_offset >= bytes_count) break; } } _consume_first() { if (!this._parse_and_consume_header()) { if (this._input_buffer.join() === "67") { throw "Receiver has fallen back to YMODEM."; } } } _on_session_end() { this._stop_keepalive(); super._on_session_end(); } }; Object.assign( Zmodem2.Session.Send.prototype, { type: "send" } ); } }); // node_modules/zmodem.js/src/zsentry.js var require_zsentry = __commonJS({ "node_modules/zmodem.js/src/zsentry.js"(exports2, module2) { "use strict"; var Zmodem2 = module2.exports; Object.assign( Zmodem2, require_zmlib(), require_zsession() ); var MAX_ZM_HEX_START_LENGTH = 21; var COMMON_ZM_HEX_START = [42, 42, 24, 66, 48]; var SENTRY_CONSTRUCTOR_REQUIRED_ARGS = [ "to_terminal", "on_detect", "on_retract", "sender" ]; var Detection = class { /** * Not called directly. */ constructor(session_type, accepter, denier, checker) { this._confirmer = accepter; this._denier = denier; this._is_valid = checker; this._session_type = session_type; } /** * Confirm that the detected ZMODEM sequence indicates the * start of a ZMODEM session. * * @return {Session} The ZMODEM Session object (i.e., either a * Send or Receive instance). */ confirm() { return this._confirmer.apply(this, arguments); } /** * Tell the Sentry that the detected bytes sequence is * **NOT** intended to be the start of a ZMODEM session. */ deny() { return this._denier.apply(this, arguments); } /** * Tells whether the Detection is still valid; i.e., whether * the Sentry has `consume()`d bytes that invalidate the * Detection. * * @returns {boolean} Whether the Detection is valid. */ is_valid() { return this._is_valid.apply(this, arguments); } /** * Gives the session’s role. * * @returns {string} One of: * - `receive` * - `send` */ get_session_role() { return this._session_type; } }; Zmodem2.Sentry = class ZmodemSentry { /** * Invoked directly. Creates a new Sentry that inspects all * traffic before it goes to the terminal. * * @param {Object} options - The Sentry parameters * * @param {Function} options.to_terminal - Handler that sends * traffic to the terminal object. Receives an iterable object * (e.g., an Array) that contains octet numbers. * * @param {Function} options.on_detect - Handler for new * detection events. Receives a new Detection object. * * @param {Function} options.on_retract - Handler for retraction * events. Receives no input. * * @param {Function} options.sender - Handler that sends traffic to * the peer. If, for example, your application uses WebSocket to talk * to the peer, use this to send data to the WebSocket instance. */ constructor(options) { if (!options) throw "Need options!"; var sentry = this; SENTRY_CONSTRUCTOR_REQUIRED_ARGS.forEach(function(arg) { if (!options[arg]) { throw "Need \u201C" + arg + "\u201D!"; } sentry["_" + arg] = options[arg]; }); this._cache = []; } _after_session_end() { this._zsession = null; } /** * “Consumes” a piece of input: * * - If there is no active or pending ZMODEM session, the text is * all output. (This is regardless of whether we’ve got a new * Detection.) * * - If there is no active ZMODEM session and the input **ends** with * a ZRINIT or ZRQINIT, then a new Detection object is created, * and it is passed to the “on_detect” function. * If there was another pending Detection object, it is retracted. * * - If there is no active ZMODEM session and the input does NOT end * with a ZRINIT or ZRQINIT, then any pending Detection object is * retracted. * * - If there is an active ZMODEM session, the input is passed to it. * Any non-ZMODEM data (i.e., “garbage”) parsed from the input * is sent to output. * If the ZMODEM session ends, any post-ZMODEM part of the input * is sent to output. * * @param {number[] | ArrayBuffer} input - Octets to parse as input. */ consume(input) { if (!(input instanceof Array)) { input = Array.prototype.slice.call(new Uint8Array(input)); } if (this._zsession) { var session_before_consume = this._zsession; session_before_consume.consume(input); if (session_before_consume.has_ended()) { if (session_before_consume.type === "receive") { input = session_before_consume.get_trailing_bytes(); } else { input = []; } } else return; } var new_session = this._parse(input); var to_terminal = input; if (new_session) { let checker = function() { return sentry._parsed_session === new_session; }, accepter = function() { if (!this.is_valid()) { throw "Stale ZMODEM session!"; } new_session.on("garbage", sentry._to_terminal); new_session.on( "session_end", sentry._after_session_end.bind(sentry) ); new_session.set_sender(sentry._sender); delete sentry._parsed_session; return sentry._zsession = new_session; }, denier = function() { if (!this.is_valid()) return; }; let replacement_detect = !!this._parsed_session; if (replacement_detect) { if (this._parsed_session.type === new_session.type) { to_terminal = []; } this._on_retract(); } this._parsed_session = new_session; var sentry = this; ; ; this._on_detect(new Detection( new_session.type, accepter, this._send_abort.bind(this), checker )); } else { var expired_session = this._parsed_session; this._parsed_session = null; if (expired_session) { if (to_terminal.length === 1 && to_terminal[0] === 67) { this._send_abort(); } this._on_retract(); } } this._to_terminal(to_terminal); } /** * @return {Session|null} The sentry’s current Session object, or * null if there is none. */ get_confirmed_session() { return this._zsession || null; } _send_abort() { this._sender(Zmodem2.ZMLIB.ABORT_SEQUENCE); } /** * Parse an input stream and decide how much of it goes to the * terminal or to a new Session object. * * This will accommodate input strings that are fragmented * across calls to this function; e.g., if you send the first * two bytes at the end of one parse() call then send the rest * at the beginning of the next, parse() will recognize it as * the beginning of a ZMODEM session. * * In order to keep from blocking any actual useful data to the * terminal in real-time, this will send on the initial * ZRINIT/ZRQINIT bytes to the terminal. They’re meant to go to the * terminal anyway, so that should be fine. * * @private * * @param {Array|Uint8Array} array_like - The input bytes. * Each member should be a number between 0 and 255 (inclusive). * * @return {Array} A two-member list: * 0) the bytes that should be printed on the terminal * 1) the created Session object (if any) */ _parse(array_like) { var cache = this._cache; cache.push.apply(cache, array_like); while (true) { let common_hex_at = Zmodem2.ZMLIB.find_subarray(cache, COMMON_ZM_HEX_START); if (-1 === common_hex_at) break; let before_common_hex = cache.splice(0, common_hex_at); let zsession; try { zsession = Zmodem2.Session.parse(cache); } catch (err) { } if (!zsession) break; if (cache.length === 1 && cache[0] === Zmodem2.ZMLIB.XON) { cache.shift(); } return cache.length ? null : zsession; } cache.splice(MAX_ZM_HEX_START_LENGTH); return null; } }; } }); // node_modules/zmodem.js/index.js var require_zmodem = __commonJS({ "node_modules/zmodem.js/index.js"(exports2, module2) { "use strict"; Object.assign( module2.exports, require_zsentry() ); } }); // src/main/zmodem.ts var zmodem_exports = {}; __export(zmodem_exports, { attachZmodem: () => attachZmodem, detachZmodem: () => detachZmodem, feedZmodem: () => feedZmodem, isZmodemActive: () => isZmodemActive, respondZmodem: () => respondZmodem }); module.exports = __toCommonJS(zmodem_exports); var import_path = require("path"); var import_fs = require("fs"); var import_promises = require("fs/promises"); var Zmodem = __toESM(require_zmodem()); // src/shared/ipc.ts var Ipc = { // ---- PTY session lifecycle ---- // NOTE: since M2 these channels are session-generic: `id` addresses both // local pty sessions and ssh sessions; data plane is identical. PTY_CREATE: "pty:create", PTY_WRITE: "pty:write", PTY_RESIZE: "pty:resize", PTY_KILL: "pty:kill", /** main -> renderer broadcast: { id, data } */ PTY_DATA: "pty:data", /** main -> renderer broadcast: { id, exitCode } */ PTY_EXIT: "pty:exit", // ---- settings ---- SETTINGS_GET: "settings:get", SETTINGS_SET: "settings:set", /** main -> renderer broadcast after any save */ SETTINGS_CHANGED: "settings:changed", // ---- fonts ---- FONTS_LIST: "fonts:list", // ---- layouts ---- LAYOUTS_LIST: "layouts:list", LAYOUTS_GET: "layouts:get", LAYOUTS_SAVE: "layouts:save", LAYOUTS_DELETE: "layouts:delete", // ---- sessions (openSession unifies local pty and ssh) ---- SESSION_OPEN: "session:open", /** main keeps a short replay buffer per session so late subscribers catch up */ SESSION_REPLAY: "session:replay", // ---- ssh connections (bookmarks) ---- CONNECTIONS_LIST: "connections:list", CONNECTIONS_SAVE: "connections:save", CONNECTIONS_DELETE: "connections:delete", // ---- host key verification ---- /** main -> renderer: needs user decision before connect proceeds */ HOSTKEY_PROMPT: "hostkey:prompt", HOSTKEY_RESPOND: "hostkey:respond", // ---- sysinfo (M3) ---- SYSINFO_START: "sysinfo:start", SYSINFO_STOP: "sysinfo:stop", /** main -> renderer broadcast: { id, meta } (once per session) */ SYSINFO_META: "sysinfo:meta", /** main -> renderer broadcast: { id, sample } (poll interval) */ SYSINFO_SAMPLE: "sysinfo:sample", // ---- sftp (M4) ---- SFTP_LIST: "sftp:list", SFTP_MKDIR: "sftp:mkdir", SFTP_RENAME: "sftp:rename", SFTP_DELETE: "sftp:delete", SFTP_CHMOD: "sftp:chmod", SFTP_CHOWN: "sftp:chown", SFTP_UPLOAD: "sftp:upload", SFTP_DOWNLOAD: "sftp:download", TRANSFER_CANCEL: "transfer:cancel", /** main -> renderer broadcast: TransferProgressEvent */ TRANSFER_PROGRESS: "transfer:progress", DIALOG_PICK_FILES: "dialog:pickFiles", DIALOG_PICK_DIR: "dialog:pickDirectory", // ---- commands + logs (M5) ---- COMMANDS_RECORD: "commands:record", COMMANDS_HISTORY_LIST: "commands:historyList", COMMANDS_HISTORY_CLEAR: "commands:historyClear", COMMANDS_LIBRARY_LIST: "commands:libraryList", COMMANDS_LIBRARY_SAVE: "commands:librarySave", COMMANDS_LIBRARY_DELETE: "commands:libraryDelete", LOG_START: "log:start", LOG_STOP: "log:stop", LOG_LIST: "log:list", LOG_OPEN_DIR: "log:openDir", // ---- zmodem (M6: main-process engine, ssh sessions only) ---- /** main -> renderer: remote ran rz (mode=send) or sz (mode=receive); renderer must ask the user */ ZMODEM_OFFER: "zmodem:offer", /** renderer -> main: user answered the zmodem offer */ ZMODEM_RESPOND: "zmodem:respond", /** main -> renderer: zmodem session finished (ok, cancelled or failed) */ ZMODEM_DONE: "zmodem:done", // ---- misc ---- APP_INFO: "app:info" }; // src/main/zmodem.ts var OFFER_TIMEOUT_MS = 12e4; var STALL_TIMEOUT_MS = 9e4; var ABORT_BUFFER = Buffer.from(Zmodem.ZMLIB.ABORT_SEQUENCE); var engines = /* @__PURE__ */ new Map(); function current(sessionId) { return engines.get(sessionId); } function cancelTimers(engine) { if (engine.offerTimer) clearTimeout(engine.offerTimer); if (engine.stallTimer) clearTimeout(engine.stallTimer); engine.offerTimer = null; engine.stallTimer = null; } function emitProgress(engine, patch) { const evt = { transferId: engine.transferId, kind: engine.mode === "receive" ? "zmodem-download" : "zmodem-upload", state: "running", file: "", bytes: engine.bytes, totalBytes: engine.totalBytes, ...patch }; try { engine.deps.broadcast(Ipc.TRANSFER_PROGRESS, evt); } catch { } } function emitDone(engine, ok, message) { if (engine.doneEmitted) return; engine.doneEmitted = true; const evt = { id: engine.id, ok, message }; try { engine.deps.broadcast(Ipc.ZMODEM_DONE, evt); } catch { } } function finalize(engine, ok, message) { engine.active = false; cancelTimers(engine); if (engine.receiveStream) { try { engine.receiveStream.end(); } catch { } engine.receiveStream = null; } engine.session = null; engine.detection = null; if (!engine.progressEmitted) { emitProgress(engine, { state: ok ? "done" : "cancelled", file: message ?? "" }); } engine.progressEmitted = true; if (ok) emitDone(engine, true); else emitDone(engine, false, message ?? "\u4F20\u8F93\u5931\u8D25"); } function makeSessionEnd(engine) { return () => finalize(engine, true); } function touchActivity(engine) { if (engine.stallTimer) clearTimeout(engine.stallTimer); const timer = setTimeout(() => { if (engine.stallTimer === null) return; finalize(engine, false, "\u4F20\u8F93\u8D85\u65F6"); }, STALL_TIMEOUT_MS); engine.stallTimer = timer; } function wireSession(engine) { const session = engine.session; if (!session) return; const sendToPeer = (octets) => { try { engine.deps.writeStream(engine.id, Buffer.from(octets)); } catch { } }; session.set_sender(sendToPeer); session.on("session_end", makeSessionEnd(engine)); touchActivity(engine); } async function sendOneFile(engine, session, file) { const xfer = await session.send_offer({ name: file.name, size: file.size, mtime: new Date(file.mtimeMs), mode: void 0 }); if (!xfer) return; emitProgress(engine, { file: file.name, bytes: engine.bytes, totalBytes: engine.totalBytes }); await new Promise((resolve, reject) => { const rs = (0, import_fs.createReadStream)(file.path); rs.on("data", (chunk) => { rs.pause(); const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk); try { xfer.send(new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)); } catch (err) { rs.destroy(); reject(err instanceof Error ? err : new Error("\u53D1\u9001\u5931\u8D25")); return; } engine.bytes += buf.length; emitProgress(engine, { file: file.name, bytes: engine.bytes, totalBytes: engine.totalBytes }); touchActivity(engine); rs.resume(); }); rs.on("end", () => { xfer.end().then(() => resolve()).catch(reject); }); rs.on("error", reject); }); } async function runSend(engine, paths) { try { const session = engine.session; const files = await Promise.all( paths.map(async (p) => { const s = await (0, import_promises.stat)(p); return { path: p, name: (0, import_path.basename)(p), size: s.size, mtimeMs: s.mtimeMs }; }) ); engine.totalBytes = files.reduce((acc, f) => acc + f.size, 0); for (const f of files) { emitProgress(engine, { file: f.name, bytes: engine.bytes, totalBytes: engine.totalBytes }); await sendOneFile(engine, session, f); } emitProgress(engine, { file: "", bytes: engine.totalBytes, totalBytes: engine.totalBytes }); await session.close(); } catch (err) { finalize(engine, false, err instanceof Error ? err.message : "\u4E0A\u4F20\u5931\u8D25"); } } function handleOffer(engine, offer) { const details = offer.get_details(); const name2 = (0, import_path.basename)(String(details.name ?? "file")); const dest = (0, import_path.join)(engine.dir ?? ".", name2); if (details.size) engine.totalBytes += details.size; const stream = (0, import_fs.createWriteStream)(dest); engine.receiveStream = stream; emitProgress(engine, { file: name2, bytes: engine.bytes, totalBytes: engine.totalBytes }); offer.accept({ on_input: (payload) => { const buf = Array.isArray(payload) ? Buffer.from(payload) : Buffer.from(payload.buffer, payload.byteOffset, payload.byteLength); if (!stream.destroyed && !stream.closed) { stream.write(buf); } engine.bytes += buf.byteLength; emitProgress(engine, { file: name2, bytes: engine.bytes, totalBytes: engine.totalBytes }); touchActivity(engine); } }).then(() => { stream.end(() => { if (engine.receiveStream === stream) engine.receiveStream = null; emitProgress(engine, { file: name2, bytes: engine.bytes, totalBytes: engine.totalBytes }); }); }).catch((err) => { finalize(engine, false, err instanceof Error ? err.message : "\u63A5\u6536\u5931\u8D25"); }); } function attachZmodem(sessionId, deps) { const engine = { id: sessionId, deps, sentry: new Zmodem.Sentry({ to_terminal: (octets) => { if (engine.active) return; try { deps.toTerminal(sessionId, Buffer.from(octets).toString("utf8")); } catch { } }, on_detect: (detection) => { const role = detection.get_session_role(); engine.mode = role === "receive" ? "receive" : "send"; engine.detection = detection; engine.active = true; engine.transferId = `zm-${sessionId}`; emitProgress(engine, { file: "", bytes: 0, totalBytes: 0 }); try { deps.broadcast(Ipc.ZMODEM_OFFER, { id: sessionId, mode: engine.mode }); } catch { } touchActivity(engine); engine.offerTimer = setTimeout(() => { if (engine.detection && !engine.confirmed) abortWithoutSession(engine, "\u672A\u9009\u62E9\u6587\u4EF6\uFF0C\u5DF2\u53D6\u6D88"); }, OFFER_TIMEOUT_MS); }, on_retract: () => { engine.detection = null; engine.mode = null; engine.active = false; cancelTimers(engine); }, sender: (octets) => { try { deps.writeStream(sessionId, Buffer.from(octets)); } catch { } } }), detection: null, session: null, active: false, mode: null, dir: null, confirmed: false, transferId: `zm-${sessionId}`, progressEmitted: false, doneEmitted: false, offerTimer: null, stallTimer: null, receiveStream: null, bytes: 0, totalBytes: 0 }; engines.set(sessionId, engine); } function abortWithoutSession(engine, message) { try { engine.deps.writeStream(engine.id, ABORT_BUFFER); } catch { } engine.active = false; cancelTimers(engine); if (!engine.progressEmitted) emitProgress(engine, { state: "cancelled", file: message }); engine.progressEmitted = true; emitDone(engine, false, message); } function abortSession(engine, message) { try { engine.session?.abort(); } catch { } try { engine.deps.writeStream(engine.id, ABORT_BUFFER); } catch { } finalize(engine, false, message); } function feedZmodem(sessionId, data) { const engine = current(sessionId); if (!engine) return; try { engine.sentry.consume(data); } catch (err) { if (!engine.doneEmitted) finalize(engine, false, err instanceof Error ? err.message : "ZMODEM \u4F20\u8F93\u5F02\u5E38"); } } function isZmodemActive(sessionId) { return current(sessionId)?.active ?? false; } function respondZmodem(resp) { const engine = current(resp.id); if (!engine || engine.confirmed) return; if (resp.cancelled) { abortWithoutSession(engine, "\u5DF2\u53D6\u6D88"); return; } const detection = engine.detection; if (!detection || !detection.is_valid()) { abortWithoutSession(engine, "\u4F1A\u8BDD\u5DF2\u5931\u6548"); return; } engine.confirmed = true; engine.session = detection.confirm(); if (!engine.session) { abortWithoutSession(engine, "\u65E0\u6CD5\u5EFA\u7ACB ZMODEM \u4F1A\u8BDD"); return; } wireSession(engine); if (engine.mode === "receive") { if (!resp.dir) { abortSession(engine, "\u672A\u6307\u5B9A\u4FDD\u5B58\u76EE\u5F55"); return; } engine.dir = resp.dir; const session = engine.session; session.on("offer", (offer) => handleOffer(engine, offer)); void session.start().catch((err) => finalize(engine, false, err instanceof Error ? err.message : "\u63A5\u6536\u5931\u8D25")); } else { const paths = resp.paths ?? []; if (paths.length === 0) { abortSession(engine, "\u672A\u9009\u62E9\u6587\u4EF6"); return; } void runSend(engine, paths); } } function detachZmodem(sessionId) { const engine = current(sessionId); if (!engine) return; engine.active = false; cancelTimers(engine); if (engine.receiveStream) { try { engine.receiveStream.end(); } catch { } engine.receiveStream = null; } engine.session = null; engine.detection = null; engines.delete(sessionId); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { attachZmodem, detachZmodem, feedZmodem, isZmodemActive, respondZmodem }); /*! Bundled license information: crc-32/crc32.js: (*! crc32.js (C) 2014-present SheetJS -- http://sheetjs.com *) */