module Network.Asus.WL500gP
(
Connection (..)
,ConnectionStatus (..)
,Status (..)
,Log
,Conn
,withConnection
,readStatus
,readLog
,connectWan
,disconnectWan
,clearLog
) where
import Control.Monad.Reader
import Network.Curl
import Text.Printf (printf)
import Text.HTML.TagSoup
import Data.List (tails)
import Data.Maybe (maybe)
import Data.Either (either)
import Control.Monad (guard)
data ConnectionStatus = Connected | Disconnected deriving (Eq, Show)
toConnStatus :: String -> ConnectionStatus
toConnStatus s = if s == "Connected" then Connected else Disconnected
data Connection = Connection {
user :: String
, password :: String
, hostname :: String
} deriving (Show, Eq)
data Status = Status {
connectionStatus :: ConnectionStatus
, ip :: String
, subnetMask :: String
, defaultGateway :: String
, dnsServers :: [String]
} deriving (Show)
type Log = [String]
type Conn a = ReaderT Connection IO a
withConnection :: Connection -> Conn a -> IO a
withConnection con cl = runReaderT cl' con
where cl' = cl >>= \r -> logout >> return r
readStatus :: Conn (Either String Status)
readStatus =
liftM (either Left
(toEither "Fail to parse data" . parseStatusPage)) $
getPage "Main_GStatus_Content.asp"
readLog :: Conn (Either String Log)
readLog =
liftM (either Left
(toEither "Fail to parse data" . parseLogPage)) $
getPage "Main_LogStatus_Content.asp"
disconnectWan :: Conn ()
disconnectWan =
performAction (actionState "dhcpc_release")
connectWan :: Conn ()
connectWan =
performAction (actionState "dhcpc_renew")
clearLog :: Conn ()
clearLog =
performAction (actionLog "+Clear+")
toEither :: a -> Maybe b -> Either a b
toEither a = maybe (Left a) Right
performAction :: String -> Conn ()
performAction act = do
up <- getUserPassword
url <- liftM (++ act) $ getUrl "apply.cgi"
(resuln, str) <- liftIO $ curlGetString url $ CurlUserPwd up : method_GET
return ()
actionState :: String -> String
actionState = printf "?action_mode=Update&action_script=%s"
actionLog :: String -> String
actionLog = printf "?action_mode=%s"
getPage :: String -> Conn (Either String String)
getPage page = do
up <- getUserPassword
url <- getUrl page
(result, str) <- liftIO $ curlGetString url $ CurlUserPwd up : method_GET
return $ if result /= CurlOK
then Left $ printf "Failed to get url: '%s'" url
else Right str
getUserPassword :: Conn String
getUserPassword = do
u <- liftM (user) ask
p <- liftM (password) ask
return $ printf "%s:%s" u p
getUrl :: String -> Conn String
getUrl page = do
h <- liftM (hostname) ask
return $ printf "http://%s/%s" h page
logout :: Conn ()
logout = do
url <- getUrl "Logout.asp"
liftIO $ curlGetString url method_GET
return ()
parseStatusPage :: String -> Maybe Status
parseStatusPage content =
let
inputs = [(fromAttrib "name" a, fromAttrib "value" a)
| a:_ <- tails (parseTags content)
, a~== "<input>"
, fromAttrib "name" a /= ""]
in do
(status':ip':subnet':gateway':dns':[]) <-
mapM (`lookup` inputs) ["wan_status_t", "wan_ipaddr_t", "wan_netmask_t",
"wan_gateway_t", "wan_dns_t"]
return $ Status
{connectionStatus = toConnStatus status'
,ip = ip'
,subnetMask = subnet'
,defaultGateway = gateway'
,dnsServers = words dns'}
parseLogPage :: String -> Maybe Log
parseLogPage content =
let
logString = [fromTagText t | a:t:_ <- tails (parseTags content),
a ~== "<textarea class=content_log_td>"]
in do
guard (not $ null logString)
return $ filter (/= "") $ lines $ head logString