maccatcher 1.0.1 → 2.0.0
raw patch · 4 files changed
+78/−76 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- System.Info.MAC: new :: IO (Maybe MAC)
- System.Info.MAC.Fetch: nixen :: IO (Maybe MAC)
- System.Info.MAC.Fetch: win32 :: IO (Maybe MAC)
+ System.Info.MAC: macs :: IO [MAC]
+ System.Info.MAC: refresh :: IO [MAC]
+ System.Info.MAC.Fetch: fetchMACs :: IO [MAC]
+ System.Info.MAC.Fetch: i_config :: IO String
+ System.Info.MAC.Fetch: ifconfig :: Parser [MAC]
+ System.Info.MAC.Fetch: ipconfig :: Parser [MAC]
+ System.Info.MAC.Fetch: parse' :: String -> Parser [t] -> String -> [t]
+ System.Info.MAC.Fetch: parseMAC :: Parser t -> Parser t' -> Char -> Parser (Maybe MAC)
+ System.Info.MAC.Fetch: parseMACs :: Parser t -> Parser t' -> Char -> Parser [MAC]
Files
- MACCatcher.hs +3/−5
- System/Info/MAC.hs +23/−15
- System/Info/MAC/Fetch.hs +51/−55
- maccatcher.cabal +1/−1
MACCatcher.hs view
@@ -1,11 +1,9 @@ #!/usr/bin/env runhaskell- -- Catch your MAC Address! import System.Info.MAC main = do- mac <- mac- case mac of- Just mac -> print mac- Nothing -> putStrLn "Failed to obtain MAC address."+ macs <- macs+ case macs of _:_ -> mapM_ print macs+ [ ] -> putStrLn "Failed to obtain MAC address."
System/Info/MAC.hs view
@@ -2,12 +2,13 @@ {-| Obtain a MAC address for the host system, on *NIX and Windows.- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}+ -} module System.Info.MAC- ( new+ ( refresh , mac+ , macs ) where import Data.MAC@@ -16,28 +17,35 @@ import Data.IORef import System.IO import System.IO.Unsafe+import Data.Maybe+import Control.Applicative {-| Explicitly re-run the MAC catching operation.- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}-new :: IO (Maybe MAC)-new = fetch+ -}+refresh :: IO [MAC]+refresh = do+ res <- fetchMACs+ writeIORef fetched res+ return res -{-| Return a host MAC address, using a cached value if it is available.- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}+{-| Fetch MAC address, using a cached value if it is available.+ -} mac :: IO (Maybe MAC)-mac = do+mac = listToMaybe <$> macs+++{-| Fetch MAC addresses, using a cached value if it is available.+ -}+macs :: IO [MAC]+macs = do val <- readIORef fetched- case val of- Nothing -> do- res <- new- writeIORef fetched res- return res- _ -> return val+ case val of [ ] -> refresh+ _:_ -> return val {-# NOINLINE fetched #-}-fetched = unsafePerformIO $ newIORef Nothing+fetched = unsafePerformIO $ newIORef []
System/Info/MAC/Fetch.hs view
@@ -1,8 +1,6 @@-- {-| System specific routines for determing the MAC address and macros to help- - sort things out at compile time.- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}+ sort things out at compile time.+ -} module System.Info.MAC.Fetch where@@ -10,82 +8,75 @@ import Data.MAC import Control.Monad+import Control.Applicative import Data.List+import Data.Maybe import System.Process import System.Info import System.IO import Text.ParserCombinators.Parsec -{-| Obtain the appropriate hardware MAC fetcher for the host operating system.- - This could be inlined, but in practice it is run only once.- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}-fetch =- case os of -- This feels like it should be in IO.- "mingw32" -> win32- _ -> nixen---{-| Obtain the hardware address on @*NIX@ of any kind, using a command line- - utility.- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}-nixen :: IO (Maybe MAC)-nixen = do- (_, o, _, h) <- runInteractiveCommand "ifconfig"- waitForProcess h- outputs <- hGetContents o- return $ join $ ifconfig outputs +{-| Obtain a list of all available MACs.+ -}+fetchMACs :: IO [MAC]+fetchMACs = parser <$> i_config - -- TODO Test this thing.-{-| Obtain the hardware address on Windows, using a command line utility. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}-win32 :: IO (Maybe MAC)-win32 = do- (_, o, _, h) <- runInteractiveCommand "ipconfig /all"+{-| Run @ifconfig@ or @ipconfig@, as appropriate, capturing its output.+ -}+i_config :: IO String+i_config = do+ (_, o, _, h) <- runInteractiveCommand cmd outputs <- hGetContents o seq (length outputs) (return ()) waitForProcess h- return $ join $ ipconfig outputs + return outputs where- -- Maybe we don't need this?- locations = map (++ "\\ipconfig")- [ "c:\\windows\\system32"- , "c:\\winnt\\system32"- ]+ cmd | os == "mingw32" = "ipconfig /all"+ | otherwise = "ifconfig" -{-| Parses the output of Windows @ipconfig@, yielding a Maybe MAC on- - succesful parse.- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}-ipconfig = parse' "ipconfig" $ do- manyTill anyChar $ try $ string "Physical Address"- manyTill anyChar $ char ':'- spaces- hexen <- sepHex '-'- return . maybeMAC . intercalate ":" $ hexen+parser | os == "mingw32" = parse' "ipconfig" ipconfig+ | otherwise = parse' "ifconfig" ifconfig -{-| Parses the output of Linux or BSD @ifconfig@, yielding a Maybe MAC on- - succesful parse.- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}-ifconfig = parse' "ifconfig" $ do- manyTill anyChar markers- spaces- hexen <- sepHex ':'- return . maybeMAC . intercalate ":" $ hexen+{-| Parses the output of Windows @ipconfig@.+ -}+ipconfig :: Parser [MAC]+ipconfig = parseMACs ((try . string) "Physical Address")+ (manyAnyTill (char ':') >> spaces)+ '-'+++{-| Parses the output of Linux or BSD @ifconfig@.+ -}+ifconfig :: Parser [MAC]+ifconfig = parseMACs markers spaces ':' where markers = choice $ map (try . string) [ "ether", "HWaddr" ] +parseMAC :: Parser t -> Parser t' -> Char -> Parser (Maybe MAC)+parseMAC preamble fill c = do+ preamble+ fill+ maybeMAC . intercalate ":" <$> sepHex (char c) -parse' source parser = eitherToMaybe . parse parser source+parseMACs :: Parser t -> Parser t' -> Char -> Parser [MAC]+parseMACs preamble fill c = catMaybes <$> parseMACs' where- eitherToMaybe (Left _) = Nothing- eitherToMaybe (Right r) = Just r + parseMACs' = + (skipManyTill anyChar . choice) [ eof >> return []+ , do m <- parseMAC preamble fill c+ (m:) <$> parseMACs' ] +parse' :: String -> Parser [t] -> String -> [t]+parse' source parser = either (const []) id . parse parser source++ maybeMAC :: String -> Maybe MAC maybeMAC s = case reads s of@@ -93,6 +84,11 @@ _ -> Nothing -sepHex = sepBy (sequence [hexDigit, hexDigit]) . char+sepHex = sepBy (sequence [hexDigit, hexDigit]) ++manyAnyTill = manyTill anyChar+++skipManyTill p end = choice [try end, p >> skipManyTill p end]
maccatcher.cabal view
@@ -1,5 +1,5 @@ name: maccatcher-version: 1.0.1+version: 2.0.0 category: Text license: BSD3 license-file: LICENSE