|  |  |  | @ -2,35 +2,142 @@ | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | module Main where | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | import UserDB (User(..), getAllUsers, getSingleUser, addUser) | 
			
		
	
		
			
				
					|  |  |  |  | import UserDB (User(..), getAllUsers, getSingleUser, addUser, | 
			
		
	
		
			
				
					|  |  |  |  |                updateUser, deleteUser) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | import Control.Concurrent | 
			
		
	
		
			
				
					|  |  |  |  | -- import Control.Concurrent.MVar | 
			
		
	
		
			
				
					|  |  |  |  | import Control.Monad (forever) | 
			
		
	
		
			
				
					|  |  |  |  | import Data.List (intersperse) | 
			
		
	
		
			
				
					|  |  |  |  | import Data.List (intersperse, intercalate) | 
			
		
	
		
			
				
					|  |  |  |  | import Data.Text (Text) | 
			
		
	
		
			
				
					|  |  |  |  | import qualified Data.Text as T | 
			
		
	
		
			
				
					|  |  |  |  | import Data.ByteString (ByteString) | 
			
		
	
		
			
				
					|  |  |  |  | import qualified Data.ByteString as BS | 
			
		
	
		
			
				
					|  |  |  |  | import qualified Data.ByteString.Lazy as BSL | 
			
		
	
		
			
				
					|  |  |  |  | import Data.Text.Encoding (decodeUtf8, encodeUtf8) | 
			
		
	
		
			
				
					|  |  |  |  | import Network.Socket hiding ({-close,-} recv) | 
			
		
	
		
			
				
					|  |  |  |  | import Network.Socket hiding (recv) | 
			
		
	
		
			
				
					|  |  |  |  | import Network.Socket.ByteString (recv, sendAll) | 
			
		
	
		
			
				
					|  |  |  |  | import Data.Aeson | 
			
		
	
		
			
				
					|  |  |  |  | import Control.Applicative (empty) | 
			
		
	
		
			
				
					|  |  |  |  | import qualified Data.HashMap.Lazy as HML | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | getAllUsers' :: MVar Bool -> IO [User] | 
			
		
	
		
			
				
					|  |  |  |  | getAllUsers' m = do | 
			
		
	
		
			
				
					|  |  |  |  |   m' <- takeMVar m | 
			
		
	
		
			
				
					|  |  |  |  |   users <- getAllUsers | 
			
		
	
		
			
				
					|  |  |  |  |   putMVar m m' | 
			
		
	
		
			
				
					|  |  |  |  |   return users | 
			
		
	
		
			
				
					|  |  |  |  | import Data.Aeson.Types | 
			
		
	
		
			
				
					|  |  |  |  | import Data.Either (lefts) | 
			
		
	
		
			
				
					|  |  |  |  | import Data.String (fromString) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | addUser' :: MVar Bool -> User -> IO () | 
			
		
	
		
			
				
					|  |  |  |  | addUser' m u = do | 
			
		
	
		
			
				
					|  |  |  |  |   m' <- takeMVar m | 
			
		
	
		
			
				
					|  |  |  |  |   b <- addUser u | 
			
		
	
		
			
				
					|  |  |  |  |   print b | 
			
		
	
		
			
				
					|  |  |  |  |   putMVar m m' | 
			
		
	
		
			
				
					|  |  |  |  | -- type UserName = Text | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | -- { | 
			
		
	
		
			
				
					|  |  |  |  | --   "actions" : [ | 
			
		
	
		
			
				
					|  |  |  |  | --     { | 
			
		
	
		
			
				
					|  |  |  |  | --       "action" : "delete", | 
			
		
	
		
			
				
					|  |  |  |  | --       "params" : "gdp" | 
			
		
	
		
			
				
					|  |  |  |  | --     }, | 
			
		
	
		
			
				
					|  |  |  |  | --     { | 
			
		
	
		
			
				
					|  |  |  |  | --       "action" : "add", | 
			
		
	
		
			
				
					|  |  |  |  | --       "params" : { | 
			
		
	
		
			
				
					|  |  |  |  | --         "username" : "gdp", | 
			
		
	
		
			
				
					|  |  |  |  | --         "shell" : "/bin/sh", | 
			
		
	
		
			
				
					|  |  |  |  | --         "homeDirectory" : "/home/gdp", | 
			
		
	
		
			
				
					|  |  |  |  | --         "realName" : "Gaël Depreeuw", | 
			
		
	
		
			
				
					|  |  |  |  | --         "phone" : "555-123-456789" | 
			
		
	
		
			
				
					|  |  |  |  | --       } | 
			
		
	
		
			
				
					|  |  |  |  | --     }, | 
			
		
	
		
			
				
					|  |  |  |  | --     { | 
			
		
	
		
			
				
					|  |  |  |  | --       "action" : "update", | 
			
		
	
		
			
				
					|  |  |  |  | --       "params" : { | 
			
		
	
		
			
				
					|  |  |  |  | --         "username" : "gdp", | 
			
		
	
		
			
				
					|  |  |  |  | --         "newUsername" : "...", | 
			
		
	
		
			
				
					|  |  |  |  | --         "newShell" : "...", | 
			
		
	
		
			
				
					|  |  |  |  | --         "newHomedirectory" : "...", | 
			
		
	
		
			
				
					|  |  |  |  | --         "newRealName" : "...", | 
			
		
	
		
			
				
					|  |  |  |  | --         "newPhone" : "...", | 
			
		
	
		
			
				
					|  |  |  |  | --      } | 
			
		
	
		
			
				
					|  |  |  |  | --     } | 
			
		
	
		
			
				
					|  |  |  |  | --   ] | 
			
		
	
		
			
				
					|  |  |  |  | -- } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | data UserUpdate = UserUpdate { | 
			
		
	
		
			
				
					|  |  |  |  |   name :: String, | 
			
		
	
		
			
				
					|  |  |  |  |   mbUsername :: Maybe String, | 
			
		
	
		
			
				
					|  |  |  |  |   mbShell :: Maybe String, | 
			
		
	
		
			
				
					|  |  |  |  |   mbHomeDirectory :: Maybe String, | 
			
		
	
		
			
				
					|  |  |  |  |   mbRealName :: Maybe String, | 
			
		
	
		
			
				
					|  |  |  |  |   mbPhone :: Maybe String | 
			
		
	
		
			
				
					|  |  |  |  | } deriving (Show, Eq) | 
			
		
	
		
			
				
					|  |  |  |  | instance FromJSON UserUpdate where | 
			
		
	
		
			
				
					|  |  |  |  |   parseJSON = withObject "UserUpdate" $ \o -> UserUpdate | 
			
		
	
		
			
				
					|  |  |  |  |     <$> o .: "username" | 
			
		
	
		
			
				
					|  |  |  |  |     <*> o .:? "newUsername" | 
			
		
	
		
			
				
					|  |  |  |  |     <*> o .:? "shell" | 
			
		
	
		
			
				
					|  |  |  |  |     <*> o .:? "homeDirectory" | 
			
		
	
		
			
				
					|  |  |  |  |     <*> o .:? "realName" | 
			
		
	
		
			
				
					|  |  |  |  |     <*> o .:? "phone" | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | data Action = DeleteAction Text | 
			
		
	
		
			
				
					|  |  |  |  |             | AddUser User | 
			
		
	
		
			
				
					|  |  |  |  |             | ModifyUser UserUpdate | 
			
		
	
		
			
				
					|  |  |  |  |             deriving (Show, Eq) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | instance FromJSON Action where | 
			
		
	
		
			
				
					|  |  |  |  |   parseJSON = withObject "Action" $ \o -> do | 
			
		
	
		
			
				
					|  |  |  |  |     a <- o .: "action" :: Parser Text | 
			
		
	
		
			
				
					|  |  |  |  |     let mbValue = HML.lookup "params" o | 
			
		
	
		
			
				
					|  |  |  |  |     case mbValue of | 
			
		
	
		
			
				
					|  |  |  |  |       Nothing -> empty | 
			
		
	
		
			
				
					|  |  |  |  |       Just v -> case a of | 
			
		
	
		
			
				
					|  |  |  |  |                   "delete" -> DeleteAction <$> o .: "params" | 
			
		
	
		
			
				
					|  |  |  |  |                   "add" -> AddUser <$> parseJSON v | 
			
		
	
		
			
				
					|  |  |  |  |                   "update" -> ModifyUser <$> parseJSON v | 
			
		
	
		
			
				
					|  |  |  |  |                   _ -> empty | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | data Config = Config [Action] deriving (Show, Eq) | 
			
		
	
		
			
				
					|  |  |  |  | instance FromJSON Config where | 
			
		
	
		
			
				
					|  |  |  |  |   parseJSON = withObject "Config" $ \o -> Config <$> o .: "actions" | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | -- instance FromJSON Config where | 
			
		
	
		
			
				
					|  |  |  |  | --   parseJSON = withObject "Config" $ \o -> | 
			
		
	
		
			
				
					|  |  |  |  | --     case HML.lookup "actions" o of | 
			
		
	
		
			
				
					|  |  |  |  | --       (Just (Array v)) -> Config <$> (mapM parseJSON $ V.toList v) | 
			
		
	
		
			
				
					|  |  |  |  | --       _ -> empty | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | -- (.:) :: FromJSON a => Object -> Text -> Parser a | 
			
		
	
		
			
				
					|  |  |  |  | -- parseJSON :: FromJSON a => Value -> Parser a | 
			
		
	
		
			
				
					|  |  |  |  | -- withObject :: String -> (Object -> Parser a) -> Value -> Parser a | 
			
		
	
		
			
				
					|  |  |  |  | -- withArray :: String -> (Array -> Parser a) -> Value -> Parser a | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | doAction :: MVar () -> Action -> IO (Either String ()) | 
			
		
	
		
			
				
					|  |  |  |  | doAction m (DeleteAction t) = do | 
			
		
	
		
			
				
					|  |  |  |  |   b <- protect m $ deleteUser t | 
			
		
	
		
			
				
					|  |  |  |  |   case b of | 
			
		
	
		
			
				
					|  |  |  |  |     True -> return $ Right () | 
			
		
	
		
			
				
					|  |  |  |  |     False -> return $ Left ("User " ++ (T.unpack t) | 
			
		
	
		
			
				
					|  |  |  |  |                             ++ " does not exist.") | 
			
		
	
		
			
				
					|  |  |  |  | doAction m (AddUser u) = do | 
			
		
	
		
			
				
					|  |  |  |  |   b <- protect m $ addUser u | 
			
		
	
		
			
				
					|  |  |  |  |   case b of | 
			
		
	
		
			
				
					|  |  |  |  |     True -> return $ Right () | 
			
		
	
		
			
				
					|  |  |  |  |     False -> return $ Left ("User " ++ (T.unpack $ username u) | 
			
		
	
		
			
				
					|  |  |  |  |                                    ++ " exists already.") | 
			
		
	
		
			
				
					|  |  |  |  | doAction m (ModifyUser (UserUpdate n _ s h r p)) = do | 
			
		
	
		
			
				
					|  |  |  |  |   b <- protect m $ updateUser n s h r p | 
			
		
	
		
			
				
					|  |  |  |  |   case b of | 
			
		
	
		
			
				
					|  |  |  |  |     True -> return $ Right () | 
			
		
	
		
			
				
					|  |  |  |  |     False -> return $ Left ("User " ++ n | 
			
		
	
		
			
				
					|  |  |  |  |                                    ++ " does not exist.") | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | doConfig :: MVar () -> Config -> IO (Either String ()) | 
			
		
	
		
			
				
					|  |  |  |  | doConfig m (Config xs) = | 
			
		
	
		
			
				
					|  |  |  |  |   f . lefts <$>  mapM (doAction m) xs | 
			
		
	
		
			
				
					|  |  |  |  |   where f [] = Right () | 
			
		
	
		
			
				
					|  |  |  |  |         f ys = Left $ intercalate "\n" ys | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | -- creates a critical section of the IO action | 
			
		
	
		
			
				
					|  |  |  |  | protect :: MVar () -> IO a -> IO a | 
			
		
	
		
			
				
					|  |  |  |  | protect m act = do | 
			
		
	
		
			
				
					|  |  |  |  |   takeMVar m | 
			
		
	
		
			
				
					|  |  |  |  |   a <- act | 
			
		
	
		
			
				
					|  |  |  |  |   putMVar m () | 
			
		
	
		
			
				
					|  |  |  |  |   return a | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | formatUser :: User -> ByteString | 
			
		
	
		
			
				
					|  |  |  |  | formatUser (User _ uname sh homeDir rName _) = BS.concat | 
			
		
	
	
		
			
				
					|  |  |  | @ -40,37 +147,53 @@ formatUser (User _ uname sh homeDir rName _) = BS.concat | 
			
		
	
		
			
				
					|  |  |  |  |     , "Shell: ", e sh, "\n"] | 
			
		
	
		
			
				
					|  |  |  |  |     where e = encodeUtf8 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | returnUsers :: Socket -> MVar Bool -> IO () | 
			
		
	
		
			
				
					|  |  |  |  | returnUsers :: Socket -> MVar () -> IO () | 
			
		
	
		
			
				
					|  |  |  |  | returnUsers soc m = do | 
			
		
	
		
			
				
					|  |  |  |  |   rows <- getAllUsers-- m | 
			
		
	
		
			
				
					|  |  |  |  |   rows <- protect m getAllUsers | 
			
		
	
		
			
				
					|  |  |  |  |   let usernames = map username rows | 
			
		
	
		
			
				
					|  |  |  |  |       newlineSeparated = T.concat $ intersperse "\n" usernames | 
			
		
	
		
			
				
					|  |  |  |  |   sendAll soc (encodeUtf8 newlineSeparated) | 
			
		
	
		
			
				
					|  |  |  |  |       newlineSeparated = T.concat $ (intersperse "\n" usernames) | 
			
		
	
		
			
				
					|  |  |  |  |   sendAll soc (encodeUtf8 $ T.append newlineSeparated "\n") | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | returnUser :: Socket -> Text -> IO () | 
			
		
	
		
			
				
					|  |  |  |  | returnUser soc uname = do | 
			
		
	
		
			
				
					|  |  |  |  |   maybeUser <- getSingleUser uname | 
			
		
	
		
			
				
					|  |  |  |  | returnUser :: Socket -> MVar () -> Text -> IO () | 
			
		
	
		
			
				
					|  |  |  |  | returnUser soc m uname = do | 
			
		
	
		
			
				
					|  |  |  |  |   maybeUser <- protect m $ getSingleUser uname | 
			
		
	
		
			
				
					|  |  |  |  |   case maybeUser of | 
			
		
	
		
			
				
					|  |  |  |  |     Nothing -> do | 
			
		
	
		
			
				
					|  |  |  |  |       putStrLn $ "Couldn't find matching user for username: " ++ show uname | 
			
		
	
		
			
				
					|  |  |  |  |       return () | 
			
		
	
		
			
				
					|  |  |  |  |     Just user -> sendAll soc (formatUser user) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | handleQuery :: Socket -> MVar Bool -> IO () | 
			
		
	
		
			
				
					|  |  |  |  | -- Modified this to accept message longer than 1024 | 
			
		
	
		
			
				
					|  |  |  |  | -- keeping in mind that \r\n might be split over two packages | 
			
		
	
		
			
				
					|  |  |  |  | recvCommand :: Socket -> IO (Maybe ByteString) | 
			
		
	
		
			
				
					|  |  |  |  | recvCommand soc = getData >>= checkForCRLF | 
			
		
	
		
			
				
					|  |  |  |  |   where | 
			
		
	
		
			
				
					|  |  |  |  |     getData = recv soc 1024 | 
			
		
	
		
			
				
					|  |  |  |  |     checkForCRLF b = | 
			
		
	
		
			
				
					|  |  |  |  |       if BS.isInfixOf "\r\n" b | 
			
		
	
		
			
				
					|  |  |  |  |          then return . Just . BS.init . head . BS.split 0x0A $ b | 
			
		
	
		
			
				
					|  |  |  |  |          else getData >>= stopOrContinue b | 
			
		
	
		
			
				
					|  |  |  |  |     stopOrContinue b msg = | 
			
		
	
		
			
				
					|  |  |  |  |       if BS.null b | 
			
		
	
		
			
				
					|  |  |  |  |          then return Nothing | 
			
		
	
		
			
				
					|  |  |  |  |          else checkForCRLF $ BS.append b msg | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | handleQuery :: Socket -> MVar () -> IO () | 
			
		
	
		
			
				
					|  |  |  |  | handleQuery soc m = do | 
			
		
	
		
			
				
					|  |  |  |  |   msg <- recv soc 1024 | 
			
		
	
		
			
				
					|  |  |  |  |   msg <- recvCommand soc | 
			
		
	
		
			
				
					|  |  |  |  |   case msg of | 
			
		
	
		
			
				
					|  |  |  |  |     "\r\n" -> returnUsers soc m | 
			
		
	
		
			
				
					|  |  |  |  |     name -> returnUser soc (decodeUtf8 name) | 
			
		
	
		
			
				
					|  |  |  |  |     Nothing -> putStrLn "Client closed socket." | 
			
		
	
		
			
				
					|  |  |  |  |     Just "" -> returnUsers soc m | 
			
		
	
		
			
				
					|  |  |  |  |     Just n -> returnUser soc m (decodeUtf8 n) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | handleQueries :: Socket -> MVar Bool -> IO () | 
			
		
	
		
			
				
					|  |  |  |  | handleQueries :: Socket -> MVar () -> IO () | 
			
		
	
		
			
				
					|  |  |  |  | handleQueries sock m = forever $ do | 
			
		
	
		
			
				
					|  |  |  |  |   (soc, _) <- accept sock | 
			
		
	
		
			
				
					|  |  |  |  |   putStrLn "Got connection, handling query" | 
			
		
	
		
			
				
					|  |  |  |  |   handleQuery soc m | 
			
		
	
		
			
				
					|  |  |  |  |   Network.Socket.close soc -- sClose soc is deprecated | 
			
		
	
		
			
				
					|  |  |  |  |   close soc | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | fingerd :: MVar Bool -> IO () | 
			
		
	
		
			
				
					|  |  |  |  | fingerd :: MVar () -> IO () | 
			
		
	
		
			
				
					|  |  |  |  | fingerd m = do | 
			
		
	
		
			
				
					|  |  |  |  |   withSocketsDo $ do | 
			
		
	
		
			
				
					|  |  |  |  |     addrinfos <- getAddrInfo (Just (defaultHints {addrFlags = [AI_PASSIVE]})) | 
			
		
	
	
		
			
				
					|  |  |  | @ -78,42 +201,32 @@ fingerd m = do | 
			
		
	
		
			
				
					|  |  |  |  |                              (Just "79") | 
			
		
	
		
			
				
					|  |  |  |  |     let serveraddr = head addrinfos | 
			
		
	
		
			
				
					|  |  |  |  |     sock <- socket (addrFamily serveraddr) Stream defaultProtocol | 
			
		
	
		
			
				
					|  |  |  |  |     Network.Socket.bind sock (addrAddress serveraddr) | 
			
		
	
		
			
				
					|  |  |  |  |       -- bindSocket sock (addrAddress serveraddr) is deprecated | 
			
		
	
		
			
				
					|  |  |  |  |     listen sock 1 | 
			
		
	
		
			
				
					|  |  |  |  |     bind sock (addrAddress serveraddr) | 
			
		
	
		
			
				
					|  |  |  |  |     -- only one connection open at a time | 
			
		
	
		
			
				
					|  |  |  |  |     listen sock 1 | 
			
		
	
		
			
				
					|  |  |  |  |     handleQueries sock m | 
			
		
	
		
			
				
					|  |  |  |  |     Network.Socket.close sock -- sClose sock is deprecated | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | recvJson :: Socket -> IO ByteString | 
			
		
	
		
			
				
					|  |  |  |  | recvJson soc = do | 
			
		
	
		
			
				
					|  |  |  |  |   msg <- recv soc 1024 | 
			
		
	
		
			
				
					|  |  |  |  |   let l = BS.length msg | 
			
		
	
		
			
				
					|  |  |  |  |   case l of | 
			
		
	
		
			
				
					|  |  |  |  |     0 -> do | 
			
		
	
		
			
				
					|  |  |  |  |       msg' <- recvJson soc | 
			
		
	
		
			
				
					|  |  |  |  |       return $ msg `BS.append` msg' | 
			
		
	
		
			
				
					|  |  |  |  |     _ -> case BS.last msg of | 
			
		
	
		
			
				
					|  |  |  |  |       0 -> return $ BS.take (l - 1) msg | 
			
		
	
		
			
				
					|  |  |  |  |       _ -> do | 
			
		
	
		
			
				
					|  |  |  |  |         msg' <- recvJson soc | 
			
		
	
		
			
				
					|  |  |  |  |         return $ msg `BS.append` msg' | 
			
		
	
		
			
				
					|  |  |  |  |   -- return msg | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | handleRequest :: Socket -> MVar Bool -> IO () | 
			
		
	
		
			
				
					|  |  |  |  |     close sock | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | recvJson :: Socket -> IO (Maybe ByteString) | 
			
		
	
		
			
				
					|  |  |  |  | recvJson soc = recv soc 1024 >>= stopOrContinue | 
			
		
	
		
			
				
					|  |  |  |  |   where stopOrContinue b | 
			
		
	
		
			
				
					|  |  |  |  |           | BS.null b = return Nothing | 
			
		
	
		
			
				
					|  |  |  |  |           | BS.last b == 0 = (return . Just $ BS.init b) | 
			
		
	
		
			
				
					|  |  |  |  |           | otherwise = (fmap . fmap) (BS.append b) (recvJson soc) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | handleRequest :: Socket -> MVar () -> IO () | 
			
		
	
		
			
				
					|  |  |  |  | handleRequest sock m = forever $ do | 
			
		
	
		
			
				
					|  |  |  |  |   (soc, _) <- accept sock | 
			
		
	
		
			
				
					|  |  |  |  |   putStrLn "Woohoo!" | 
			
		
	
		
			
				
					|  |  |  |  |   j <- recvJson soc | 
			
		
	
		
			
				
					|  |  |  |  |   print j | 
			
		
	
		
			
				
					|  |  |  |  |   case decode (BSL.fromStrict j) of | 
			
		
	
		
			
				
					|  |  |  |  |     Nothing -> putStrLn "Cannot decode." | 
			
		
	
		
			
				
					|  |  |  |  |     (Just u) -> do | 
			
		
	
		
			
				
					|  |  |  |  |       putStrLn $ "Decoded User: " ++ show u | 
			
		
	
		
			
				
					|  |  |  |  |       addUser' m u | 
			
		
	
		
			
				
					|  |  |  |  |   Network.Socket.close soc -- sClose soc is deprecated | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | add :: MVar Bool -> IO () | 
			
		
	
		
			
				
					|  |  |  |  |   resp <- case j >>= (decode . BSL.fromStrict) of | 
			
		
	
		
			
				
					|  |  |  |  |     Nothing -> return "Cannot decode json.\r\n" | 
			
		
	
		
			
				
					|  |  |  |  |     (Just c) -> createMsg <$> doConfig m c | 
			
		
	
		
			
				
					|  |  |  |  |   sendAll soc resp | 
			
		
	
		
			
				
					|  |  |  |  |   close soc | 
			
		
	
		
			
				
					|  |  |  |  |   where createMsg (Right _) = "Actions succesfully applied.\r\n" | 
			
		
	
		
			
				
					|  |  |  |  |         createMsg (Left s) = fromString s | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | add :: MVar () -> IO () | 
			
		
	
		
			
				
					|  |  |  |  | add m = do | 
			
		
	
		
			
				
					|  |  |  |  |   withSocketsDo $ do | 
			
		
	
		
			
				
					|  |  |  |  |     addrinfos <- getAddrInfo (Just (defaultHints {addrFlags = [AI_PASSIVE]})) | 
			
		
	
	
		
			
				
					|  |  |  | @ -121,16 +234,13 @@ add m = do | 
			
		
	
		
			
				
					|  |  |  |  |                              (Just "4242") | 
			
		
	
		
			
				
					|  |  |  |  |     let serveraddr = head addrinfos | 
			
		
	
		
			
				
					|  |  |  |  |     sock <- socket (addrFamily serveraddr) Stream defaultProtocol | 
			
		
	
		
			
				
					|  |  |  |  |     Network.Socket.bind sock (addrAddress serveraddr) | 
			
		
	
		
			
				
					|  |  |  |  |       -- bindSocket sock (addrAddress serveraddr) is deprecated | 
			
		
	
		
			
				
					|  |  |  |  |     bind sock (addrAddress serveraddr) | 
			
		
	
		
			
				
					|  |  |  |  |     listen sock 1 | 
			
		
	
		
			
				
					|  |  |  |  |     -- only one connection open at a time | 
			
		
	
		
			
				
					|  |  |  |  |     handleRequest sock m | 
			
		
	
		
			
				
					|  |  |  |  |     Network.Socket.close sock -- sClose sock is deprecated | 
			
		
	
		
			
				
					|  |  |  |  |     close sock | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | main :: IO () | 
			
		
	
		
			
				
					|  |  |  |  | -- main = createDatabase | 
			
		
	
		
			
				
					|  |  |  |  | main = do | 
			
		
	
		
			
				
					|  |  |  |  |   m <- newMVar True | 
			
		
	
		
			
				
					|  |  |  |  |   m <- newMVar () | 
			
		
	
		
			
				
					|  |  |  |  |   _ <- forkIO $ add m | 
			
		
	
		
			
				
					|  |  |  |  |   fingerd m |