gdris

A toy gopher client written in Idris2

git clone https://git.8pit.net/gdris.git

  1module Gopher
  2
  3import Builtin
  4import Data.Strings
  5import Network.Socket
  6
  7-- Valid gopher item types as defined in RFC 1436.
  8public export
  9data 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    HTML
 25
 26public export
 27Show ItemType where
 28    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"
 44
 45-- Selector used to retrieve a document from a server.
 46public export
 47Selector : Type
 48Selector = String
 49
 50-- Address of a server which stores a given document.
 51public export
 52Address : Type
 53Address = (String, Nat)
 54
 55-- Product type for a Gopher menu entry.
 56public export
 57data Item = MkItem ItemType String Selector Address
 58
 59public export
 60unmarshalType : Char -> Maybe ItemType
 61unmarshalType '0' = Just Document
 62unmarshalType '1' = Just Directory
 63unmarshalType '2' = Just PhoneBook
 64unmarshalType '3' = Just Error
 65unmarshalType '4' = Just BinHex
 66unmarshalType '5' = Just PCDOS
 67unmarshalType '6' = Just UnixUuencoded
 68unmarshalType '7' = Just SearchService
 69unmarshalType '8' = Just TelnetSession
 70unmarshalType '9' = Just Binary
 71unmarshalType '+' = Just Duplicated
 72unmarshalType 'g' = Just Gif
 73unmarshalType 'I' = Just Image
 74unmarshalType 'i' = Just InfoLine
 75unmarshalType 'T' = Just Tn3270Session
 76unmarshalType 'h' = Just HTML
 77unmarshalType _   = Nothing
 78
 79public export
 80isUnAscii : Char -> Bool
 81isUnAscii '\r' = False
 82isUnAscii '\n' = False
 83isUnAscii '\t' = False
 84isUnAscii '\0' = False
 85isUnAscii _    = True
 86
 87public export
 88isHostPart : Char -> Bool
 89isHostPart c = (isUnAscii c) && (c /= '.')
 90
 91partial
 92recvMsg' : HasIO io => Socket -> List String -> io (Either SocketError String)
 93recvMsg' sock acc = do
 94    res <- recv sock bufsiz
 95    case res of
 96        Left err => if err == 0
 97                      then pure $ Right (concat acc)
 98                      else pure $ Left err
 99        Right (str, n) => if isSuffixOf delim str
100                            then pure $ let out = rmDelim str in
101                                Right (concat $ acc ++ [out])
102                            else recvMsg' sock (acc ++ [str])
103    where
104        bufsiz : ByteLength
105        bufsiz = 4096
106
107        delim : String
108        delim = "\r\n.\r\n"
109
110        rmDelim : String -> String
111        rmDelim s = strSubstr 0 (cast $ minus (length s) (length ".\r\n")) s
112
113export
114recvMsg : HasIO io => (sock : Socket) -> io (Either SocketError String)
115recvMsg sock = recvMsg' sock []