carboncopy-0.1: CarbonCopy/ThreadBuilder.hs
{-# OPTIONS_GHC -XTypeSynonymInstances -XMultiParamTypeClasses #-}
module CarbonCopy.ThreadBuilder (
headerVal,
saveMatchingChain,
Chain(..),
prepareChain,
matchFromHeader,
MsgidChain) where
import Control.Monad
import CarbonCopy.MailHeaders
import CarbonCopy.HeadersStorage
import Data.Maybe
import Data.ByteString.Char8 as BStr
import Text.ParserCombinators.ReadP as R
import Data.List as L
import Prelude as P
data Chain keyT valueT = Chain { current, previous :: Header keyT valueT} | Root { current :: Header keyT valueT }
type MsgidChain = Chain String String
saveMatchingChain :: Storage (Header keyT valueT) -> Chain keyT valueT -> IO (Bool)
saveMatchingChain storage
( Chain { current=myCurrent, previous=myPrevious } ) = do
prevHdrExists <- storage `hdrExists` myPrevious
currHdrExists <- storage `hdrExists` myCurrent
when (prevHdrExists && not currHdrExists) $ storage `hdrAdd` myCurrent
return ( prevHdrExists || currHdrExists )
saveMatchingChain storage _ = return False
findHeaderByName :: String -> [StrHeader] -> Maybe (StrHeader)
findHeaderByName hdrName = L.find ( (hdrName ==) . name )
prepareChain :: [StrHeader] -> Maybe (MsgidChain)
prepareChain hdrs = processNextHeader $ findHeaderByName in_reply_to_hdr hdrs
where
processNextHeader (Just inReplyToHdr) = do
msgIdHdr <- findHeaderByName msg_id_hdr hdrs
Just (Chain msgIdHdr inReplyToHdr)
processNextHeader Nothing = do
msgIdHdr <- findHeaderByName msg_id_hdr hdrs
Just (Root msgIdHdr)
matchFromHeader :: ByteString -> String -> ( Maybe MsgidChain, Bool )
matchFromHeader content email = ( chain, hdrsMatchFound )
where
headers = visitHeader content
hdrsMatchFound = or $ P.map hdrMatch headers
chain = prepareChain headers
hdrMatch (Header name value) = name == from_hdr && email `L.isInfixOf` value
visitHeader :: ByteString -> [StrHeader]
visitHeader = flip extractHeaders (
headerValue from_hdr +++
headerVal msg_id_hdr +++
headerVal in_reply_to_hdr
)
headerValue :: String -> ReadP StrHeader
headerValue hdrName = do
R.string hdrName
R.skipSpaces
R.char ':'
R.skipSpaces
xs <- R.many R.get
R.satisfy ( == '\n' )
return (Header hdrName xs)
headerVal :: String -> ReadP StrHeader
headerVal name = do
R.string name
R.skipSpaces
R.char ':'
R.skipSpaces
R.char '<'
xs <- R.many R.get
R.char '>'
return (Header name xs)