packages feed

irc-fun-messages-0.4: src/Network/Irc/Messages/Internal/Tokens/Target.hs

{- This file is part of irc-fun-messages.
 -
 - Written in 2015 by fr33domlover <fr33domlover@rel4tion.org>.
 -
 - ♡ Copying is an act of love. Please copy, reuse and share.
 -
 - The author(s) have dedicated all copyright and related and neighboring
 - rights to this software to the public domain worldwide. This software is
 - distributed without any warranty.
 -
 - You should have received a copy of the CC0 Public Domain Dedication along
 - with this software. If not, see
 - <http://creativecommons.org/publicdomain/zero/1.0/>.
 -}

module Network.Irc.Messages.Internal.Tokens.Target
    ( target
    , msgtarget
    , msgto
    , channel
    , servername
    , host
    , nickname
    )
where

import Data.Char (isAsciiUpper)
import Data.Text (Text, pack)
import Network.Irc.Messages.Internal.Tokens.Other
import Network.Irc.Messages.Internal.Tokens.Wildcards
import Network.Irc.Messages.Internal.Types
import Network.Irc.Types
import Text.Regex.Applicative

target :: Regex Target
target = NickTarget <$> nickname <|> ServerTarget <$> servername

msgtarget :: Regex [MessageTarget]
msgtarget = (:) <$> msgto <*> many (sym ',' *> msgto)

msgto :: Regex MessageTarget
msgto = ChannelTarget <$> channel
    <|> uhs <$> user
            <*> optional (sym '%' *> host) <* sym '@'
            <*> servername
    <|> uh <$> user <* sym '%'
           <*> host
    <|> MaskTarget <$> targetmask
    <|> nn <$> nickname
    <|> nuh <$> nickname <* sym '!'
            <*> user <* sym '@'
            <*> host
    where
    uhs u h s = UserTarget Nothing  (Just (UserAddress u h))        (Just s)
    uh  u h   = UserTarget Nothing  (Just (UserAddress u (Just h))) Nothing
    nn  n     = UserTarget (Just n) Nothing                      Nothing
    nuh n u h = UserTarget (Just n) (Just (UserAddress u (Just h))) Nothing

channel :: Regex Channel
channel =
    Channel . pack . snd <$>
    withMatched
    ( (sym '#' <|> sym '+' <|> sym '!' <* channelid <|> sym '&') <*
      chanstring                                                 <*
      optional (sym ':' <* chanstring)
    )

servername :: Regex Hostname
servername = hostname

host :: Regex Host
host =
    HostByAddr  <$> hostaddr
    <|>
    HostByName  <$> hostname
    <|>
    HostCloak   <$> hostcloak

hostname :: Regex Hostname
hostname =
    Hostname . pack . snd <$>
    withMatched (shortname <* many (sym '.' <* shortname))

shortname :: Regex String
shortname =
    snd <$> withMatched
        ( (letter <|> digit) <*
          optional (many (letter <|> digit <|> sym '-') <* (letter <|> digit))
        )

hostaddr :: Regex Address
hostaddr = IPv4 <$> ip4addr <|> IPv6 <$> ip6addr

ip4addr :: Regex Text
ip4addr = pack . snd <$> withMatched (s <* p <* s <* p <* s <* p <* s)
    where
    d = digit
    s = snd <$> withMatched (d  <|>  d <* d  <|>  d <* d <* d)
    p = sym '.'

ip6addr :: Regex Text
ip6addr = pack . snd <$> withMatched (full <|> short <|> v4)
    where
    h = some hexdigit'
    c = sym ':'
    s = h <* many (c <* h)
    full = h <* c <* h <* c <*
           h <* c <* h <* c <*
           h <* c <* h <* c <*
           h <* c <* h
    short = optional s *> string "::" <* optional s
    v4 = string "0:0:0:0:0:" <*
         (string "0" <|> string "FFFF") <*
         sym ':' <*
         ip4addr

hostcloak :: Regex Text
hostcloak =
    pack <$> some (letter <|> digit <|> special <|> psym (`elem` ".-/"))

nickname :: Regex Nickname
nickname =
    Nickname . pack <$>
    ( (:)                                             <$>
      (letter <|> special)                            <*>
      many (letter <|> digit <|> special <|> sym '-')
    )

targetmask :: Regex TargetMask
targetmask = ServerMask <$> (sym '$' *> mask)
         <|> HostMask   <$> (sym '#' *> mask)

chanstring :: Regex String
chanstring = many $ psym (`notElem` "\0\a\r\n ,:")

channelid :: Regex String
channelid = snd <$> withMatched (c *> c *> c *> c *> c)
    where
    c = psym isAsciiUpper <|> digit