{-# Language OverloadedStrings #-}
module Client.Mask
( Mask
, matchMask
, buildMask
) where
import Irc.UserInfo
import Irc.Identifier
import Data.Text (Text)
import qualified Data.Text as Text
import Text.Regex.TDFA
import Text.Regex.TDFA.String (compile)
import Data.List
newtype Mask = Mask Regex
buildMask ::
[Identifier] ->
Mask
buildMask patterns =
case componentsToMask (map (translate . parseMaskComponents . idTextNorm) patterns) of
Left e -> error e
Right m -> m
matchMask :: Mask -> UserInfo -> Bool
matchMask (Mask re) userInfo =
matchTest re (Text.unpack (normalized (renderUserInfo userInfo)))
normalized :: Text -> Text
normalized = idTextNorm . mkId
parseMaskComponents :: Text -> String
parseMaskComponents str = Text.unpack nick ++ "!" ++ user ++ "@" ++ host
where
(nickuser,rawhost) = Text.break (=='@') str
(nick ,rawuser) = Text.break (=='!') nickuser
user = defaultWild rawuser
host = defaultWild rawhost
defaultWild x =
case Text.uncons x of
Nothing -> "*"
Just (_, y) -> Text.unpack y
componentsToMask :: [String] -> Either String Mask
componentsToMask xs =
Mask <$> compile defaultCompOpt { multiline = False }
defaultExecOpt { captureGroups = False }
("^(" ++ intercalate "|" xs ++ ")$")
translate :: String -> String
translate [] = []
translate ('\\' : '*' : xs) = '\\' : '*' : translate xs
translate ('\\' : '?' : xs) = '\\' : '?' : translate xs
translate ('\\' : '\\' : xs) = '\\' : '\\' : translate xs
translate ('*' : xs) = '.' : '*' : translate xs
translate ('?' : xs) = '.' : '?' : translate xs
translate (x : xs)
| isMetaChar x = '\\' : x : translate xs
| otherwise = x : translate xs
isMetaChar :: Char -> Bool
isMetaChar c = case c of
'^' -> True
'\\' -> True
'.' -> True
'|' -> True
'*' -> True
'?' -> True
'+' -> True
'(' -> True
')' -> True
'[' -> True
']' -> True
'{' -> True
'}' -> True
'$' -> True
_ -> False