diff options
| author | Gregor Kleen <aethoago@141.li> | 2017-01-30 13:33:33 +0100 | 
|---|---|---|
| committer | Gregor Kleen <aethoago@141.li> | 2017-01-30 13:33:33 +0100 | 
| commit | a45fa188046ab652150d332f48202f0e3fa5ea82 (patch) | |
| tree | 36d54dbfb82f2127a86b105a27df34339e370d17 /lib | |
| parent | f5d85473fc1f59dc63f184a118c08af02f025345 (diff) | |
| download | postdelay-a45fa188046ab652150d332f48202f0e3fa5ea82.tar postdelay-a45fa188046ab652150d332f48202f0e3fa5ea82.tar.gz postdelay-a45fa188046ab652150d332f48202f0e3fa5ea82.tar.bz2 postdelay-a45fa188046ab652150d332f48202f0e3fa5ea82.tar.xz postdelay-a45fa188046ab652150d332f48202f0e3fa5ea82.zip | |
Support a X-Timezone header
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Postdelay/Scan.hs | 27 | ||||
| -rw-r--r-- | lib/Postdelay/TimeSpec.hs | 7 | 
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 | ||
| 3 | module Postdelay.Scan | 3 | module Postdelay.Scan | 
| 4 | ( scan | 4 | ( scan | 
| @@ -45,24 +45,29 @@ scan :: (MonadIO m, MonadError ParseError m) => String -> m (Maybe Delay) | |||
| 45 | scan = fmap getOption . extractDelay <=< either throwError return . parse message "" | 45 | scan = fmap getOption . extractDelay <=< either throwError return . parse message "" | 
| 46 | 46 | ||
| 47 | extractDelay :: forall m. (MonadIO m, MonadError ParseError m) => Message -> m (Option Delay) | 47 | extractDelay :: forall m. (MonadIO m, MonadError ParseError m) => Message -> m (Option Delay) | 
| 48 | extractDelay (Message headers _) | 48 | extractDelay (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 | ||
| 3 | module Postdelay.TimeSpec | 3 | module 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 | ||
| 311 | pTimeZone :: MonadTP m => ParsecT String () m (Either TimeZone TZ) | 312 | pTimeZone :: MonadIO m => ParsecT String () m (Either TimeZone TZ) | 
| 312 | pTimeZone = choice' [ do | 313 | pTimeZone = 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) | 
