diff options
| author | Gregor Kleen <aethoago@141.li> | 2017-03-08 14:39:38 +0100 |
|---|---|---|
| committer | Gregor Kleen <aethoago@141.li> | 2017-03-08 14:39:38 +0100 |
| commit | b78644e2fe649207d81a89d0af36988aed110104 (patch) | |
| tree | 3bf68d64f91a56858f78763eda1b3f69ee20ff17 /lib | |
| parent | c6f1f8c512e8dbca953cb43c11a08c6fcf54f6d3 (diff) | |
| download | postdelay-b78644e2fe649207d81a89d0af36988aed110104.tar postdelay-b78644e2fe649207d81a89d0af36988aed110104.tar.gz postdelay-b78644e2fe649207d81a89d0af36988aed110104.tar.bz2 postdelay-b78644e2fe649207d81a89d0af36988aed110104.tar.xz postdelay-b78644e2fe649207d81a89d0af36988aed110104.zip | |
Framework for spooling
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Postdelay/Queue.hs | 108 | ||||
| -rw-r--r-- | lib/Postdelay/Scan.hs | 1 | ||||
| -rw-r--r-- | lib/Postdelay/TimeSpec.hs | 2 |
3 files changed, 109 insertions, 2 deletions
diff --git a/lib/Postdelay/Queue.hs b/lib/Postdelay/Queue.hs new file mode 100644 index 0000000..ac760ec --- /dev/null +++ b/lib/Postdelay/Queue.hs | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | {-# LANGUAGE RankNTypes, RecordWildCards, ApplicativeDo, FlexibleContexts #-} | ||
| 2 | |||
| 3 | module Postdelay.Queue | ||
| 4 | ( sendmail | ||
| 5 | , StoredMailF(..) | ||
| 6 | , StoredMail, StoredMail' | ||
| 7 | , sendStored, sendStored' | ||
| 8 | , StoreConfig, storeConfig | ||
| 9 | , pushStore, popStore | ||
| 10 | ) where | ||
| 11 | |||
| 12 | import Postdelay.Types | ||
| 13 | |||
| 14 | import Control.Monad.IO.Class (MonadIO(..)) | ||
| 15 | import Control.Monad.Catch (handle, MonadThrow(throwM)) | ||
| 16 | import Control.Monad.Trans.Maybe | ||
| 17 | import Control.Monad.Reader | ||
| 18 | import Control.Monad.Trans.Class | ||
| 19 | import Control.Monad | ||
| 20 | |||
| 21 | import System.IO (hClose, stderr) | ||
| 22 | import System.IO.Error | ||
| 23 | import GHC.IO.Exception | ||
| 24 | import System.Process | ||
| 25 | |||
| 26 | import Data.ByteString.Lazy as Lazy (ByteString) | ||
| 27 | import qualified Data.ByteString.Lazy as Lazy.BS | ||
| 28 | |||
| 29 | import Foreign.C.Error (Errno(..), ePIPE) | ||
| 30 | |||
| 31 | import Data.Bool | ||
| 32 | import Data.Conduit | ||
| 33 | import Data.Time | ||
| 34 | |||
| 35 | import qualified Options.Applicative as Opt (Parser) | ||
| 36 | import Options.Applicative hiding (Parser) | ||
| 37 | |||
| 38 | |||
| 39 | data StoredMailF a = StoredMail | ||
| 40 | { sendDelay :: Delay | ||
| 41 | , sender :: String | ||
| 42 | , recipients :: [String] | ||
| 43 | , message :: a | ||
| 44 | } | ||
| 45 | |||
| 46 | type StoredMail = StoredMailF Lazy.ByteString | ||
| 47 | type StoredMail' = StoredMailF (IO Lazy.ByteString) | ||
| 48 | |||
| 49 | data StoreConfig = StoreConfig | ||
| 50 | { storeLocation :: FilePath | ||
| 51 | } | ||
| 52 | |||
| 53 | |||
| 54 | storeConfig :: Opt.Parser StoreConfig | ||
| 55 | storeConfig = do | ||
| 56 | storeLocation <- strOption $ mconcat | ||
| 57 | [ long "spool" | ||
| 58 | , short 's' | ||
| 59 | , metavar "PATH" | ||
| 60 | , help "Where to expect the mail spool" | ||
| 61 | ] | ||
| 62 | pure StoreConfig{..} | ||
| 63 | |||
| 64 | |||
| 65 | sendmail' :: MonadIO m | ||
| 66 | => [String] -- ^ Arguments to sendmail | ||
| 67 | -> Lazy.ByteString -- ^ Message | ||
| 68 | -> m () | ||
| 69 | sendmail' args mail = liftIO . withCreateProcess cp $ \(Just inh) _ _ pHandle -> do | ||
| 70 | ignoreSigPipe $ do | ||
| 71 | Lazy.BS.hPutStr inh mail | ||
| 72 | hClose inh | ||
| 73 | |||
| 74 | ret <- waitForProcess pHandle | ||
| 75 | bool throwM (\_ -> return ()) (ret == ExitSuccess) $ ret | ||
| 76 | where | ||
| 77 | cp = (proc "sendmail" args) | ||
| 78 | { std_in = CreatePipe | ||
| 79 | } | ||
| 80 | ignoreSigPipe = handle $ \e -> case e of | ||
| 81 | IOError { ioe_type = ResourceVanished | ||
| 82 | , ioe_errno = Just ioe } | ||
| 83 | | Errno ioe == ePIPE -> return () | ||
| 84 | _ -> throwM e | ||
| 85 | |||
| 86 | sendmail :: MonadIO m | ||
| 87 | => String -- ^ Sender | ||
| 88 | -> [String] -- ^ Recipients | ||
| 89 | -> Lazy.ByteString -- ^ Message | ||
| 90 | -> m () | ||
| 91 | sendmail sender recipients = sendmail' $ ["-G", "-i", "-f", sender, "--"] ++ recipients | ||
| 92 | |||
| 93 | sendStored :: MonadIO m => StoredMail -> m () | ||
| 94 | sendStored StoredMail{ sendDelay = Until{..}, ..} = void . runMaybeT $ do | ||
| 95 | now <- liftIO getCurrentTime | ||
| 96 | guard $ now >= releaseTime | ||
| 97 | lift $ sendmail sender recipients message | ||
| 98 | |||
| 99 | sendStored' :: MonadIO m => StoredMail' -> m () | ||
| 100 | sendStored' StoredMail{..} = do | ||
| 101 | message' <- liftIO message | ||
| 102 | sendStored StoredMail{ message = message', .. } | ||
| 103 | |||
| 104 | popStore :: (MonadIO m, MonadReader StoreConfig m) => Source m StoredMail' | ||
| 105 | popStore = undefined | ||
| 106 | |||
| 107 | pushStore :: (MonadIO m, MonadReader StoreConfig m) => Source m StoredMail -> m () | ||
| 108 | pushStore = undefined | ||
diff --git a/lib/Postdelay/Scan.hs b/lib/Postdelay/Scan.hs index 7f80818..6355928 100644 --- a/lib/Postdelay/Scan.hs +++ b/lib/Postdelay/Scan.hs | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | module Postdelay.Scan | 3 | module Postdelay.Scan |
| 4 | ( scan | 4 | ( scan |
| 5 | , Delay(..) | 5 | , Delay(..) |
| 6 | , ParseError(..) | ||
| 7 | ) where | 6 | ) where |
| 8 | 7 | ||
| 9 | import Postdelay.Types | 8 | import Postdelay.Types |
diff --git a/lib/Postdelay/TimeSpec.hs b/lib/Postdelay/TimeSpec.hs index 951b1c0..f61d84e 100644 --- a/lib/Postdelay/TimeSpec.hs +++ b/lib/Postdelay/TimeSpec.hs | |||
| @@ -124,7 +124,7 @@ dateSpec = label "Date" $ (>> scribe (prio' Default . time) midnight) <$> choice | |||
| 124 | scribe (prio' Assign . date.days) 1 | 124 | scribe (prio' Assign . date.days) 1 |
| 125 | ] | 125 | ] |
| 126 | , try $ do | 126 | , try $ do |
| 127 | let daySuffix = optional $ choice [ string' "st", string' "nd", string' "rd", string' "th" ] | 127 | let daySuffix = optional $ choice [ string ".", string' "st", string' "nd", string' "rd", string' "th" ] |
| 128 | (m, d) <- choice [ try $ (,) <$> monthName <* spaces <*> dayNumber False <* daySuffix | 128 | (m, d) <- choice [ try $ (,) <$> monthName <* spaces <*> dayNumber False <* daySuffix |
| 129 | , try $ flip (,) <$> dayNumber False <* daySuffix <* spaces <*> monthName | 129 | , try $ flip (,) <$> dayNumber False <* daySuffix <* spaces <*> monthName |
| 130 | ] | 130 | ] |
