packages feed

mbox-tools-0.2.0.0: mbox-list.hs

{-# LANGUAGE TemplateHaskell, TypeOperators #-}
--------------------------------------------------------------------
-- |
-- Executable : mbox-list
-- Copyright : (c) Nicolas Pouillard 2008, 2009, 2011
-- License   : BSD3
--
-- Maintainer: Nicolas Pouillard <nicolas.pouillard@gmail.com>
-- Stability : provisional
-- Portability:
--
--------------------------------------------------------------------

import Prelude
import Control.Arrow
import Codec.Mbox (Mbox(..),Direction(..),parseMboxFiles,mboxMsgBody,opposite)
import Email (readEmail)
import EmailFmt (putEmails,ShowFormat(..),fmtOpt,defaultShowFormat,showFormatsDoc)
import System.Environment (getArgs)
import System.Console.GetOpt
import Data.Label

data Settings = Settings { _fmt      :: ShowFormat
                         , _dir      :: Direction
                         , _takeOpt  :: Maybe Int
                         , _dropOpt  :: Maybe Int
                         , _help     :: Bool
                         }
$(mkLabels [''Settings])

type Flag = Settings -> Settings

listMbox :: Settings -> [String] -> IO ()
listMbox opts mboxfiles =
  mapM_ (putEmails (get fmt opts) .
         map ((readEmail . get mboxMsgBody) &&& id) .
         maybe id take (get takeOpt opts) .
         maybe id drop (get dropOpt opts) .
         mboxMessages)
    =<< parseMboxFiles (get dir opts) mboxfiles

defaultSettings :: Settings
defaultSettings = Settings { _fmt      = defaultShowFormat
                           , _dir      = Forward
                           , _takeOpt  = Nothing
                           , _dropOpt  = Nothing
                           , _help     = False
                           }

usage :: String -> a
usage msg = error $ unlines [msg, usageInfo header options, showFormatsDoc]
  where header = "Usage: mbox-list [OPTION] <mbox-file>*"

maybeIntArg :: (Settings :-> Maybe Int) -> ArgDescr (Settings -> Settings)
maybeIntArg l = ReqArg (set l . Just . read) "NUM"

-- Since
--   ∀ k1 k2 Positives, take k1 . drop k2 == drop k2 . take (k2 + k1)
-- one fix an ordering: drop then take.
options :: [OptDescr Flag]
options =
  [ fmtOpt usage (set fmt)
  , Option "r" ["reverse"]  (NoArg (modify dir opposite)) "Reverse the mbox order (latest firsts)"
  , Option "d" ["drop"]     (maybeIntArg dropOpt)         "Drop the NUM firsts"
  , Option "t" ["take"]     (maybeIntArg takeOpt)         "Take the NUM firsts (happens after --drop)"
  , Option "?" ["help"]     (NoArg (set help True))       "Show this help message"
  ]

main :: IO ()
main = do
  args <- getArgs
  let (flags, nonopts, errs) = getOpt Permute options args
  let opts = foldr ($) defaultSettings flags
  if get help opts
   then usage ""
   else
    case (nonopts, errs) of
      (mboxfiles, []) -> listMbox opts mboxfiles
      (_,          _) -> usage (concat errs)