diff --git a/news.md b/news.md
--- a/news.md
+++ b/news.md
@@ -1,5 +1,23 @@
 % xmobar - Release notes
 
+## Version 0.18 (June 5, 2013)
+
+_New features_
+
+  - All extra argument monitors taking a string (e.g. `-O` for
+    `BatteryP`) accept now template variables (see [github #109] and
+    [#110]).  Thanks to Todd Lunter.
+
+  - New battery monitor extra argument, `-i`, for the idle status.
+
+_Bug fixes_
+
+  - Safer standard input parsing, avoiding <action> injections.
+
+
+[github #109]: https://github.com/jaor/xmobar/issues/109
+[#110]: https://github.com/jaor/xmobar/issues/110
+
 ## Version 0.17 (May 5, 2013)
 
 _New features_
@@ -22,7 +40,7 @@
   - Safer volume plugin (Dmitry Malikov).
   - Battery percentage capped at 100% (RJ Regenold).
 
-[github #67]: https://github.com/jaor/xmobar/issues/77
+[github #67]: https://github.com/jaor/xmobar/issues/67
 [github #77]: https://github.com/jaor/xmobar/issues/77
 [github #105]: https://github.com/jaor/xmobar/issues/105
 
@@ -97,10 +115,10 @@
 _Bug fixes_
 
   - Stricter build dependencies versioning in cabal file.
-  - [issue 56]: vertical alignment of text improved.
-  - [issue 64]: display of `watts` in `Batt` monitor fixed.
-  - [issue 69]: miscellaneous battery reporting issues.
-  - [issue 67]: compilation in DragonFly.
+  - [issue 56] vertical alignment of text improved.
+  - [issue 64] display of `watts` in `Batt` monitor fixed.
+  - [issue 69] miscellaneous battery reporting issues.
+  - [issue 67] compilation in DragonFly.
   - DiskIO works also when device path in mtab are symbolic links
     to the real device file.
   - Wireless monitor honours padding settings for ESSID names.
@@ -111,7 +129,7 @@
 [issue 64]: http://code.google.com/p/xmobar/issues/detail?id=64
 [issue 67]: http://code.google.com/p/xmobar/issues/detail?id=67
 [issue 69]: http://code.google.com/p/xmobar/issues/detail?id=69
-[github #36]: https://github.com/jaor/xmobar/issues/38
+[github #36]: https://github.com/jaor/xmobar/issues/36
 [github #38]: https://github.com/jaor/xmobar/issues/38
 
 ## Version 0.14 (Dec 10, 2011)
@@ -131,10 +149,10 @@
 
 _Bug fixes_
 
-  - [issue 45]: Fix for crashes with AC status changes in battery monitor.
-  - [issue 48]: The <quality> field of Wireless behaves like a percentage.
+  - [issue 45] Fix for crashes with AC status changes in battery monitor.
+  - [issue 48] The <quality> field of Wireless behaves like a percentage.
   - [issue 50]/[issue 61]: `MPD` monitor now works with libmpd 0.6.
-  - [issue 60]: Fixes for crashes on power resume for battery monitor.
+  - [issue 60] Fixes for crashes on power resume for battery monitor.
   - Template sections without fields are now correctly displayed.
   - Catch errors when reading battery status (Ben Boeckel).
   - Compilation issues with ghc 7.x (Sergei Trofimovich).
@@ -178,17 +196,17 @@
 
 _Bug fixes_
 
-  - [issue 14]: `StdinReader` and other plugins accepting external
+  - [issue 14] `StdinReader` and other plugins accepting external
     input don't get confused anymore when characters from `alignSep`
     appear in their input.
-  - [issue 27]: `BottomSize` placement now respects its width argument.
-  - [issue 28]: Compilation in Mac OS X fixed.
-  - [issue 30]: `Mail` plugin can be specified anywhere in commands list.
-  - [issue 36]: Battery monitor now supports non-standard locations of
+  - [issue 27] `BottomSize` placement now respects its width argument.
+  - [issue 28] Compilation in Mac OS X fixed.
+  - [issue 30] `Mail` plugin can be specified anywhere in commands list.
+  - [issue 36] Battery monitor now supports non-standard locations of
     the `/sys/class/power_supply/AC/online` file.
-  - [issue 40]: Battery monitor now supports the new power_now, that
+  - [issue 40] Battery monitor now supports the new power_now, that
     replaces current_now in linux kernels for v. 2.36 and above.
-  - [issue 42]: More accurate net monitor rates.
+  - [issue 42] More accurate net monitor rates.
   - DiskIO, Cpu and MultiCpu monitors are also more accurate now.
   - Text is now correctly centered vertically.
   - `FullBM` border spec fixed.
@@ -247,10 +265,10 @@
 
 _Bug fixes_
 
-  - [issue 23]: Wireless monitor is now compatible with iwlib 29.
-  - [issue 24]: Swap monitor's used ratio display fixed.
-  - [issue 25]: Percentages only include `%` if requested using `-P`.
-  - [issue 31]: MPD monitor now respects `-W` argument.
+  - [issue 23] Wireless monitor is now compatible with iwlib 29.
+  - [issue 24] Swap monitor's used ratio display fixed.
+  - [issue 25] Percentages only include `%` if requested using `-P`.
+  - [issue 31] MPD monitor now respects `-W` argument.
   - Fixes in CPU frequency formatting, string alignment and colour
     boxes in monitors (Norbert Zeh).
   - TopMem and TopProc now use the `-L` and `-H` options correctly for
diff --git a/readme.md b/readme.md
--- a/readme.md
+++ b/readme.md
@@ -11,7 +11,7 @@
 features, like dynamic color management, icons, output templates, and
 extensibility through plugins.
 
-This page documents xmobar 0.17 (see [release notes]).
+This page documents xmobar 0.18 (see [release notes]).
 
 [This screenshot] shows xmobar running under [sawfish], with
 antialiased fonts. And [this one] is my desktop with [xmonad] and two
@@ -734,6 +734,7 @@
   (these options, being specific to the monitor, are to be specified
   after a `--` in the argument list):
   - `-O`: string for AC "on" status (default: "On")
+  - `-i`: string for AC "idle" status (default: "On")
   - `-o`: string for AC "off" status (default: "Off")
   - `-L`: low power (`watts`) threshold (default: -12)
   - `-H`: high power threshold (default: -10)
@@ -753,7 +754,7 @@
          Run BatteryP ["BAT0"]
                       ["-t", "<acstatus><watts> (<left>%)",
                        "-L", "10", "-H", "80", "-p", "3",
-                       "--", "-O", "<fc=green>On</fc> - ", "-o", "",
+                       "--", "-O", "<fc=green>On</fc> - ", "-i", "",
                        "-L", "-15", "-H", "-5",
                        "-l", "red", "-m", "blue", "-h", "green"]
                       600
@@ -764,6 +765,20 @@
   neither the generic nor the specific options have any effect on
   `<timeleft>`.
 
+  It is also possible to specify template variables in the `-O` and
+  `-o` switches, as in the following example:
+
+         Run BatteryP ["BAT0"]
+                      ["-t", "<acstatus>"
+                      , "-L", "10", "-H", "80"
+                      , "-l", "red", "-h", "green"
+                      , "--", "-O", "Charging", "-o", "Battery: <left>%"
+                      ] 10
+
+- The "idle" AC state is selected whenever the AC power entering the
+  battery is zero.
+
+
 ### `TopProc Args RefreshRate`
 
 - Aliases to `top`
@@ -1294,11 +1309,12 @@
 In particular, xmobar [incorporates patches] by Ben Boeckel, Roman
 Cheplyaka, Patrick Chilton, John Goerzen, Reto Hablützel, Juraj
 Hercek, Tomas Janousek, Spencer Janssen, Jochen Keil, Lennart
-Kolmodin, Krzysztof Kosciuszkiewicz, Dmitry Kurochkin, Dmitry Malikov,
-Edward O'Callaghan, Svein Ove, Martin Perner, Jens Petersen, Alexander
-Polakov, Petr Rockai, Peter Simons, Andrew Sackville-West, Alexander
-Solovyov, John Soros, Artem Tarasov, Sergei Trofimovich, Thomas
-Tuegel, Jan Vornberger, Daniel Wagner and Norbert Zeh.
+Kolmodin, Krzysztof Kosciuszkiewicz, Dmitry Kurochkin, Todd Lunter,
+Dmitry Malikov, Edward O'Callaghan, Svein Ove, Martin Perner, Jens
+Petersen, Alexander Polakov, Petr Rockai, Peter Simons, Andrew
+Sackville-West, Alexander Solovyov, John Soros, Artem Tarasov, Sergei
+Trofimovich, Thomas Tuegel, Jan Vornberger, Daniel Wagner and Norbert
+Zeh.
 
 [incorporates patches]: http://www.ohloh.net/p/xmobar/contributors
 
diff --git a/src/Actions.hs b/src/Actions.hs
--- a/src/Actions.hs
+++ b/src/Actions.hs
@@ -10,13 +10,18 @@
 --
 -----------------------------------------------------------------------------
 
-module Actions where
+module Actions (Action(..), runAction, stripActions) where
 
 import System.Process (system)
 import Control.Monad (void)
+import Text.Regex (subRegex, mkRegex)
 
 data Action = Spawn String
                 deriving (Eq)
 
 runAction :: Action -> IO ()
 runAction (Spawn s) = void $ system (s ++ "&")
+
+stripActions :: String -> String
+stripActions s = subRegex actionRegex s "[action=\1]\2[action]"
+  where actionRegex = mkRegex "<action=([^>])*>(.+?)</action>"
diff --git a/src/Parsers.hs b/src/Parsers.hs
--- a/src/Parsers.hs
+++ b/src/Parsers.hs
@@ -37,16 +37,20 @@
 parseString :: Config -> String -> IO [(Widget, ColorString, Maybe Action)]
 parseString c s =
     case parse (stringParser (fgColor c) Nothing) "" s of
-      Left  _ -> return [(Text $ "Could not parse string: " ++ s, fgColor c, Nothing)]
+      Left  _ -> return [(Text $ "Could not parse string: " ++ s
+                          , fgColor c
+                          , Nothing)]
       Right x -> return (concat x)
 
 -- | Gets the string and combines the needed parsers
-stringParser :: String -> Maybe Action -> Parser [[(Widget, ColorString, Maybe Action)]]
+stringParser :: String -> Maybe Action
+                -> Parser [[(Widget, ColorString, Maybe Action)]]
 stringParser c a = manyTill (textParser c a <|> try (iconParser c a) <|>
                              try (actionParser c) <|> colorParser a) eof
 
 -- | Parses a maximal string without color markup.
-textParser :: String -> Maybe Action -> Parser [(Widget, ColorString, Maybe Action)]
+textParser :: String -> Maybe Action
+              -> Parser [(Widget, ColorString, Maybe Action)]
 textParser c a = do s <- many1 $
                           noneOf "<" <|>
                             try (notFollowedBy' (char '<')
@@ -66,7 +70,8 @@
                         notFollowedBy $ try (e >> return '*')
                         return x
 
-iconParser :: String -> Maybe Action -> Parser [(Widget, ColorString, Maybe Action)]
+iconParser :: String -> Maybe Action
+              -> Parser [(Widget, ColorString, Maybe Action)]
 iconParser c a = do
   string "<icon="
   i <- manyTill (noneOf ">") (try (string "/>"))
@@ -77,7 +82,8 @@
   a <- between (string "<action=") (string ">") (many1 (noneOf ">"))
   let a' = Just (Spawn a)
   s <- manyTill (try (textParser c a') <|> try (iconParser c a') <|>
-                 try (colorParser a') <|> actionParser c) (try $ string "</action>")
+                 try (colorParser a') <|> actionParser c)
+                (try $ string "</action>")
   return (concat s)
 
 -- | Parsers a string wrapped in a color specification.
@@ -122,7 +128,8 @@
 
 -- | Given a finite "Map" and a parsed template produce the resulting
 -- output string.
-combine :: Config -> Map.Map String Runnable -> [(String, String, String)] -> [(Runnable,String,String)]
+combine :: Config -> Map.Map String Runnable
+           -> [(String, String, String)] -> [(Runnable,String,String)]
 combine _ _ [] = []
 combine c m ((ts,s,ss):xs) = (com, s, ss) : combine c m xs
     where com  = Map.findWithDefault dflt ts m
@@ -132,7 +139,8 @@
 allTillSep = many . noneOf . sepChar
 
 stripComments :: String -> String
-stripComments = unlines . map (drop 5 . strip False . (replicate 5 ' '++)) . lines
+stripComments =
+  unlines . map (drop 5 . strip False . (replicate 5 ' '++)) . lines
     where strip m ('-':'-':xs) = if m then "--" ++ strip m xs else ""
           strip m ('\\':xss) = case xss of
                                 '\\':xs -> '\\' : strip m xs
@@ -197,7 +205,8 @@
                       ; notFollowedBy $ wrapSkip $ string "Run"
                       ; return ","
                       }
-      readCommands = manyTill anyChar (try commandsEnd) >>= read' commandsErr . flip (++) "]"
+      readCommands = manyTill anyChar (try commandsEnd) >>=
+                        read' commandsErr . flip (++) "]"
 
       strField e n = field e n . between (strDel "start" n) (strDel "end" n) .
                      many $ noneOf "\"\n\r"
@@ -217,5 +226,7 @@
                     _ -> fail $ "error reading the " ++ d ++ " field: " ++ s
 
 commandsErr :: String
-commandsErr = "commands: this usually means that a command could not be parsed.\n" ++
-              "The error could be located at the begining of the command which follows the offending one."
+commandsErr = "commands: this usually means that a command could not" ++
+              "\nbe parsed." ++
+              "\nThe error could be located at the begining of the command" ++
+              "\nwhich follows the offending one."
diff --git a/src/Plugins/Monitors/Batt.hs b/src/Plugins/Monitors/Batt.hs
--- a/src/Plugins/Monitors/Batt.hs
+++ b/src/Plugins/Monitors/Batt.hs
@@ -1,7 +1,7 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Plugins.Monitors.Batt
--- Copyright   :  (c) 2010, 2011, 2012 Jose A Ortega
+-- Copyright   :  (c) 2010, 2011, 2012, 2013 Jose A Ortega
 --                (c) 2010 Andrea Rossato, Petr Rockai
 -- License     :  BSD-style (see LICENSE)
 --
@@ -25,6 +25,7 @@
 data BattOpts = BattOpts
   { onString :: String
   , offString :: String
+  , idleString :: String
   , posColor :: Maybe String
   , lowWColor :: Maybe String
   , mediumWColor :: Maybe String
@@ -39,6 +40,7 @@
 defaultOpts = BattOpts
   { onString = "On"
   , offString = "Off"
+  , idleString = "On"
   , posColor = Nothing
   , lowWColor = Nothing
   , mediumWColor = Nothing
@@ -53,6 +55,7 @@
 options =
   [ Option "O" ["on"] (ReqArg (\x o -> o { onString = x }) "") ""
   , Option "o" ["off"] (ReqArg (\x o -> o { offString = x }) "") ""
+  , Option "i" ["idle"] (ReqArg (\x o -> o { idleString = x }) "") ""
   , Option "p" ["positive"] (ReqArg (\x o -> o { posColor = Just x }) "") ""
   , Option "l" ["low"] (ReqArg (\x o -> o { lowWColor = Just x }) "") ""
   , Option "m" ["medium"] (ReqArg (\x o -> o { mediumWColor = Just x }) "") ""
@@ -140,10 +143,12 @@
            ft = sum (map full bats)
            left = if ft > 0 then sum (map now bats) / ft else 0
            watts = sign * sum (map power bats)
-           time = if watts == 0 then 0 else sum $ map time' bats
-           mwatts = if watts == 0 then 1 else sign * watts
+           idle = watts == 0
+           time = if idle then 0 else sum $ map time' bats
+           mwatts = if idle then 1 else sign * watts
            time' b = (if ac then full b - now b else now b) / mwatts
-           acstr = if ac then onString opts else offString opts
+           acstr = if idle then idleString opts else
+                     if ac then onString opts else offString opts
        return $ if isNaN left then NA else Result left watts time acstr
 
 runBatt :: [String] -> Monitor String
@@ -158,7 +163,8 @@
   case c of
     Result x w t s ->
       do l <- fmtPercent x
-         parseTemplate (l ++ s:[fmtTime $ floor t, fmtWatts w opts suffix d])
+         let ts = [fmtTime $ floor t, fmtWatts w opts suffix d]
+         parseTemplate (l ++ s:ts)
     NA -> return "N/A"
   where fmtPercent :: Float -> Monitor [String]
         fmtPercent x = do
diff --git a/src/Plugins/Monitors/Common.hs b/src/Plugins/Monitors/Common.hs
--- a/src/Plugins/Monitors/Common.hs
+++ b/src/Plugins/Monitors/Common.hs
@@ -1,7 +1,7 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Plugins.Monitors.Common
--- Copyright   :  (c) 2010, 2011 Jose Antonio Ortega Ruiz
+-- Copyright   :  (c) 2010, 2011, 2013 Jose Antonio Ortega Ruiz
 --                (c) 2007-2010 Andrea Rossato
 -- License     :  BSD-style (see LICENSE)
 --
@@ -35,6 +35,7 @@
                        , getAfterString
                        , skipTillString
                        , parseTemplate
+                       , parseTemplate'
                        -- ** String Manipulation
                        -- $strings
                        , padString
@@ -301,19 +302,27 @@
 parseTemplate :: [String] -> Monitor String
 parseTemplate l =
     do t <- getConfigValue template
-       s <- io $ runP templateParser t
        e <- getConfigValue export
        let m = Map.fromList . zip e $ l
-       return $ combine m s
+       parseTemplate' t m
 
--- | Given a finite "Map" and a parsed templatet produces the
--- | resulting output string.
-combine :: Map.Map String String -> [(String, String, String)] -> String
-combine _ [] = []
+-- | Parses the template given to it with a map of export values and combines
+-- them
+parseTemplate' :: String -> Map.Map String String -> Monitor String
+parseTemplate' t m =
+    do s <- io $ runP templateParser t
+       combine m s
+
+-- | Given a finite "Map" and a parsed template t produces the
+-- | resulting output string as the output of the monitor.
+combine :: Map.Map String String -> [(String, String, String)] -> Monitor String
+combine _ [] = return []
 combine m ((s,ts,ss):xs) =
-    s ++ str ++ ss ++ combine m xs
-        where str = Map.findWithDefault err ts m
-              err = "<" ++ ts ++ " not found!>"
+    do next <- combine m xs
+       let str = Map.findWithDefault err ts m
+           err = "<" ++ ts ++ " not found!>"
+       nstr <- parseTemplate' str m
+       return $ s ++ (if null nstr then str else nstr) ++ ss ++ next
 
 -- $strings
 
diff --git a/src/Plugins/PipeReader.hs b/src/Plugins/PipeReader.hs
--- a/src/Plugins/PipeReader.hs
+++ b/src/Plugins/PipeReader.hs
@@ -16,6 +16,10 @@
 
 import System.IO
 import Plugins
+import System.Posix.Files
+import Control.Concurrent(threadDelay)
+import Control.Exception
+import Control.Monad(when)
 
 data PipeReader = PipeReader String String
     deriving (Read, Show)
@@ -24,11 +28,21 @@
     alias (PipeReader _ a)    = a
     start (PipeReader p _) cb = do
         let (def, pipe) = split ':' p
+        when (not $ null def) (cb def)
+        checkPipe pipe
         h <- openFile pipe ReadWriteMode
-        cb def
         forever (hGetLineSafe h >>= cb)
       where
         forever a = a >> forever a
         split c xs | c `elem` xs = let (pre, post) = span ((/=) c) xs
                                    in (pre, dropWhile ((==) c) post)
                    | otherwise   = ([], xs)
+
+checkPipe :: FilePath -> IO ()
+checkPipe file = do
+    handle (\(SomeException _) -> waitForPipe) $ do
+    status <- getFileStatus file
+    if isNamedPipe status
+      then return ()
+      else waitForPipe
+    where waitForPipe = threadDelay 1000 >> checkPipe file
diff --git a/src/Plugins/StdinReader.hs b/src/Plugins/StdinReader.hs
--- a/src/Plugins/StdinReader.hs
+++ b/src/Plugins/StdinReader.hs
@@ -20,15 +20,16 @@
 import System.IO
 import Control.Exception (SomeException(..), handle)
 import Plugins
+import Actions (stripActions)
 
-data StdinReader = StdinReader
-    deriving (Read, Show)
+data StdinReader = StdinReader deriving (Read, Show)
 
 instance Exec StdinReader where
-    start StdinReader cb = do
-        cb =<< handle (\(SomeException e) -> do hPrint stderr e; return "")
-                      (hGetLineSafe stdin)
-        eof <- hIsEOF stdin
-        if eof
-            then exitImmediately ExitSuccess
-            else start StdinReader cb
+  start StdinReader cb = do
+    s <- handle (\(SomeException e) -> do hPrint stderr e; return "")
+                (hGetLineSafe stdin)
+    cb (stripActions s)
+    eof <- hIsEOF stdin
+    if eof
+      then exitImmediately ExitSuccess
+      else start StdinReader cb
diff --git a/src/Plugins/XMonadLog.hs b/src/Plugins/XMonadLog.hs
--- a/src/Plugins/XMonadLog.hs
+++ b/src/Plugins/XMonadLog.hs
@@ -28,9 +28,11 @@
 #endif
 import Foreign.C (CChar)
 import XUtil (nextEvent')
-
+import Actions (stripActions)
 
-data XMonadLog = XMonadLog | XPropertyLog String | NamedXPropertyLog String String
+data XMonadLog = XMonadLog
+               | XPropertyLog String
+               | NamedXPropertyLog String String
     deriving (Read, Show)
 
 instance Exec XMonadLog where
@@ -51,7 +53,7 @@
 
         let update = do
                         mwp <- getWindowProperty8 d xlog root
-                        maybe (return ()) (cb . decodeCChar) mwp
+                        maybe (return ()) (cb . stripActions. decodeCChar) mwp
 
         update
 
diff --git a/xmobar.cabal b/xmobar.cabal
--- a/xmobar.cabal
+++ b/xmobar.cabal
@@ -1,5 +1,5 @@
 name:               xmobar
-version:            0.17
+version:            0.18
 homepage:           http://projects.haskell.org/xmobar/
 bug-reports:        http://code.google.com/p/xmobar/issues
 synopsis:           A Minimalistic Text Based Status Bar
@@ -97,6 +97,7 @@
     build-depends:
       base == 4.*,
       containers,
+      regex-compat,
       process,
       old-locale,
       bytestring,
