packages feed

danecheck-1.0.0.0: Dane/Scanner/SMTP/Parse.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

module Dane.Scanner.SMTP.Parse (SmtpReply(..), parseReply)
  where

import           Control.Applicative ( (<|>) )
import           Control.Monad (mzero)
import           Data.Attoparsec.ByteString.Char8 (Parser, parseOnly)
import qualified Data.Attoparsec.ByteString.Char8 as AP
import qualified Data.ByteString.Char8 as BC
import           Data.Char (ord)
import           Data.Either (isLeft)

import           Dane.Scanner.SMTP.Internal

digit :: Parser Int
digit = do
  c <- AP.satisfy AP.isDigit
  return $ ord(c) - ord('0')

space :: Parser Char
space = AP.char ' '

hyphen :: Parser Char
hyphen = AP.char '-'

textchar :: Parser BC.ByteString
textchar = do
  c <- AP.satisfy $ (&&) <$> (/= '\r') <*> (/= '\n')
  return $ BC.singleton c

barecr :: Parser BC.ByteString
barecr = do
  c <- AP.char '\r' *> AP.peekChar
  case c of
    Just '\n' -> mzero
    _ -> return $ BC.singleton '\r'

text :: Parser BC.ByteString
text = do
  chunks <- AP.many' $ (textchar <|> barecr)
  return $ mconcat chunks

parser :: Parser SmtpReply
parser = do
  digits <- AP.count 3 digit
  let replyCode = foldl (\acc x -> 10 * acc + x) 0 digits
  replyCont <- isLeft <$> AP.eitherP hyphen space
  replyText <- text
  AP.endOfLine
  AP.endOfInput
  return $! SmtpReply{..}

parseReply :: BC.ByteString -> Maybe SmtpReply
parseReply reply =
  case (parseOnly parser reply) of
  Right x -> Just x
  Left _  -> Nothing