diff options
Diffstat (limited to 'lib/Postdelay')
-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 | ] |