module Net.TFTP where

-- TFTP - Trivial File Transfer Protocol, RFC 1350, STD 33
-- See http://www.networksorcery.com/enp/protocol/tftp.htm
--     http://www.networksorcery.com/enp/rfc/rfc1350.txt

import Net.Bits
import Net.Packet
import Net.PacketParsing

data Packet
  = RRQ Filename Mode
  | WRQ Filename Mode
  | Data BlockNr Data
  | Ack BlockNr
  | Error ErrorCode ErrMsg
  deriving (Show)

type Filename = String
type Mode = String
type BlockNr = Word16
type Data = UArray Int Word8 -- could be changed
newtype ErrorCode = E Word16 deriving (Eq,Show)
type ErrMsg = String

--------------------------------------------------------------------------------

instance Parse Packet where
  parse =
    do opcode <- word16
       case opcode of
         1 -> RRQ # string <# string
	 2 -> WRQ # string <# string
	 3 -> Data # parse <# parse
	 4 -> Ack # parse
	 5 -> Error # parse <# string
	 _ -> fail "bad TFTP opcode"

instance Parse ErrorCode where parse = E # parse

string = do b <- word8
	    if b==0
	      then return []
	      else (char b:) # string
  where char :: Word8 -> Char
	char = toEnum . fromEnum

--------------------------------------------------------------------------------

instance Unparse Packet where
  unparse p =
    case p of
      RRQ f m -> w 1 . unstring f . unstring m
      WRQ f m -> w 2 . unstring f . unstring m
      Data n d -> w 3 . unparse (n,d)
      Ack n -> w 4 . unparse n
      Error n s -> w 5 . unparse n . unstring s
    where w n = unparse (n::Word16)

instance Unparse ErrorCode where unparse (E w) = unparse w

unstring s = unparse (s,'\0')