diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,5 @@
+#!/usr/bin/env runhaskell
+
+> import Distribution.Simple
+> main = defaultMain
+ 
diff --git a/WL500gPControl.cabal b/WL500gPControl.cabal
new file mode 100644
--- /dev/null
+++ b/WL500gPControl.cabal
@@ -0,0 +1,23 @@
+name:                           WL500gPControl
+version:                        0.3.1
+cabal-version:                  >= 1.2
+license:                        BSD3
+license-file:                   LICENSE
+author:                         Vasyl Pasternak <vasyl.pasternak@gmail.com>
+category:                       Network, UI
+synopsis:                       A simple command line tools to control the 
+                                Asus WL500gP router
+build-type:                     Simple
+
+executable WL500gPStatus
+           main-is:             Status/Main.hs
+           build-depends:       base < 4, WL500gPLibrary >= 0.3
+           hs-source-dirs:      src
+           other-modules:       Common
+
+executable WL500gPControl
+           main-is:             Control/Main.hs
+           build-depends:       base < 4, WL500gPLibrary >= 0.3, mtl, unix
+           hs-source-dirs:      src
+           other-modules:       Common
+
diff --git a/src/Common.hs b/src/Common.hs
new file mode 100644
--- /dev/null
+++ b/src/Common.hs
@@ -0,0 +1,33 @@
+
+module Common 
+    (
+     defaultCredsFile
+    ,parseCredsFile
+    )where
+
+import System.IO.Unsafe (unsafePerformIO)
+import System.Environment (getEnv)
+import Text.Printf (printf)
+import qualified Network.Asus.WL500gP as W
+import Data.Char (toLower)
+import Control.Monad (liftM)
+    
+homeDirectory = unsafePerformIO $ getEnv "HOME"
+
+defaultCredsFile = printf "%s/.wl500gp" homeDirectory :: String
+
+
+parseCredsFile :: String -> IO (Maybe W.Connection)
+parseCredsFile fname = 
+    let toPair (a:b:[]) = (map toLower a, b)
+        toPair _ = ("", "")
+        parse = filter (/= ("", "")) . map (toPair . words) . lines
+    in do
+      contentsMap <- liftM parse $ readFile fname
+      return $ do (host:passwd:user:[]) <- 
+                      mapM (`lookup` contentsMap) ["host:"
+                                                  ,"password:"
+                                                  ,"user:"]
+                  return $ W.Connection {W.user = user
+                                        ,W.password = passwd
+                                        ,W.hostname = host}
diff --git a/src/Control/Main.hs b/src/Control/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Main.hs
@@ -0,0 +1,96 @@
+
+module Main where
+
+import System.Console.GetOpt
+import System.Environment (getArgs, getProgName)
+import Data.Maybe (maybe)
+import Common
+import Control.Monad (sequence_, zipWithM_)
+import Text.Printf (printf)
+import qualified Network.Asus.WL500gP as W
+import Data.Either (either)
+import Data.List (intersperse)
+import Control.Monad.Trans (liftIO)
+import System.Posix.Unistd (sleep)
+
+data Operation = Connect 
+               | Disconnect 
+               | Reconnect Int
+               | Status 
+               | Log Int
+               | ClearLog deriving (Show)
+
+options :: [OptDescr Operation]
+options = 
+    [Option ['c'] ["connect"] (NoArg Connect) 
+                "Connects to the WAN"
+    ,Option ['d'] ["disconnect"] (NoArg Disconnect) 
+                "Disconnects from the provider"
+    ,Option ['r'] ["reconnect"] (OptArg (Reconnect . maybe 5 read) "S") 
+                "Disconnects from WAN, waits S seconds and reconnects to the WAN"
+    ,Option ['s'] ["status"] (NoArg Status) 
+                "Prints the connection status"
+    ,Option ['l'] ["log"] (OptArg (Log . maybe 25 read) "N") 
+                "Prints last N lines from the log"
+    ,Option ['x'] ["log-clear"] (NoArg ClearLog) 
+                "Clears log"
+    ]
+
+-- returns the list of flags and the config filename
+parseOpts :: [String] -> IO (Operation, String)
+parseOpts argv = 
+    case getOpt Permute options argv of
+      (o, n, []) -> let creds = if null n 
+                                 then defaultCredsFile 
+                                 else (head n)
+                        op = if null o 
+                              then Status
+                              else (head o)
+                    in return (op, creds)
+      (_, _, errs) -> do 
+        progName <- getProgName
+        let header = printf "Usage: %s OPERATION CREDENTIAL_FILE" progName
+        ioError (userError (concat errs ++ usageInfo header options))
+     
+
+main :: IO ()
+main = do
+  (oper, creds) <- getArgs >>= parseOpts
+  parseCredsFile creds >>= maybe 
+                     (ioError $ userError $ printf "Failed to open credentials file '%s'" creds) 
+                     (switch oper)
+
+brace :: String -> String -> W.Conn () -> W.Conn ()
+brace b a c = sequence_ [liftIO $ putStrLn b, c, liftIO $ putStrLn a]
+
+switch op conn = 
+    W.withConnection conn $ 
+     case op of 
+       Connect -> brace "Connecting..." "Done" W.connectWan
+       Disconnect -> brace "Disconnecting..." "Done" W.disconnectWan
+       ClearLog -> brace "Erasing log.." "Done" W.clearLog
+       Reconnect n -> brace "Reconnecting..." "Done" $ 
+                      sequence_ [W.disconnectWan
+                                ,liftIO (sleep n >> return ())
+                                ,W.connectWan]
+       Status -> W.readStatus >>= liftIO . either (ioError . userError) showStatus
+       Log n -> W.readLog >>= liftIO . either (ioError . userError) (showLog n)
+
+showStatus stat = do
+  printf "Connection status:\n"    
+  case W.connectionStatus stat of
+    W.Disconnected -> printf "\tWAN disconnected\n"
+    _ -> do printf " WAN Connected\n"
+            zipWithM_ printf [" IP:\t\t%s\n"
+                             ," Subnet Mask:\t%s\n"
+                             ," Gateway:\t%s\n"
+                             ," DNS Servers:\t%s\n"
+                             ] $ 
+                               map ($ stat) [W.ip
+                                            ,W.subnetMask
+                                            ,W.defaultGateway
+                                            ,concat . intersperse ", " . W.dnsServers]
+
+
+showLog n = printf "%s" . unlines . reverse . take n . reverse
+    
diff --git a/src/Status/Main.hs b/src/Status/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/Status/Main.hs
@@ -0,0 +1,38 @@
+
+module Main where
+
+import qualified Network.Asus.WL500gP as W
+import System.Environment (getArgs)
+import Text.Printf (printf)
+import Common
+import Data.Either (either)
+
+data Status = StatusConnected | StatusDisconnected | StatusError String deriving Eq
+
+fromConnStatus :: W.ConnectionStatus -> Status
+fromConnStatus W.Connected = StatusConnected
+fromConnStatus W.Disconnected = StatusDisconnected
+
+main :: IO ()
+main = do
+  args <- getArgs
+  -- config file name should be the last argument
+  let configFile = if null args 
+                   then defaultCredsFile
+                   else head (reverse args)
+  -- '-c' - for colorized output
+  let outString = printStatus ("-c" `elem` args)
+  let configError = outString (StatusError $ printf "Failed to open file %s " configFile)
+  let getStatus conn = 
+          either (outString . StatusError) 
+                 (outString . fromConnStatus . W.connectionStatus) =<< 
+                 W.withConnection conn W.readStatus
+
+  maybe configError getStatus  =<< parseCredsFile configFile
+  
+printStatus c StatusConnected = format c "#00ff00" "Connected"
+printStatus c StatusDisconnected = format c "#ff0000" "Disconnected"
+printStatus c (StatusError e) = format c "#dddddd" (if c then "N/A" else e)
+
+format True col s = printf "<fc=%s>%s</fc>" col s
+format _ _ s = printf s
