1module Gopher23import Builtin4import Data.Strings5import Network.Socket67-- Valid gopher item types as defined in RFC 1436.8public export9data ItemType = Document |10 Directory |11 PhoneBook |12 Error |13 BinHex |14 PCDOS |15 UnixUuencoded |16 SearchService |17 TelnetSession |18 Binary |19 Duplicated |20 Gif |21 Image |22 Tn3270Session |23 InfoLine |24 HTML2526public export27Show ItemType where28 show Document = "Document"29 show Directory = "Directory"30 show PhoneBook = "Phonebook"31 show Error = "Error"32 show BinHex = "BINHEX"33 show PCDOS = "PCDOS"34 show UnixUuencoded = "Uuencoded"35 show SearchService = "SearchService"36 show TelnetSession = "Telnet"37 show Binary = "Binary"38 show Duplicated = "Duplicated"39 show Gif = "Gif"40 show Image = "Image"41 show Tn3270Session ="Tn3270"42 show InfoLine = "Info"43 show HTML = "HTML"4445-- Selector used to retrieve a document from a server.46public export47Selector : Type48Selector = String4950-- Address of a server which stores a given document.51public export52Address : Type53Address = (String, Nat)5455-- Product type for a Gopher menu entry.56public export57data Item = MkItem ItemType String Selector Address5859public export60unmarshalType : Char -> Maybe ItemType61unmarshalType '0' = Just Document62unmarshalType '1' = Just Directory63unmarshalType '2' = Just PhoneBook64unmarshalType '3' = Just Error65unmarshalType '4' = Just BinHex66unmarshalType '5' = Just PCDOS67unmarshalType '6' = Just UnixUuencoded68unmarshalType '7' = Just SearchService69unmarshalType '8' = Just TelnetSession70unmarshalType '9' = Just Binary71unmarshalType '+' = Just Duplicated72unmarshalType 'g' = Just Gif73unmarshalType 'I' = Just Image74unmarshalType 'i' = Just InfoLine75unmarshalType 'T' = Just Tn3270Session76unmarshalType 'h' = Just HTML77unmarshalType _ = Nothing7879public export80isUnAscii : Char -> Bool81isUnAscii '\r' = False82isUnAscii '\n' = False83isUnAscii '\t' = False84isUnAscii '\0' = False85isUnAscii _ = True8687public export88isHostPart : Char -> Bool89isHostPart c = (isUnAscii c) && (c /= '.')9091partial92recvMsg' : HasIO io => Socket -> List String -> io (Either SocketError String)93recvMsg' sock acc = do94 res <- recv sock bufsiz95 case res of96 Left err => if err == 097 then pure $ Right (concat acc)98 else pure $ Left err99 Right (str, n) => if isSuffixOf delim str100 then pure $ let out = rmDelim str in101 Right (concat $ acc ++ [out])102 else recvMsg' sock (acc ++ [str])103 where104 bufsiz : ByteLength105 bufsiz = 4096106107 delim : String108 delim = "\r\n.\r\n"109110 rmDelim : String -> String111 rmDelim s = strSubstr 0 (cast $ minus (length s) (length ".\r\n")) s112113export114recvMsg : HasIO io => (sock : Socket) -> io (Either SocketError String)115recvMsg sock = recvMsg' sock []