module Network.Mail.SMTP.ReplyLine (
ReplyLine
, Greeting
, replyCode
, greeting
, replyLines
) where
import qualified Data.ByteString as B
import Data.Attoparsec.ByteString.Char8
import Control.Applicative
import Network.Mail.SMTP.Types
data ReplyLine = ReplyLine !ReplyCode !B.ByteString
deriving (Show)
replyCode :: ReplyLine -> ReplyCode
replyCode (ReplyLine x _) = x
data Greeting = Greeting !B.ByteString ![B.ByteString]
deriving (Show)
crlf :: Parser ()
crlf = char '\r' >> char '\n' >> pure ()
textstring :: Parser B.ByteString
textstring = takeWhile1 predicate
where
predicate c' = let c = fromEnum c' in c == 9 || (c >= 32 && c <= 126)
replyLines :: Parser [ReplyLine]
replyLines = (++) <$> many' replyLine' <*> (pure <$> replyLine)
replyLine :: Parser ReplyLine
replyLine = ReplyLine <$> code <* space <*> option "" textstring <* crlf
replyLine' :: Parser ReplyLine
replyLine' = ReplyLine <$> code <* char '-' <*> option "" textstring <* crlf
code :: Parser ReplyCode
code = decimal
greeting :: Parser Greeting
greeting = manyGreetings <|> oneGreeting
where
oneGreeting :: Parser Greeting
oneGreeting = do
string "220 "
bytestring <- takeWhile1 isASCIIPrintableNonWhitespace
messages <- option [] (char ' ' *> (pure <$> textstring))
crlf
return $ Greeting bytestring messages
manyGreetings :: Parser Greeting
manyGreetings = do
string "220-"
bytestring <- takeWhile1 isASCIIPrintableNonWhitespace
greets <- option [] (char ' ' *> (pure <$> textstring))
crlf
moreGreets <- many (string "220-" *> textstring <* crlf)
string "220"
lastgreet <- option [] (pure <$> (char ' ' >> textstring))
let messages = greets ++ moreGreets ++ lastgreet
return $ Greeting bytestring messages
isASCIIPrintableNonWhitespace :: Char -> Bool
isASCIIPrintableNonWhitespace c' = let c = fromEnum c' in c > 32 && c <= 126