{-# LANGUAGE RecordWildCards #-} import System.IO import System.Console.ArgParser import Control.Monad import Control.Applicative import Paths_alea (getDataFileName) import Alea.Diceware import Alea.Random data ProgArgs = ProgArgs { interactive :: Bool , dictionary :: FilePath , phraseLength :: Int , phrases :: Int } deriving (Show) parser :: IO (ParserSpec ProgArgs) parser = path >>= \path -> return $ ProgArgs `parsedBy` boolFlag "interactive" `Descr` "Manually insert numbers" `andBy` optFlag path "dictionary" `Descr` "Specify dictionary file path" `andBy` optFlag 6 "lenght" `Descr` "Number of words in a passphrase" `andBy` optFlag 1 "phrases" `Descr` "Number of passphrases to generate" interface :: IO (CmdLnInterface ProgArgs) interface = (`setAppDescr` "A diceware passphrase generator") <$> (`setAppEpilog` "Alea iacta est.") <$> (mkApp =<< parser) main :: IO () main = interface >>= flip runApp (readDict >=> exec) -- Default path of the dictionary path :: IO FilePath path = getDataFileName "dict/diceware" -- Read dictionary file readDict :: ProgArgs -> IO ProgArgs readDict args@ProgArgs{..} = readFile dictionary >>= \x -> return args {dictionary = x} -- Main function exec :: ProgArgs -> IO () exec args@ProgArgs{..} = if interactive then interact (unlines . map dice . lines) else do randWords dictSize phraseLength >>= putStrLn . unwords . map dice' when (phrases > 1) $ exec args {phrases = phrases - 1} where (dict, dictSize) = (parseDiceware dictionary, length dict) dice n = readDiceware dict (read n :: Int) dice' n = readDiceware' dict n