content: module Network.IMAP.Parsers where
  
  import Network.IMAP.Types
  import Network.IMAP.Parsers.Fetch
  import Network.IMAP.Parsers.Utils
  import Network.IMAP.Parsers.Untagged
  
  
  import Data.Attoparsec.ByteString
  import qualified Data.Attoparsec.ByteString as AP
  import Data.Word8
  
  import qualified Data.Text.Encoding as T
  
  import Control.Applicative
  
  parseReply :: Parser (Either ErrorMessage CommandResult)
  parseReply = parseFetch <|> parseLine
  
  parseLine :: Parser (Either ErrorMessage CommandResult)
  parseLine = do
    many $ string "\r\n"
  
    -- WARNING: We are not actually waiting for go ahead here :P
    skipMany $ string "+ go ahead\r\n"
    parsed <- parseUntagged <|> parseTagged
    string "\r\n"
    return parsed
  
  parseTagged :: Parser (Either ErrorMessage CommandResult)
  parseTagged = do
    requestId <- takeWhile1 isLetter
    word8 _space
  
    commandState <- takeWhile1 isLetter
    word8 _space
  
    rest <- T.decodeUtf8 <$> takeWhile1 (/= _cr)
    let state = case commandState of
                  "OK" -> OK
                  "NO" -> NO
                  "BAD" -> BAD
                  _ -> BAD
  
    return . Right . Tagged $ TaggedResult requestId state rest
  
  parseUntagged :: Parser (Either ErrorMessage CommandResult)
  parseUntagged = do
    string "* "
    result <- parseFlags <|>
              parseExists <|>
              parseHighestModSeq <|>
              parseRecent <|>
              parseUnseen <|>
              (Right <$> parsePermanentFlags) <|>
              parseUidNext <|>
              parseUidValidity <|>
              parseCapabilityList <|>
              (Right <$> parseOk) <|>
              (Right <$> parseNo) <|>
              (Right <$> parseBad) <|>
              (Right <$> parseBye) <|>
              (Right <$> parseListLikeResp "LIST") <|>
              (Right <$> parseListLikeResp "LSUB") <|>
              parseStatus <|>
              parseExpunge <|>
              parseSearchResult
  
    -- Take the rest
    _ <- AP.takeWhile (/= _cr)
    return $ result >>= Right . Untagged
  