1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
{-# LANGUAGE CPP #-}
-----------------------------------------------------------------------------
-- |
-- Module : Plugins.MBox
-- Copyright : (c) Jose A Ortega Ruiz
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Jose A Ortega Ruiz <jao@gnu.org>
-- Stability : unstable
-- Portability : unportable
--
-- A plugin for checking mail in mbox files.
--
-----------------------------------------------------------------------------
module Xmobar.Plugins.MBox (MBox(..)) where
import Prelude
import Xmobar.Run.Exec
#ifdef INOTIFY
import Xmobar.Plugins.Monitors.Common (parseOptsWith)
import Xmobar.System.Utils (changeLoop, expandHome)
import Control.Monad (when)
import Control.Concurrent.STM
import Control.Exception (SomeException (..), handle, evaluate)
import System.Console.GetOpt
import System.Directory (doesFileExist)
import System.FilePath ((</>))
import System.INotify (Event(..), EventVariety(..), initINotify, addWatch)
import qualified Data.ByteString.Lazy.Char8 as B
#if MIN_VERSION_hinotify(0,3,10)
import qualified Data.ByteString.Char8 as BS (ByteString, pack)
pack :: String -> BS.ByteString
pack = BS.pack
#else
pack :: String -> String
pack = id
#endif
data Options = Options
{ oAll :: Bool
, oUniq :: Bool
, oDir :: FilePath
, oPrefix :: String
, oSuffix :: String
}
defaults :: Options
defaults = Options {
oAll = False, oUniq = False, oDir = "", oPrefix = "", oSuffix = ""
}
options :: [OptDescr (Options -> Options)]
options =
[ Option "a" ["all"] (NoArg (\o -> o { oAll = True })) ""
, Option "u" [] (NoArg (\o -> o { oUniq = True })) ""
, Option "d" ["dir"] (ReqArg (\x o -> o { oDir = x }) "") ""
, Option "p" ["prefix"] (ReqArg (\x o -> o { oPrefix = x }) "") ""
, Option "s" ["suffix"] (ReqArg (\x o -> o { oSuffix = x }) "") ""
]
#else
import System.IO
#endif
-- | A list of display names, paths to mbox files and display colours,
-- followed by a list of options.
data MBox = MBox [(String, FilePath, String)] [String] String
deriving (Read, Show)
instance Exec MBox where
alias (MBox _ _ a) = a
#ifndef INOTIFY
start _ _ =
hPutStrLn stderr $ "Warning: xmobar is not compiled with -fwith_inotify" ++
" but the MBox plugin requires it"
#else
start (MBox boxes args _) cb = do
opts <- parseOptsWith options defaults args
let showAll = oAll opts
prefix = oPrefix opts
suffix = oSuffix opts
uniq = oUniq opts
names = map (\(t, _, _) -> t) boxes
colors = map (\(_, _, c) -> c) boxes
extractPath (_, f, _) = expandHome $ oDir opts </> f
events = [CloseWrite]
i <- initINotify
vs <- mapM (\b -> do
f <- extractPath b
exists <- doesFileExist f
n <- if exists then countMails f else return (-1)
v <- newTVarIO (f, n)
when exists $
addWatch i events (pack f) (handleNotification v) >> return ()
return v)
boxes
changeLoop (mapM (fmap snd . readTVar) vs) $ \ns ->
let s = unwords [ showC uniq m n c | (m, n, c) <- zip3 names ns colors
, showAll || n > 0 ]
in cb (if null s then "" else prefix ++ s ++ suffix)
showC :: Bool -> String -> Int -> String -> String
showC u m n c =
if c == "" then msg else "<fc=" ++ c ++ ">" ++ msg ++ "</fc>"
where msg = m ++ if not u || n > 1 then show n else ""
countMails :: FilePath -> IO Int
countMails f =
handle (\(SomeException _) -> evaluate 0)
(do txt <- B.readFile f
evaluate $! length . filter (B.isPrefixOf from) . B.lines $ txt)
where from = B.pack "From "
handleNotification :: TVar (FilePath, Int) -> Event -> IO ()
handleNotification v _ = do
(p, _) <- atomically $ readTVar v
n <- countMails p
atomically $ writeTVar v (p, n)
#endif
|