summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregor Kleen <aethoago@141.li>2017-01-30 13:33:33 +0100
committerGregor Kleen <aethoago@141.li>2017-01-30 13:33:33 +0100
commita45fa188046ab652150d332f48202f0e3fa5ea82 (patch)
tree36d54dbfb82f2127a86b105a27df34339e370d17
parentf5d85473fc1f59dc63f184a118c08af02f025345 (diff)
downloadpostdelay-a45fa188046ab652150d332f48202f0e3fa5ea82.tar
postdelay-a45fa188046ab652150d332f48202f0e3fa5ea82.tar.gz
postdelay-a45fa188046ab652150d332f48202f0e3fa5ea82.tar.bz2
postdelay-a45fa188046ab652150d332f48202f0e3fa5ea82.tar.xz
postdelay-a45fa188046ab652150d332f48202f0e3fa5ea82.zip
Support a X-Timezone header
-rw-r--r--lib/Postdelay/Scan.hs27
-rw-r--r--lib/Postdelay/TimeSpec.hs7
2 files changed, 21 insertions, 13 deletions
diff --git a/lib/Postdelay/Scan.hs b/lib/Postdelay/Scan.hs
index fba9f35..2f0a78a 100644
--- a/lib/Postdelay/Scan.hs
+++ b/lib/Postdelay/Scan.hs
@@ -1,4 +1,4 @@
1{-# LANGUAGE OverloadedStrings, ScopedTypeVariables, FlexibleContexts, RecordWildCards, ViewPatterns #-} 1{-# LANGUAGE OverloadedStrings, ScopedTypeVariables, FlexibleContexts, RecordWildCards, ViewPatterns, TupleSections #-}
2 2
3module Postdelay.Scan 3module Postdelay.Scan
4 ( scan 4 ( scan
@@ -45,24 +45,29 @@ scan :: (MonadIO m, MonadError ParseError m) => String -> m (Maybe Delay)
45scan = fmap getOption . extractDelay <=< either throwError return . parse message "" 45scan = fmap getOption . extractDelay <=< either throwError return . parse message ""
46 46
47extractDelay :: forall m. (MonadIO m, MonadError ParseError m) => Message -> m (Option Delay) 47extractDelay :: forall m. (MonadIO m, MonadError ParseError m) => Message -> m (Option Delay)
48extractDelay (Message headers _) 48extractDelay (Message headers _) = do
49 = let latestCtx = maximumBy (comparing baseTime) dateHeaders 49 zones <- zoneHeaders
50 in foldMap pure <$> mapM (flip runReaderT latestCtx . parseDelay) delayHeaders 50 let (baseTime, dateTz) = maximumBy (comparing fst) dateHeaders
51 tz = foldr' (flip (<>)) (Left dateTz) zones
52 foldMap pure <$> mapM (flip runReaderT TimeCtx{..} . parseDelay) delayHeaders
51 where 53 where
52 delayHeaders :: [Field] 54 delayHeaders :: [Field]
53 delayHeaders = do 55 delayHeaders = do
54 (OptionalField field content) <- headers 56 (OptionalField field content) <- headers
55 guard $ CI.mk field == "X-Delay" 57 guard $ CI.mk field == "X-Delay"
56 return . OptionalField field $ decodeWords content 58 return . OptionalField field $ decodeWords content
57 dateHeaders :: [TimeCtx] 59 dateHeaders :: [(UTCTime, TimeZone)]
58 dateHeaders = do 60 dateHeaders = do
59 (Date CalendarTime{..}) <- headers 61 (Date CalendarTime{..}) <- headers
60 let tz = minutesToTimeZone . round $ ctTZ % 60 62 let tz = minutesToTimeZone . round $ ctTZ % 60
61 return $ TimeCtx 63 return . (, tz) . localTimeToUTC tz $ LocalTime
62 { baseTime = localTimeToUTC tz $ LocalTime 64 (fromGregorian (fromIntegral ctYear) (fromEnum ctMonth + 1) ctDay)
63 (fromGregorian (fromIntegral ctYear) (fromEnum ctMonth + 1) ctDay) 65 (TimeOfDay ctHour ctMin $ fromIntegral ctSec + fromIntegral ctPicosec * 1e-12)
64 (TimeOfDay ctHour ctMin $ fromIntegral ctSec + fromIntegral ctPicosec * 1e-12) 66 zoneHeaders :: m [Either TimeZone TZ]
65 , tz = Left tz 67 zoneHeaders = runListT $ do
66 } 68 (OptionalField field content) <- ListT $ return headers
69 guard $ CI.mk field == "X-Timezone"
70 Right r <- runParserT (spaces *> pTimeZone <* spaces <* eof) () field content
71 return r
67 parseDelay :: Field -> ReaderT TimeCtx m Delay 72 parseDelay :: Field -> ReaderT TimeCtx m Delay
68 parseDelay (OptionalField field content) = either throwError return =<< runParserT (Until <$> pTimeSpec) () field content 73 parseDelay (OptionalField field content) = either throwError return =<< runParserT (Until <$> pTimeSpec) () field content
diff --git a/lib/Postdelay/TimeSpec.hs b/lib/Postdelay/TimeSpec.hs
index af8d801..676dabf 100644
--- a/lib/Postdelay/TimeSpec.hs
+++ b/lib/Postdelay/TimeSpec.hs
@@ -2,6 +2,7 @@
2 2
3module Postdelay.TimeSpec 3module Postdelay.TimeSpec
4 ( pTimeSpec 4 ( pTimeSpec
5 , pTimeZone
5 , TimeCtx(..) 6 , TimeCtx(..)
6 ) where 7 ) where
7 8
@@ -308,7 +309,7 @@ pTimeBase = choice' [ do
308 pMinute = ensure (< 60) =<< natural 309 pMinute = ensure (< 60) =<< natural
309 pSecond = decimal 310 pSecond = decimal
310 311
311pTimeZone :: MonadTP m => ParsecT String () m (Either TimeZone TZ) 312pTimeZone :: MonadIO m => ParsecT String () m (Either TimeZone TZ)
312pTimeZone = choice' [ do 313pTimeZone = choice' [ do
313 sgn <- choice [ id <$ char '+' 314 sgn <- choice [ id <$ char '+'
314 , negate <$ char '-' 315 , negate <$ char '-'
@@ -317,7 +318,9 @@ pTimeZone = choice' [ do
317 ms <- option 0 $ (\d u -> 10 * d + u) <$> digit <*> digit 318 ms <- option 0 $ (\d u -> 10 * d + u) <$> digit <*> digit
318 return . Left . minutesToTimeZone $ hs * 60 + ms 319 return . Left . minutesToTimeZone $ hs * 60 + ms
319 , do 320 , do
320 n <- many1 $ letter <|> char '/' 321 let
322 ident = (++) <$> many1 alphaNum <*> option "" ((:) <$> oneOf "_-/.+" <*> ident)
323 n <- ident
321 tz <- liftIO $ do 324 tz <- liftIO $ do
322 let 325 let
323 fbHandler :: IO a -> (IOException -> IO a) 326 fbHandler :: IO a -> (IOException -> IO a)