assumpta-core-0.1.0.2: Core functionality for an SMTP client

Network.Mail.Assumpta.ParseResponse

Description

Parse server replies.

The general format of replies is described in RFC 5321, at p. 49:

  The format for multiline replies requires that every line,
except the last, begin with the reply code, followed
immediately by a hyphen, "-" (also known as minus), followed by
text.  The last line will begin with the reply code, followed
immediately by <SP>, optionally some text, and <CRLF>.

For example:
123-First line
123-Second line
123-234 text beginning with numbers
123 The last line


On p. 49, sec 4.2.2, "Reply Codes by Function Groups", the RFC lists the various server responses that can be made. (Also Wikipedia has a more pleasantly formatted version of the list at https://en.wikipedia.org/wiki/List_of_SMTP_server_return_codes.)

Synopsis

# Fetching replies

getReply is intended to be the main function used by other modules - it allows fetching and parsing replies from a server. The other functions are lower-level utility functions, and might be useful if you want to customize parsing.

getReply pull

Given some action 'pull' which can be called to supply the parser with more input, attempt to fetch content from the server and parse it as a Reply. On failure, ParseError will be thrown, with a message explaining the failure.

A ParseError will also be thrown if the response looks superficially like a reply, but has multiple reply codes for different lines. (In other words, a successful return value means the reply has at least one line, and all lines have the same reply code.)

The result returned is in the MonadError monad, so can be specialised by the caller to a Maybe, Either, or some other MonadError instance as desired.

# Low-level functions and types

type Parser = Parser Source #

Attoparsec parser type.

A string of length at least 1, which may contain printable US ASCII, characters, space characters, and horizontal tabs.

See RFC 5321, p. 47, "textstring".

The spec in the RFC is

textstring  = 1*(%d09 / %d32-126) ; HT, SP, Printable US-ASCII

>>> :set -XOverloadedStrings
>>> Att.parseOnly (textstring <* Att.endOfInput) "~" -- ASCII 126
Right "~"
>>> Att.parseOnly (textstring <* Att.endOfInput) "\x7f" -- ASCII 127
Left "printable ASCII text: Failed reading: takeWhile1"


The RFC states that an SMTP server SHOULD only send the codes listed in the spec, but we don't validate that here; we accept any sequence of decimal digits, higher-level functions can further validate it if desired.

>>> :set -XOverloadedStrings
>>> Att.parseOnly (code <* Att.endOfInput) "42"
Right 42
>>> Att.parseOnly (code <* Att.endOfInput) "042"
Right 42


One or more server reply lines, terminating with a last line. The parser does not check that they all have the same reply code.

getReply_ pull
Given some action 'pull' which can be called to supply the parser with more input, attempt to fetch input and parse it as a superficially well-formed Reply (multiple lines ending in a terminating line). We don't check that all reply lines have the same reply code.
parseFrom x pull
Given some action 'pull' which can be called to supply the parser with more input, parse thing x and return a result.