packages feed

alea-0.1.1.0: Main.hs

{-# LANGUAGE DeriveDataTypeable, RecordWildCards #-}

import System.IO
import System.Console.CmdArgs
import Control.Monad (when)

import Paths_alea (getDataFileName)
import Alea.Diceware
import Alea.Random

_NAME = "Alea"
_VERSION = "0.1.0"
_INFO = _NAME ++ " version " ++ _VERSION
_ABOUT = "a diceware passphrase generator"
_COPYRIGHT = "(C) Michele Guerini Rocco 2014"

data Args = Args
	{ interactive  :: Bool
	, dictionary   :: FilePath
	, phraseLength :: Int
	, phrases      :: Int
	} deriving (Data, Typeable, Show, Eq)

progArgs :: Args
progArgs = Args
	{ interactive  = def &= help "Manually insert numbers"
	, dictionary   = def &= help "Specify dictionary file path"
	, phraseLength = def &= help "Number of words in a passphrase"
	, phrases      = def &= help "Number of passphrases to generate"
	}

getProgArgs :: IO Args
getProgArgs = cmdArgs $ progArgs
    &= versionArg [explicit, name "version", name "v", summary _INFO]
    &= summary (_INFO ++ ", " ++ _COPYRIGHT)
    &= help _ABOUT
    &= helpArg [explicit, name "help", name "h"]
    &= program _NAME


main :: IO ()
main = getProgArgs >>= defaults >>= exec

-- Assign defaults value to unspecified args
defaults :: Args -> IO Args
defaults args@Args{..} = do
	dictionary <- getDataFileName "dict/diceware" >>= readFile
	return args
		{ dictionary   = dictionary
		, phraseLength = if phraseLength == 0 then 6 else phraseLength
		}

exec :: Args -> IO ()
exec args@Args{..} =
	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
		-- helpers
		dice  n = readDiceware  (parseDiceware dictionary) (read n :: Int)
		dice' n = readDiceware' (parseDiceware dictionary) n
		dictSize = size $ parseDiceware dictionary