haskell-xmpp-2.0.0: src/Network/XMPP/XEP/MAM.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE RecordWildCards #-}
-----------------------------------------------------------------------------
-- |
-- Copyright : (c) riskbook, 2020
-- SPDX-License-Identifier: BSD3
--
-----------------------------------------------------------------------------
module Network.XMPP.XEP.MAM
( messageArchiveQueryStanza
, defMamQuery
, MAMQuery(..)
, MAMPayload(..)
) where
import qualified Data.UUID as UUID
import Data.Time (UTCTime)
import Data.Text (Text, pack)
import Data.Maybe (catMaybes)
import Text.Hamlet.XML (xml)
import Network.XMPP.Types
import Network.XMPP.XML (ToXML(..), FromXML(..), matchPatterns,
txtpat, mread)
import Network.XMPP.XEP.Form (XmppForm(..), XmppField(..))
--
-- Messaging archives management extenstion
-- https://xmpp.org/extensions/xep-0313.html#query
--
messageArchiveQueryStanza :: MAMQuery -> UUID.UUID -> Stanza 'IQ 'Outgoing ()
messageArchiveQueryStanza MAMQuery {..} uuid =
let form = XmppForm $ catMaybes
[ Just $ HiddenField "FORM_TYPE" "urn:xmpp:mam:2"
, SingleTextField "with" . pack . show <$> mqWith
, SingleTextField "start" . pack . show <$> mqStart
, SingleTextField "end" . pack . show <$> mqEnd
]
in MkIQ { iqFrom = Nothing
, iqTo = SomeJID <$> mqRoom
, iqId = UUID.toText uuid
, iqType = Set
, iqPurpose = SOutgoing
, iqBody = [xml|
<query xmlns="urn:xmpp:mam:2">
^{encodeXml form}
<set xmlns="http://jabber.org/protocol/rsm">
<max>#{pack $ show mqLimit}
$maybe afterId <- mqAfter
<after>#{afterId}
$if mqFromLatest
<before>
$maybe beforeId <- mqBefore
#{beforeId}
$else
$maybe beforeId <- mqBefore
<before>#{beforeId}
|]
}
data MAMQuery = MAMQuery
{ mqStart :: Maybe UTCTime
, mqEnd :: Maybe UTCTime
, mqWith :: Maybe (JID 'Node)
, mqRoom :: Maybe (JID 'Node)
, mqLimit :: Int
, mqAfter :: Maybe Text
, mqBefore :: Maybe Text
, mqFromLatest :: Bool
} deriving (Show)
defMamQuery :: MAMQuery
defMamQuery = MAMQuery
{ mqStart = Nothing
, mqEnd = Nothing
, mqWith = Nothing
, mqRoom = Nothing
, mqLimit = 10
, mqAfter = Nothing
, mqBefore = Nothing
, mqFromLatest = False
}
data MAMPayload = MAMFinalPayload
{ mComplete :: Bool
, mLast :: Text
, mFirst :: Text
, mFirstIdx :: Text
, mCount :: Int
} deriving (Show)
instance FromXML MAMPayload where
decodeXml m
| matchPatterns m ["/fin/@complete", "/fin/set/count"]
= MAMFinalPayload
<$> decodeBool (txtpat "/fin/@complete" m)
<*> Just (txtpat "/fin/set/last/-" m)
<*> Just (txtpat "/fin/set/first/-" m)
<*> Just (txtpat "/fin/set/first@index" m)
<*> mread (txtpat "/fin/set/count/-" m)
| otherwise
= Nothing
where
decodeBool "true" = Just True
decodeBool "false" = Just False
decodeBool _ = Nothing