2014-05-25 05:30:49 +05:30
|
|
|
module Network.IRC.Protocol
|
|
|
|
( MessagePart (..)
|
|
|
|
, parseLine
|
2014-06-08 05:33:03 +05:30
|
|
|
, formatCommand) where
|
2014-05-04 02:57:43 +05:30
|
|
|
|
2014-05-10 21:45:16 +05:30
|
|
|
import ClassyPrelude
|
2014-06-08 05:33:03 +05:30
|
|
|
import Data.Foldable (msum)
|
|
|
|
import Data.List ((!!))
|
|
|
|
import Data.Text (strip)
|
2014-05-04 02:57:43 +05:30
|
|
|
|
|
|
|
import Network.IRC.Types
|
|
|
|
|
2014-10-04 21:22:24 +05:30
|
|
|
parseLine :: BotConfig -> UTCTime -> Text -> [MessagePart] -> (Maybe Message, [MessagePart])
|
2014-06-08 04:26:50 +05:30
|
|
|
parseLine botConfig@BotConfig { .. } time line msgParts =
|
2014-06-08 07:12:33 +05:30
|
|
|
fromMaybe (Nothing, msgParts) . msum . flip map parsers $ \MessageParser { .. } ->
|
|
|
|
let (parserMsgParts, otherParserMsgParts) = partition ((msgParserId ==) . msgPartParserId) msgParts
|
2014-06-08 05:33:03 +05:30
|
|
|
in case msgParser botConfig time line parserMsgParts of
|
|
|
|
Reject -> Nothing
|
|
|
|
Partial msgParts' -> Just (Nothing, msgParts' ++ otherParserMsgParts)
|
|
|
|
Done message' msgParts' -> Just (Just message', msgParts' ++ otherParserMsgParts)
|
2014-05-25 05:30:49 +05:30
|
|
|
where
|
2014-06-08 04:26:50 +05:30
|
|
|
parsers = [pingParser, namesParser, lineParser] ++ msgParsers ++ [defaultParser]
|
2014-05-25 14:51:33 +05:30
|
|
|
|
|
|
|
pingParser :: MessageParser
|
2014-06-08 04:26:50 +05:30
|
|
|
pingParser = MessageParser "ping" go
|
|
|
|
where
|
|
|
|
go _ time line _
|
2014-10-04 21:22:24 +05:30
|
|
|
| "PING :" `isPrefixOf` line = Done (Message time line . toMessage . PingMsg . drop 6 $ line) []
|
2014-06-08 04:26:50 +05:30
|
|
|
| otherwise = Reject
|
2014-05-25 05:30:49 +05:30
|
|
|
|
2014-06-08 04:26:50 +05:30
|
|
|
parseMsgLine :: Text -> ([Text], Text, Text, Text, Text)
|
|
|
|
parseMsgLine line = (splits, command, source, target, message)
|
2014-05-04 02:57:43 +05:30
|
|
|
where
|
2014-06-08 07:12:33 +05:30
|
|
|
splits = words line
|
|
|
|
command = splits !! 1
|
|
|
|
source = drop 1 $ splits !! 0
|
|
|
|
target = splits !! 2
|
|
|
|
message = strip . drop 1 . unwords . drop 3 $ splits
|
2014-05-20 00:05:06 +05:30
|
|
|
|
2014-06-08 04:26:50 +05:30
|
|
|
lineParser :: MessageParser
|
|
|
|
lineParser = MessageParser "line" go
|
|
|
|
where
|
|
|
|
go BotConfig { .. } time line _ =
|
|
|
|
case command of
|
|
|
|
"PONG" -> done $ toMessage $ PongMsg message
|
|
|
|
"JOIN" -> done $ toMessage $ JoinMsg user
|
|
|
|
"QUIT" -> done $ toMessage $ QuitMsg user quitMessage
|
|
|
|
"PART" -> done $ toMessage $ PartMsg user message
|
|
|
|
"KICK" -> done $ toMessage $ KickMsg user (Nick kicked) kickReason
|
2014-10-04 21:22:24 +05:30
|
|
|
"MODE" -> done $ toMessage $ if Nick target == botNick
|
2014-06-08 04:26:50 +05:30
|
|
|
then ModeMsg Self target message []
|
|
|
|
else ModeMsg user target mode modeArgs
|
|
|
|
"NICK" -> done $ toMessage $ NickMsg user $ Nick (drop 1 target)
|
|
|
|
"433" -> done $ toMessage NickInUseMsg
|
2014-10-04 21:22:24 +05:30
|
|
|
"PRIVMSG" | target /= botChannel -> done $ toMessage $ PrivMsg user message
|
|
|
|
| isActionMsg -> done $ toMessage $ ActionMsg user (initDef . drop 8 $ message)
|
|
|
|
| otherwise -> done $ toMessage $ ChannelMsg user message
|
2014-06-08 04:26:50 +05:30
|
|
|
_ -> Reject
|
|
|
|
where
|
2014-10-04 21:22:24 +05:30
|
|
|
done = flip Done [] . Message time line
|
2014-06-08 04:26:50 +05:30
|
|
|
|
|
|
|
(splits, command, source, target, message) = parseMsgLine line
|
|
|
|
quitMessage = strip . drop 1 . unwords . drop 2 $ splits
|
|
|
|
user = uncurry User . (Nick *** drop 1) . break (== '!') $ source
|
|
|
|
mode = splits !! 3
|
|
|
|
modeArgs = drop 4 splits
|
|
|
|
kicked = splits !! 3
|
|
|
|
kickReason = drop 1 . unwords . drop 4 $ splits
|
|
|
|
isActionMsg = "\SOH" `isPrefixOf` message && "ACTION" `isPrefixOf` drop 1 message
|
|
|
|
|
|
|
|
defaultParser :: MessageParser
|
|
|
|
defaultParser = MessageParser "default" go
|
|
|
|
where
|
2014-10-04 21:22:24 +05:30
|
|
|
go _ time line _ = flip Done [] . Message time line $
|
2014-06-08 04:26:50 +05:30
|
|
|
toMessage $ OtherMsg source command target message
|
|
|
|
where
|
|
|
|
(_, command, source, target, message) = parseMsgLine line
|
2014-05-25 05:30:49 +05:30
|
|
|
|
|
|
|
namesParser :: MessageParser
|
2014-06-08 04:26:50 +05:30
|
|
|
namesParser = MessageParser "names" go
|
2014-05-25 05:30:49 +05:30
|
|
|
where
|
2014-06-08 04:26:50 +05:30
|
|
|
go BotConfig { .. } time line msgParts = case command of
|
|
|
|
"353" -> Partial $ MessagePart "names" target time line : msgParts
|
|
|
|
"366" -> let
|
|
|
|
(myMsgParts, otherMsgParts) = partition ((target ==) . msgPartTarget) msgParts
|
|
|
|
(nicks, allLines) = concat *** intercalate "\r\n" . (++ [line])
|
|
|
|
$ unzip $ map (\MessagePart { .. } -> (namesNicks msgPartLine, msgPartLine)) myMsgParts
|
2014-10-04 21:22:24 +05:30
|
|
|
in Done (Message time allLines . toMessage $ NamesMsg nicks) otherMsgParts
|
2014-06-08 04:26:50 +05:30
|
|
|
_ -> Reject
|
|
|
|
where
|
|
|
|
(_ : command : target : _) = words line
|
|
|
|
stripNickPrefix = pack . dropWhile (`elem` ("~&@%+" :: String)) . unpack
|
|
|
|
namesNicks line' =
|
|
|
|
map (Nick . stripNickPrefix) . words . drop 1 . unwords . drop 5 . words $ line'
|
2014-05-04 02:57:43 +05:30
|
|
|
|
2014-06-08 05:33:03 +05:30
|
|
|
formatCommand :: CommandFormatter
|
2014-10-04 21:22:24 +05:30
|
|
|
formatCommand botConfig@BotConfig { .. } message =
|
|
|
|
msum . map (\formatter -> formatter botConfig message) $ defaultCommandFormatter : cmdFormatters
|
2014-06-08 05:33:03 +05:30
|
|
|
|
|
|
|
defaultCommandFormatter :: CommandFormatter
|
2014-10-04 21:22:24 +05:30
|
|
|
defaultCommandFormatter BotConfig { .. } Message { .. }
|
|
|
|
| Just (PongCmd msg) <- fromMessage message = Just $ "PONG :" ++ msg
|
|
|
|
| Just (PingCmd msg) <- fromMessage message = Just $ "PING :" ++ msg
|
|
|
|
| Just NickCmd <- fromMessage message = Just $ "NICK " ++ botNick'
|
|
|
|
| Just UserCmd <- fromMessage message =
|
2014-06-08 04:26:50 +05:30
|
|
|
Just $ "USER " ++ botNick' ++ " 0 * :" ++ botNick'
|
2014-10-04 21:22:24 +05:30
|
|
|
| Just JoinCmd <- fromMessage message = Just $ "JOIN " ++ botChannel
|
|
|
|
| Just QuitCmd <- fromMessage message = Just "QUIT"
|
|
|
|
| Just (ChannelMsgReply msg) <- fromMessage message =
|
|
|
|
Just $ "PRIVMSG " ++ botChannel ++ " :" ++ msg
|
|
|
|
| Just (PrivMsgReply (User { .. }) msg) <- fromMessage message =
|
2014-06-08 04:26:50 +05:30
|
|
|
Just $ "PRIVMSG " ++ nickToText userNick ++ " :" ++ msg
|
2014-10-04 21:22:24 +05:30
|
|
|
| Just NamesCmd <- fromMessage message = Just $ "NAMES " ++ botChannel
|
2014-06-08 07:12:33 +05:30
|
|
|
| otherwise = Nothing
|
2014-06-01 23:14:19 +05:30
|
|
|
where
|
|
|
|
botNick' = nickToText botNick
|