require 'pty' SOH = 0x01 EOT = 0x04 ACK = 0x06 NAK = 0x15 BLOCKSIZE = 128 infile, outfile = ARGV File.open(outfile, 'wb') do |f| PTY.spawn('sx', '-b', infile) do |stdout, stdin, _pid| stdout.gets # "Give your local XMODEM receive command now." stdin.putc(NAK) loop do control = stdout.readbyte break if control == EOT control == SOH || raise('expected start of header') blocknum = stdout.readbyte inv_blocknum = stdout.readbyte blocknum + inv_blocknum == 0xFF || raise("block numbers don't match") block = stdout.read(BLOCKSIZE) expected = block.bytes.reduce(0, &:+) & 0xFF actual = stdout.readbyte stdin.putc(expected == actual ? ACK : NAK) f.write(block) if expected == actual end stdin.putc(ACK) end end