module Util where
import Prelude ()
import BasicPrelude
import Control.Applicative (many)
import Data.Time (getCurrentTime)
import Data.XML.Types (Element(..), Node(NodeElement), isNamed, elementText, elementChildren, attributeText)
import qualified Data.Text as T
import qualified Network.Protocol.XMPP as XMPP
import qualified Data.Attoparsec.Text as Atto
log :: (Show a, MonadIO m) => String -> a -> m ()
log tag x = liftIO $ do
time <- getCurrentTime
putStr (show time ++ s" " ++ fromString tag ++ s" :: ") >> print x >> putStrLn mempty
s :: (IsString a) => String -> a
s = fromString
escapeJid :: Text -> Text
escapeJid txt = mconcat result
where
Right result = Atto.parseOnly (many (
slashEscape <|>
replace ' ' "\\20" <|>
replace '"' "\\22" <|>
replace '&' "\\26" <|>
replace '\'' "\\27" <|>
replace '/' "\\2f" <|>
replace ':' "\\3a" <|>
replace '<' "\\3c" <|>
replace '>' "\\3e" <|>
replace '@' "\\40" <|>
fmap T.singleton Atto.anyChar
) <* Atto.endOfInput) txt
replace c str = Atto.char c *> pure (fromString str)
-- XEP-0106 says to only escape \ when absolutely necessary
slashEscape =
fmap (s"\\5c"++) $
Atto.char '\\' *> Atto.choice escapes
escapes = map (Atto.string . fromString) [
"20", "22", "26", "27", "2f", "3a", "3c", "3e", "40", "5c"
]
unescapeJid :: Text -> Text
unescapeJid txt = fromString result
where
Right result = Atto.parseOnly (many (
(Atto.char '\\' *> Atto.choice unescapes) <|>
Atto.anyChar
) <* Atto.endOfInput) txt
unescapes = map (\(str, c) -> Atto.string (fromString str) *> pure c) [
("20", ' '), ("22", '"'), ("26", '&'), ("27", '\''), ("2f", '/'), ("3a", ':'), ("3c", '<'), ("3e", '>'), ("40", '@'), ("5c", '\\')
]
bareTxt (XMPP.JID (Just node) domain _) = mconcat [XMPP.strNode node, s"@", XMPP.strDomain domain]
bareTxt (XMPP.JID Nothing domain _) = XMPP.strDomain domain
getFormField form var =
listToMaybe $ mapMaybe (\node ->
case node of
NodeElement el
| elementName el == s"{jabber:x:data}field" &&
(attributeText (s"{jabber:x:data}var") el == Just var ||
attributeText (s"var") el == Just var) ->
Just $ mconcat $
elementText =<< isNamed (s"{jabber:x:data}value") =<< elementChildren el
_ -> Nothing
) (elementNodes form)