require "process" require "io/memory" require "io" module Taro enum WinType LIST READER COMPOSE end class Mesg @type : UInt8 @data : Slice(UInt8) def type @type end def data @data end def initialize(@type, @data) end end class ChildWindow @lifetime : Channel(UInt8) @msg : Channel(Mesg) @stdout_w : IO::FileDescriptor @stdout_r : IO::FileDescriptor @stdin_w : IO::FileDescriptor @stdin_r : IO::FileDescriptor @decoding : Bool = false @sizing : Bool = false @szshort : UInt16 = 0 def initialize(w : WinType = WinType::LIST) @stdout_r, @stdout_w = IO.pipe @stdin_r, @stdin_w = IO.pipe @lifetime = Channel(UInt8).new @msg = Channel(Mesg).new uxnrom : String = "" case w when WinType::LIST then uxnrom = "taro-ls" when WinType::READER then uxnrom = "taro-reader" when WinType::COMPOSE then uxnrom = "taro-compose" end uxnargs = ["-s", "1", "#{uxnrom}.rom"] spawn do Process.run(command: "uxnemu", args: uxnargs, input: @stdin_r, output: @stdout_w, error: Process::Redirect::Inherit) @lifetime.send(0) end spawn do loop do @msg.send(read_msg) end end end def lifetime @lifetime end def msg @msg end def write_msg(msgtype : UInt8, data : Slice) msgsz = UInt16.new(data.size > 16384 ? 16384 : data.size) msgtype.to_io(@stdin_w, IO::ByteFormat::BigEndian) if msgsz != 0 msgsz.to_io(@stdin_w, IO::ByteFormat::BigEndian) else 8_u16.to_io(@stdin_w, IO::ByteFormat::BigEndian) end if msgsz == 16384 @stdin_w.write(data[0..msgsz - 2]) 10_u8.to_io(@stdin_w, IO::ByteFormat::BigEndian) elsif msgsz != 0 @stdin_w.write(data[0..msgsz - 1]) else @stdin_w.write("nothing\n".to_slice) end end def read_msg msgType : UInt8 = 0 data : Slice(UInt8) = Slice(UInt8).new(0) loop do if @stdout_r.closed? @decoding = false @sizing = false @szshort = 0 break end if !@decoding msgType = @stdout_r.read_byte || 0_u8 @decoding = true @sizing = true elsif @sizing szslice = Slice(UInt8).new(2) @stdout_r.read_fully(szslice) szlow : UInt16 = UInt16.new(szslice[0])*256 szhigh : UInt16 = UInt16.new(szslice[1]) @szshort = szlow + szhigh @sizing = false if @szshort == 0 @decoding = false break end else slc = Slice(UInt8).new(@szshort) @stdout_r.read_fully(slc) data = slc @decoding = false @szshort = 0 break end end return Mesg.new(msgType, data) end end class MblazeProxy @mailbox : String def initialize @mailbox = "INBOX" end private def run_cmd(cmdtxt : String) : String puts cmdtxt io = IO::Memory.new Process.run(cmdtxt, shell: true, output: io) return io.to_s end def list_mail : String cmd = " mbox=${MBOX_ROOT}/#{@mailbox} mdirs ${mbox} | xargs minc > /dev/null mlist ${mbox} | msort -dr | mseq -S | mscan" return run_cmd(cmd) end def list_mboxes : String cmd = "echo 'INBOX' ; for x in $(mdirs -a ${MBOX_ROOT} | sort | grep -v INBOX); do echo ${x#$MBOX_ROOT/}; done" return run_cmd(cmd) end def mark_all_read cmd = "mflag -S :" run_cmd(cmd) end def set_mbox(box : String) @mailbox = box end def trash_mail(range : String) cmd = "mflag -T #{range}; mlist ${MBOX_ROOT}/#{@mailbox} | mseq -S | mpick -t 'trashed' | mrefile ${MBOX_ROOT}/Trash" run_cmd(cmd) end def refile_mail(range : String, to_mbox : String) cmd = "mrefile #{range} ${MBOX_ROOT}/#{to_mbox}" run_cmd(cmd) end def search_mail(query : String, body : Bool) : String mailCmd = "mlist ${MBOX_ROOT}/#{@mailbox} | magrep #{body ? "/" : "*"} | msort -dr | mseq -S | mscan | uniq" return run_cmd(cmd) end end class TaroCtl @mblaze : MblazeProxy @lsWin : ChildWindow @readWins : Array(ChildWindow) @composeWins : Array(ChildWindow) def initialize @lsWin = ChildWindow.new @readWins = Array(ChildWindow).new @composeWins = Array(ChildWindow).new @mblaze = MblazeProxy.new list = @mblaze.list_mail mboxes = @mblaze.list_mboxes @lsWin.write_msg(0_u8, mboxes.to_slice) @lsWin.write_msg(2_u8, list.to_slice) end def mblaze @mblaze end def mainWindow @lsWin end def readWins @readWins end def composeWins @composeWins end end end taro = Taro::TaroCtl.new loop do select when taro.mainWindow.lifetime.receive? exit when m = taro.mainWindow.msg.receive case m.type when 1 then taro.mblaze.set_mbox(String.new(m.data)) taro.mainWindow.write_msg(2_u8, taro.mblaze.list_mail.to_slice) when 3 then taro.mblaze.mark_all_read taro.mainWindow.write_msg(2_u8, taro.mblaze.list_mail.to_slice) end end end