initial, greets support is in babyyyy
This commit is contained in:
		
						commit
						c0a8b7b64d
					
				
							
								
								
									
										132
									
								
								Anna.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								Anna.hs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,132 @@
 | 
				
			|||||||
 | 
					module Main where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Data.List
 | 
				
			||||||
 | 
					import Data.Char (isSpace)
 | 
				
			||||||
 | 
					import System.IO
 | 
				
			||||||
 | 
					import System.Directory
 | 
				
			||||||
 | 
					import Control.Monad
 | 
				
			||||||
 | 
					import Control.Monad.IO.Class
 | 
				
			||||||
 | 
					import qualified Network.Socket as N
 | 
				
			||||||
 | 
					import Control.Monad.Trans.Reader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Configuration
 | 
				
			||||||
 | 
					hostname = "127.0.0.1"
 | 
				
			||||||
 | 
					port     = 6667
 | 
				
			||||||
 | 
					name     = "anna"
 | 
				
			||||||
 | 
					channels = ["#bots"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data Bot = Bot { socket :: Handle }
 | 
				
			||||||
 | 
					type Net = ReaderT Bot IO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Entrypoint
 | 
				
			||||||
 | 
					main :: IO ()
 | 
				
			||||||
 | 
					main = do
 | 
				
			||||||
 | 
					  handle <- connectTo hostname port
 | 
				
			||||||
 | 
					  hSetBuffering stdout NoBuffering
 | 
				
			||||||
 | 
					  runReaderT run Bot { socket = handle }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run :: Net ()
 | 
				
			||||||
 | 
					run = do
 | 
				
			||||||
 | 
					  sendNick
 | 
				
			||||||
 | 
					  sendUser
 | 
				
			||||||
 | 
					  joinChannels
 | 
				
			||||||
 | 
					  listen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					listen :: Net ()
 | 
				
			||||||
 | 
					listen = forever $ do
 | 
				
			||||||
 | 
					  h <- asks socket
 | 
				
			||||||
 | 
					  line <- liftIO $ hGetLine h
 | 
				
			||||||
 | 
					  -- Debug print
 | 
				
			||||||
 | 
					  liftIO $ putStrLn line
 | 
				
			||||||
 | 
					  tokenDispatch (parseUser $ tail line) (words line)
 | 
				
			||||||
 | 
					    where parseUser str = userName
 | 
				
			||||||
 | 
					            where userName = getName str
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  getName :: String -> Maybe String
 | 
				
			||||||
 | 
					                  getName s
 | 
				
			||||||
 | 
					                    | comesBefore ' ' '!' s = Nothing
 | 
				
			||||||
 | 
					                    | otherwise = Just $ takeWhile (\c -> (c /= '!')) s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  comesBefore :: Eq a => a -> a -> [a] -> Bool
 | 
				
			||||||
 | 
					                  comesBefore c1 c2 arr
 | 
				
			||||||
 | 
					                    | elemIndex c1 arr == Nothing = False
 | 
				
			||||||
 | 
					                    | elemIndex c2 arr == Nothing = True
 | 
				
			||||||
 | 
					                    | otherwise = elemIndex c1 arr < elemIndex c2 arr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tokenDispatch :: Maybe String -> [String] -> Net ()
 | 
				
			||||||
 | 
					tokenDispatch _ ("PING":_) = pong
 | 
				
			||||||
 | 
					tokenDispatch _ []         = return ()
 | 
				
			||||||
 | 
					tokenDispatch (Just userName) ts = if elem "PRIVMSG" ts
 | 
				
			||||||
 | 
					                                   then helper
 | 
				
			||||||
 | 
					                                   else return ()
 | 
				
			||||||
 | 
					  where helper
 | 
				
			||||||
 | 
					          | elem "o/" tokens  = updateRightGreets
 | 
				
			||||||
 | 
					          | elem "\\o" tokens = updateLeftGreets
 | 
				
			||||||
 | 
					          | otherwise         = case head tokens of
 | 
				
			||||||
 | 
					              "!greets" -> greets $ head channels
 | 
				
			||||||
 | 
					              _         -> return ()
 | 
				
			||||||
 | 
					        tokens = case length msgTokens of
 | 
				
			||||||
 | 
					          1 -> [rstrip $ tail $ head msgTokens]
 | 
				
			||||||
 | 
					          _ -> (tail $ head msgTokens) : ((init $ tail msgTokens) ++ [(rstrip $ last msgTokens)])
 | 
				
			||||||
 | 
					        msgTokens = drop 3 ts
 | 
				
			||||||
 | 
					        rstrip = reverse . dropWhile isSpace . reverse
 | 
				
			||||||
 | 
					tokenDispatch Nothing _         = return ()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Bot commands
 | 
				
			||||||
 | 
					updateRightGreets :: Net ()
 | 
				
			||||||
 | 
					updateRightGreets = do
 | 
				
			||||||
 | 
					  content <- liftIO $ readFile "greets"
 | 
				
			||||||
 | 
					  let contentLines = lines content
 | 
				
			||||||
 | 
					      rightGreets  = show $ 1 + (read $ head contentLines :: Int)
 | 
				
			||||||
 | 
					      leftGreets   = head $ tail contentLines
 | 
				
			||||||
 | 
					  liftIO $ removeFile "greets"
 | 
				
			||||||
 | 
					  liftIO $ writeFile "greets" $ rightGreets ++ "\n" ++ leftGreets ++ "\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					updateLeftGreets :: Net ()
 | 
				
			||||||
 | 
					updateLeftGreets = do
 | 
				
			||||||
 | 
					  content <- liftIO $ readFile "greets"
 | 
				
			||||||
 | 
					  let contentLines = lines content
 | 
				
			||||||
 | 
					      rightGreets  = head contentLines
 | 
				
			||||||
 | 
					      leftGreets   = show $ 1 + (read $ head $ tail contentLines :: Int)
 | 
				
			||||||
 | 
					  liftIO $ removeFile "greets"
 | 
				
			||||||
 | 
					  liftIO $ writeFile "greets" $ rightGreets ++ "\n" ++ leftGreets ++ "\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					greets :: String -> Net ()
 | 
				
			||||||
 | 
					greets chn = do
 | 
				
			||||||
 | 
					  content <- liftIO $ readFile "greets"
 | 
				
			||||||
 | 
					  let contentLines = lines content
 | 
				
			||||||
 | 
					      displayLine = "o/ - " ++ (head contentLines) ++ " vs \\o - " ++ (head $ tail contentLines)
 | 
				
			||||||
 | 
					  liftIO $ putStrLn displayLine
 | 
				
			||||||
 | 
					  sendMessage chn displayLine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Basic commands
 | 
				
			||||||
 | 
					write :: String -> String -> Net ()
 | 
				
			||||||
 | 
					write cmd args = do
 | 
				
			||||||
 | 
					  h <- asks socket
 | 
				
			||||||
 | 
					  liftIO $ hPutStr h $ cmd ++ " " ++ args ++ "\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sendNick :: Net ()
 | 
				
			||||||
 | 
					sendNick = write "NICK" name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sendUser :: Net ()
 | 
				
			||||||
 | 
					sendUser = write "USER" $ name ++ " 0.0.0.0 " ++ name ++ " :" ++ name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sendMessage :: String -> String -> Net ()
 | 
				
			||||||
 | 
					sendMessage channel message = write "PRIVMSG" $ channel ++ " :" ++ message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sendAction :: String -> String -> Net ()
 | 
				
			||||||
 | 
					sendAction channel action = sendMessage channel $ "\x01ACTION " ++ action ++ "\x01"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					joinChannels :: Net ()
 | 
				
			||||||
 | 
					joinChannels = mapM_ (\chn -> write "JOIN" chn) channels
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pong :: Net ()
 | 
				
			||||||
 | 
					pong = write "PONG" $ ":" ++ name ++ "\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Connect to a server given its name and port number
 | 
				
			||||||
 | 
					connectTo :: N.HostName -> N.PortNumber -> IO Handle
 | 
				
			||||||
 | 
					connectTo host port = do
 | 
				
			||||||
 | 
					    addr : _ <- N.getAddrInfo Nothing (Just host) (Just (show port))
 | 
				
			||||||
 | 
					    sock <- N.socket (N.addrFamily addr) (N.addrSocketType addr) (N.addrProtocol addr)
 | 
				
			||||||
 | 
					    N.connect sock (N.addrAddress addr)
 | 
				
			||||||
 | 
					    N.socketToHandle sock ReadWriteMode
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user