module Network.IMAP.Utils where import Network.IMAP.Types import qualified Data.ByteString.Char8 as BSC import System.Random import qualified Data.Text as T import Data.Text.Encoding (encodeUtf8) import Control.Monad.STM import Control.Concurrent.STM.TQueue import Control.Concurrent.STM.TVar import Control.Monad (MonadPlus(..)) import Control.Monad.IO.Class (MonadIO(..)) import Control.Concurrent.STM.Delay genRequestId :: IO BSC.ByteString genRequestId = do randomGen <- newStdGen return $ BSC.pack . Prelude.take 9 $ randomRs ('a', 'z') randomGen readResults :: (MonadPlus m, MonadIO m, Universe m) => IMAPState -> ResponseRequest -> m CommandResult readResults state req@(ResponseRequest resultsQueue requestId) = do let timeout = imapTimeout . imapSettings $ state let reqs = outstandingReqs state delay <- liftIO . newDelay $ timeout * 1000000 let d_wait = do didComplete <- tryWaitDelay delay if didComplete then do -- Remove current request from the list of outstanding ones allReqs <- readTVar reqs writeTVar reqs $ filter (/=req) allReqs return . Tagged $ TaggedResult { commandId=requestId, resultState=BAD, resultRest="Connection timeout" } else retry readResult = readTQueue resultsQueue nextResult <- liftIO . atomically $ d_wait `orElse` readResult case nextResult of Tagged _ -> return nextResult Untagged _ -> return nextResult `mplus` readResults state req escapeText :: T.Text -> T.Text escapeText t = T.replace "{" "\\{" $ T.replace "}" "\\}" $ T.replace "\"" "\\\"" $ T.replace "\\" "\\\\" t ifNotDisconnected :: (MonadPlus m, MonadIO m) => IMAPConnection -> m CommandResult -> m CommandResult ifNotDisconnected conn action = do connState <- liftIO . atomically . readTVar $ connectionState conn if isDisconnected connState then return . Tagged $ TaggedResult { commandId = "noid", resultState = BAD, resultRest = "Cannot post a command when watcher is disconnected" } else action flagsToText :: [Flag] -> BSC.ByteString flagsToText flagList = BSC.concat ["(", encodedFlags, ")"] where encodedFlags = BSC.intercalate " " textFlags textFlags = flip map flagList (\case FSeen -> "\\Seen" FAnswered -> "\\Answered" FFlagged -> "\\Flagged" FDeleted -> "\\Deleted" FDraft -> "\\Draft" FRecent -> "\\Recent" FAny -> "*" FOther t -> encodeUtf8 t)