imm 0.1.0.0 → 0.1.1.0
raw patch · 8 files changed
+95/−51 lines, 8 filesdep +timerepdep +xdg-basedirPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: timerep, xdg-basedir
API changes (from Hackage documentation)
- Imm.Core: defaultParameters :: Parameters
- Imm.Util: stringToUTC :: String -> Maybe UTCTime
+ Imm.Config: defaultMailDirectory :: PortableFilePath
+ Imm.Config: defaultParameters :: Parameters
+ Imm.Types: RefDirs :: FilePath -> FilePath -> FilePath -> FilePath -> RefDirs
+ Imm.Types: data RefDirs
+ Imm.Types: mConfiguration :: RefDirs -> FilePath
+ Imm.Types: mData :: RefDirs -> FilePath
+ Imm.Types: mHome :: RefDirs -> FilePath
+ Imm.Types: mTemporary :: RefDirs -> FilePath
+ Imm.Types: type PortableFilePath = RefDirs -> FilePath
+ Imm.Util: parseDate :: String -> Maybe UTCTime
+ Imm.Util: resolve :: (RefDirs -> a) -> IO a
- Imm.Mail: itemToMail :: Item -> Mail
+ Imm.Mail: itemToMail :: TimeZone -> Item -> Mail
- Imm.Maildir: add :: FilePath -> Mail -> IO ()
+ Imm.Maildir: add :: PortableFilePath -> Mail -> IO ()
- Imm.Maildir: init :: FilePath -> IO Bool
+ Imm.Maildir: init :: PortableFilePath -> IO Bool
- Imm.Types: Mail :: String -> UTCTime -> String -> String -> String -> String -> String -> String -> Mail
+ Imm.Types: Mail :: String -> Maybe ZonedTime -> String -> String -> String -> String -> String -> String -> Mail
- Imm.Types: Parameters :: Maybe String -> [String] -> FilePath -> Maybe String -> Parameters
+ Imm.Types: Parameters :: Maybe String -> [String] -> PortableFilePath -> Maybe String -> Parameters
- Imm.Types: mDate :: Mail -> UTCTime
+ Imm.Types: mDate :: Mail -> Maybe ZonedTime
- Imm.Types: mMailDirectory :: Parameters -> FilePath
+ Imm.Types: mMailDirectory :: Parameters -> PortableFilePath
Files
- Imm/Config.hs +15/−0
- Imm/Core.hs +10/−19
- Imm/Mail.hs +6/−6
- Imm/Maildir.hs +17/−9
- Imm/Main.hs +1/−0
- Imm/Types.hs +16/−4
- Imm/Util.hs +19/−5
- imm.cabal +11/−8
+ Imm/Config.hs view
@@ -0,0 +1,15 @@+module Imm.Config where++import Imm.Types++-- | Default configuration.+defaultParameters :: Parameters+defaultParameters = Parameters {+ mCacheDirectory = Nothing,+ mFeedURIs = [],+ mMailDirectory = defaultMailDirectory,+ mError = Nothing+}++defaultMailDirectory :: PortableFilePath+defaultMailDirectory = const "feeds"
Imm/Core.hs view
@@ -1,6 +1,7 @@ module Imm.Core where -- {{{ Imports+import Imm.Config import Imm.Mail import qualified Imm.Maildir as Maildir import Imm.Types@@ -15,9 +16,8 @@ import Data.Foldable --import Data.Functor --import Data.Maybe-import Data.Time.Clock+import Data.Time import Data.Time.Clock.POSIX-import Data.Time.Format import Network.HTTP hiding(Response) import Network.URI@@ -62,15 +62,6 @@ showError :: Parameters -> String -> Parameters showError parameters message = parameters { mError = Just message }---- | Default configuration.-defaultParameters :: Parameters-defaultParameters = Parameters {- mCacheDirectory = Nothing,- mFeedURIs = [],- mMailDirectory = "rss",- mError = Nothing-} -- }}} -- | @@ -97,9 +88,7 @@ -- Initialize mailbox result <- Maildir.init directory- case result of- False -> putStrLn $ "Unable to initialize maildir at: " ++ directory- _ -> realMain' parameters+ when result $ realMain' parameters -- At this point, a maildir has been setup. realMain' :: Parameters -> IO ()@@ -129,9 +118,10 @@ -- oldTime <- try $ readFile (directory </> fileName)+ let timeZero = posixSecondsToUTCTime $ 0 let threshold = either- (const $ posixSecondsToUTCTime 0)- (maybe (posixSecondsToUTCTime 0) id . parseTime defaultTimeLocale "%F %T %Z")+ (const timeZero)+ (maybe timeZero id . parseTime defaultTimeLocale "%F %T %Z") oldTime lastTime <- foldlM (\acc item -> processItem parameters threshold item >>= (return . (max acc))) threshold (feedItems feed) @@ -147,6 +137,7 @@ processItem :: Parameters -> UTCTime -> Item -> IO UTCTime processItem parameters@Parameters{ mMailDirectory = directory } threshold item = do currentTime <- getCurrentTime :: IO UTCTime+ timeZone <- getCurrentTimeZone let time = getItemDate item whenLoud . putStr . unlines $ ["",@@ -155,14 +146,14 @@ " Item URI: " ++ (maybe "" id $ getItemLink item), " Item date: " ++ (maybe "" id $ time)] - case time >>= stringToUTC of+ case time >>= parseDate of Just y -> do when (threshold < y) $ do whenLoud . putStrLn $ "==> New entry added to maildir."- Maildir.add directory . itemToMail $ item + Maildir.add directory . itemToMail timeZone $ item return y _ -> do- Maildir.add directory . itemToMail $ item + Maildir.add directory . itemToMail timeZone $ item return threshold downloadRaw :: URI -> IO (Either String String)
Imm/Mail.hs view
@@ -6,28 +6,28 @@ import Control.Monad -import Data.Time.Clock.POSIX+import Data.Time import Text.Feed.Query import Text.Feed.Types -- }}} - + defaultMail :: Mail defaultMail = Mail { mCharset = "utf-8", mContent = "", mContentDisposition = "inline",- mDate = posixSecondsToUTCTime 0,+ mDate = Nothing, mFrom = "imm", mMIME = "text/html", mSubject = "Untitled", mReturnPath = "<imm@noreply>"} -itemToMail :: Item -> Mail-itemToMail item = defaultMail {- mDate = maybe (posixSecondsToUTCTime 0) id . (stringToUTC <=< getItemDate) $ item,+itemToMail :: TimeZone -> Item -> Mail+itemToMail timeZone item = defaultMail {+ mDate = maybe Nothing (Just . utcToZonedTime timeZone) . parseDate <=< getItemDate $ item, mFrom = maybe "Anonymous" id $ getItemAuthor item, mSubject = maybe "Untitled" id $ getItemTitle item, mContent = maybe "Empty" id $ getItemDescription item}
Imm/Maildir.hs view
@@ -3,32 +3,40 @@ -- {{{ Imports import Imm.Mail() import Imm.Types+import Imm.Util import Data.Time.Clock.POSIX import Network.BSD +import System.Console.CmdArgs import System.Directory import System.FilePath import System.IO.Error import System.Random -- }}} -init :: FilePath -> IO Bool+init :: PortableFilePath -> IO Bool init directory = do- root <- try $ createDirectoryIfMissing True directory- cur <- try . createDirectoryIfMissing True . (directory </>) $ "cur"- new <- try . createDirectoryIfMissing True . (directory </>) $ "new"- tmp <- try . createDirectoryIfMissing True . (directory </>) $ "tmp"+ dir <- resolve directory+ root <- try $ createDirectoryIfMissing True dir+ cur <- try . createDirectoryIfMissing True . (dir </>) $ "cur"+ new <- try . createDirectoryIfMissing True . (dir </>) $ "new"+ tmp <- try . createDirectoryIfMissing True . (dir </>) $ "tmp" case (root, cur, new, tmp) of- (Right _, Right _, Right _, Right _) -> return True- _ -> return False+ (Right _, Right _, Right _, Right _) -> do+ whenLoud . putStrLn . ("Maildir correctly created at: " ++) $ dir+ return True+ _ -> do+ whenNormal . putStrLn . ("Unable to initialize maildir at: " ++) $ dir+ return False -add :: FilePath -> Mail -> IO ()+add :: PortableFilePath -> Mail -> IO () add directory mail = do+ dir <- resolve directory fileName <- getUniqueName- writeFile (directory </> "new" </> fileName) (show mail)+ writeFile (dir </> "new" </> fileName) (show mail) getUniqueName :: IO String
Imm/Main.hs view
@@ -1,5 +1,6 @@ module Main where +import Imm.Config import Imm.Core --import Imm.Types
Imm/Types.hs view
@@ -4,7 +4,8 @@ -- {{{ Imports import Network.URI -import Data.Time.Clock+import Data.Time+import Data.Time.RFC2822 import System.Console.CmdArgs @@ -20,7 +21,7 @@ data Parameters = Parameters { mCacheDirectory :: Maybe String, mFeedURIs :: [String], -- ^ Feeds list- mMailDirectory :: FilePath,+ mMailDirectory :: PortableFilePath, mError :: Maybe String -- ^ Error } @@ -31,7 +32,7 @@ data Mail = Mail { mReturnPath :: String,- mDate :: UTCTime,+ mDate :: Maybe ZonedTime, mFrom :: String, mSubject :: String, mMIME :: String,@@ -43,10 +44,21 @@ instance Show Mail where show mail = unlines [ "Return-Path: " ++ mReturnPath mail,- "Date: " ++ (show $ mDate mail),+ maybe "" (("Date: " ++) . showRFC2822) . mDate $ mail, "From: " ++ mFrom mail, "Subject: " ++ mSubject mail, "Content-Type: " ++ mMIME mail ++ "; charset=" ++ mCharset mail, "Content-Disposition: " ++ mContentDisposition mail, "", mContent mail]++-- | Set of reference directories, typically used to build FilePath-s+data RefDirs = RefDirs {+ mHome :: FilePath, -- ^ Home directory+ mTemporary :: FilePath, -- ^ Temporary files directory+ mConfiguration :: FilePath, -- ^ Configuration directory+ mData :: FilePath -- ^ Data directory+}++type PortableFilePath = RefDirs -> FilePath+
Imm/Util.hs view
@@ -1,22 +1,36 @@ module Imm.Util where -- {{{ Imports+import Imm.Types+ import Codec.Binary.UTF8.String -import Data.Time.Clock-import Data.Time.Format+import Data.Maybe+import Data.Time+import Data.Time.RFC2822+import Data.Time.RFC3339 --import Network.URI -import System.Locale+import System.Directory+import System.Environment.XDG.BaseDir -- }}} +resolve :: (RefDirs -> a) -> IO a+resolve f = do+ homeDir <- getHomeDirectory+ tmpDir <- getTemporaryDirectory+ configDir <- getUserConfigDir "hbro"+ dataDir <- getUserDataDir "hbro"+ + return . f $ RefDirs homeDir tmpDir configDir dataDir+ escapeFileName :: Char -> String escapeFileName '/' = "|" escapeFileName x = x:[] -stringToUTC :: String -> Maybe UTCTime-stringToUTC = parseTime defaultTimeLocale "%a, %e %b %Y %T %z"+parseDate :: String -> Maybe UTCTime+parseDate date = listToMaybe . map zonedTimeToUTC . catMaybes . map ((flip ($)) date) $ [readRFC2822, readRFC3339] decodeIfNeeded :: String -> String decodeIfNeeded text = case isUTF8Encoded text of
imm.cabal view
@@ -1,5 +1,5 @@ Name: imm-Version: 0.1.0.0+Version: 0.1.1.0 Synopsis: RSS-to-maildir tool --Description: --Homepage:@@ -21,6 +21,7 @@ Library Exposed-modules:+ Imm.Config, Imm.Core, Imm.Types, Imm.Util,@@ -28,21 +29,23 @@ Imm.Maildir Build-depends: base == 4.*,+ bytestring,+ cmdargs, directory, dyre, feed, filepath, HTTP,- time,- xml,+ mime-mail,+ network, old-locale, random,- bytestring,- mime-mail, text,- cmdargs,- network,- utf8-string+ time,+ timerep,+ utf8-string,+ xdg-basedir,+ xml -- Other-modules: -- Build-tools: