{-# LANGUAGE OverloadedStrings #-}
module System.Authinfo (readAuthinfo, getPassword) where
import System.Environment
import Data.Attoparsec.Text hiding (take)
import Data.List
import Control.Applicative
import qualified Data.Text as T
import qualified Data.Text.IO as T
import Control.Monad
import Network
import Data.Maybe
import Data.Char

type Line = (T.Text, T.Text, T.Text, Maybe PortNumber)
dropBack :: Int -> [a] -> [a]
dropBack n l = take (length l - n) l

quoted = char '"' *> takeWhile1 (not . (=='"')) <* char '"'
lstring s = lexeme $ string s
lexeme p = skipSpace *> p <* skipSpace
word = takeWhile1 $ not . isSpace
attempt p = fmap Just p <|> return Nothing
-- a possibly-quoted field
field = do p <- peekChar'
           if p == '"'
              then quoted
              else word

-- parse line
line :: Parser Line
line = fmap (\(Just h, Just l, Just p, r) -> (h,l,p,r)) 
            (line' (Nothing,Nothing,Nothing,Nothing))
  where line' s@(h,l,p,r) = 
          msum [ char '\n' >> return s
               , lstring "machine" >> field >>= (\h -> line' (Just h,l,p,r))
               , lstring "login" >> field >>= (\l -> line' (h,Just l,p,r))
               , lstring "password" >> field >>= (\p -> line' (h,l,Just p,r))
               , lstring "port" >> decimal >>= (\r -> line' (h,l,p,Just r))
               ] <?> "line"

file = many line

-- |Parses whole authinfo file
readAuthinfo :: IO [Line]
readAuthinfo = do
  home <- getEnv "HOME"
  Right res <- fmap (parseOnly file) $ T.readFile $ home ++ "/.authinfo"
  return res
  
-- |Gets the given user info out of AuthInfo
getPassword :: T.Text -> T.Text -> IO (Maybe (T.Text, Maybe PortNumber))
getPassword host user =
  fmap (fmap (\(_,_,pass,port) -> (pass,port)) . 
        find (\(h,u,_,_) -> h == host && u == user))
       readAuthinfo