{-# LANGUAGE OverloadedStrings #-} -- | Reading common header fields. -- This module is intended to be imported qualified: -- -- > import qualified Network.Email.Header.Read as H module Network.Email.Header.Read ( -- * Parsing field , structuredField -- * Origination date field , date -- * Originator fields , from , sender , replyTo -- * Destination address fields , to , cc , bcc -- * Identification fields , messageID , inReplyTo , references -- * Informational fields , subject , comments , keywords -- * Resent fields , resentDate , resentFrom , resentSender , resentTo , resentCc , resentBcc , resentMessageID -- * MIME fields , mimeVersion , contentType , contentTransferEncoding , contentID ) where import Control.Applicative import Control.Monad.Catch import Data.Attoparsec.Combinator import Data.Attoparsec.Lazy import qualified Data.ByteString as B import Data.CaseInsensitive (CI) import qualified Data.Text.Lazy as L import Data.Time.LocalTime import qualified Network.Email.Header.Parser as P import Network.Email.Header.Types -- | Lookup and parse a header with a parser. field :: MonadThrow m => HeaderName -> Parser a -> Headers -> m a field k p hs = do body <- case lookup k hs of Nothing -> throwM $ MissingHeader k Just b -> return b case parse p body of Fail _ _ s -> throwM $ HeaderParseError (k, body) s Done _ a -> return a -- | Lookup and parse a structured header with a parser. This skips initial -- comments and folding white space, and ensures that the entire body is -- consumed by the parser. structuredField :: MonadThrow m => HeaderName -> Parser a -> Headers -> m a structuredField k p = field k (P.cfws *> p <* endOfInput) -- | Get the value of the @Date:@ field. date :: MonadThrow m => Headers -> m ZonedTime date = structuredField "Date" P.dateTime -- | Get the value of the @From:@ field. from :: MonadThrow m => Headers -> m [Mailbox] from = structuredField "From" P.mailboxList -- | Get the value of the @Sender:@ field. sender :: MonadThrow m => Headers -> m Mailbox sender = structuredField "Sender" P.mailbox -- | Get the value of the @Reply-To:@ field. replyTo :: MonadThrow m => Headers -> m [Recipient] replyTo = structuredField "Reply-To" P.recipientList -- | Get the value of the @To:@ field. to :: MonadThrow m => Headers -> m [Recipient] to = structuredField "To" P.recipientList -- | Get the value of the @Cc:@ field. cc :: MonadThrow m => Headers -> m [Recipient] cc = structuredField "Cc" P.recipientList -- | Get the value of the @Bcc:@ field. bcc :: MonadThrow m => Headers -> m (Maybe [Recipient]) bcc = structuredField "Bcc" (optional P.recipientList) -- | Get the value of the @Message-ID:@ field. messageID :: MonadThrow m => Headers -> m MessageID messageID = structuredField "Message-ID" P.messageID -- | Get the value of the @In-Reply-To:@ field. inReplyTo :: MonadThrow m => Headers -> m [MessageID] inReplyTo = structuredField "In-Reply-To" (many1 P.messageID) -- | Get the value of the @References:@ field. references :: MonadThrow m => Headers -> m [MessageID] references = structuredField "References" (many1 P.messageID) -- | Get the value of the @Subject:@ field. subject :: MonadThrow m => Headers -> m L.Text subject = field "Subject" P.unstructured -- | Get the value of the @Comments:@ field. comments :: MonadThrow m => Headers -> m L.Text comments = field "Comments" P.unstructured -- | Get the value of the @Keywords:@ field. keywords :: MonadThrow m => Headers -> m [L.Text] keywords = structuredField "Keywords" P.phraseList -- | Get the value of the @Resent-Date:@ field. resentDate :: MonadThrow m => Headers -> m ZonedTime resentDate = structuredField "Resent-Date" P.dateTime -- | Get the value of the @Resent-From:@ field. resentFrom :: MonadThrow m => Headers -> m [Mailbox] resentFrom = structuredField "Resent-From" P.mailboxList -- | Get the value of the @Resent-Sender:@ field. resentSender :: MonadThrow m => Headers -> m Mailbox resentSender = structuredField "Resent-Sender" P.mailbox -- | Get the value of the @Resent-To:@ field. resentTo :: MonadThrow m => Headers -> m [Recipient] resentTo = structuredField "Resent-To" P.recipientList -- | Get the value of the @Resent-Cc:@ field. resentCc :: MonadThrow m => Headers -> m [Recipient] resentCc = structuredField "Resent-Cc" P.recipientList -- | Get the value of the @Resent-Bcc:@ field. resentBcc :: MonadThrow m => Headers -> m (Maybe [Recipient]) resentBcc = structuredField "Resent-Bcc" (optional P.recipientList) -- | Get the value of the @Resent-Message-ID:@ field. resentMessageID :: MonadThrow m => Headers -> m MessageID resentMessageID = structuredField "Resent-Message-ID" P.messageID -- | Get the value of the @MIME-Version:@ field. mimeVersion :: MonadThrow m => Headers -> m (Int, Int) mimeVersion = structuredField "MIME-Version" P.mimeVersion -- | Get the value of the @Content-Type:@ field. contentType :: MonadThrow m => Headers -> m (MimeType, Parameters) contentType = structuredField "Content-Type" P.contentType -- | Get the value of the @Content-Transfer-Encoding:@ field. contentTransferEncoding :: MonadThrow m => Headers -> m (CI B.ByteString) contentTransferEncoding = structuredField "Content-Transfer-Encoding" P.contentTransferEncoding -- | Get the value of the @Content-ID:@ field. contentID :: MonadThrow m => Headers -> m MessageID contentID = structuredField "Content-ID" P.messageID