{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE QuasiQuotes           #-}
{-# LANGUAGE RankNTypes            #-}
{-# LANGUAGE RecordWildCards       #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE OverloadedStrings     #-}
--These can disappear once we remove Content Posn versions
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}



-----------------------------------------------------------------------------
-- |
-- Module      :  Network.XMPP.Stanza
-- Copyright   :  (c) pierre, 2007
-- License     :  BSD-style (see the file libraries/base/LICENSE)
-- Copyright   :  (c) riskbook, 2020
-- SPDX-License-Identifier:  BSD3
--
-- Maintainer  :  k.pierre.k@gmail.com
-- Stability   :  experimental
-- Portability :  portable
--
-- XMPP stanzas parsing
--
-----------------------------------------------------------------------------

module Network.XMPP.Stanza
  ( StanzaEncoder(..)
  , StanzaDecoder(..)
  ) where

import           Control.Applicative         (Alternative, empty)
import           Data.Maybe                  (mapMaybe, listToMaybe)
import qualified Data.Text                   as T
import           Text.Hamlet.XML             (xml)
import           Text.XML                    (Node)
import           Text.XML.HaXml              (Content)
import           Text.XML.HaXml.Posn         (Posn)
import           Text.XML.HaXml.Xtract.Parse (xtract)
import           Network.XMPP.Types
import           Network.XMPP.XML

--------------------------------------------------------------------------------

class StanzaEncoder t p e a where
  encodeStanza :: Stanza t p e -> a

class StanzaDecoder t p e a where
  decodeStanza :: a -> Maybe (Stanza t p e)

--------------------------------------------------------------------------------

condToAlt :: Alternative m => (x -> Bool) -> x -> m x
condToAlt :: (x -> Bool) -> x -> m x
condToAlt x -> Bool
f x
x = if x -> Bool
f x
x then x -> m x
forall (f :: * -> *) a. Applicative f => a -> f a
pure x
x else m x
forall (f :: * -> *) a. Alternative f => f a
empty

toAttrList :: [(String, Maybe a)] -> [(String, a)]
toAttrList :: [(String, Maybe a)] -> [(String, a)]
toAttrList = ((String, Maybe a) -> Maybe (String, a))
-> [(String, Maybe a)] -> [(String, a)]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (String, Maybe a) -> Maybe (String, a)
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence

instance {-# OVERLAPPING #-} StanzaEncoder 'Message 'Outgoing e Node where
  encodeStanza :: Stanza 'Message 'Outgoing e -> Node
encodeStanza MkMessage{Maybe SomeJID
Text
Sing 'Outgoing
MessageType
DataByPurpose 'Outgoing e
mPurpose :: forall (p :: StanzaPurpose) ext. Stanza 'Message p ext -> Sing p
mExt :: forall (p :: StanzaPurpose) ext.
Stanza 'Message p ext -> DataByPurpose p ext
mThread :: forall (p :: StanzaPurpose) ext. Stanza 'Message p ext -> Text
mBody :: forall (p :: StanzaPurpose) ext. Stanza 'Message p ext -> Text
mSubject :: forall (p :: StanzaPurpose) ext. Stanza 'Message p ext -> Text
mType :: forall (p :: StanzaPurpose) ext.
Stanza 'Message p ext -> MessageType
mId :: forall (p :: StanzaPurpose) ext. Stanza 'Message p ext -> Text
mTo :: forall (p :: StanzaPurpose) ext.
Stanza 'Message p ext -> Maybe SomeJID
mFrom :: forall (p :: StanzaPurpose) ext.
Stanza 'Message p ext -> Maybe SomeJID
mPurpose :: Sing 'Outgoing
mExt :: DataByPurpose 'Outgoing e
mThread :: Text
mBody :: Text
mSubject :: Text
mType :: MessageType
mId :: Text
mTo :: Maybe SomeJID
mFrom :: Maybe SomeJID
..} = [Node] -> Node
forall a. [a] -> a
head [xml|
    <message *{messageAttrs} xml:lang=en>
      <body *{bodyAttrs}>
        #{mBody}
  |]
    where
      messageAttrs :: [(String, String)]
messageAttrs = [(String, Maybe String)] -> [(String, String)]
forall a. [(String, Maybe a)] -> [(String, a)]
toAttrList
        [ (String
"from", SomeJID -> String
forall a. Show a => a -> String
show (SomeJID -> String) -> Maybe SomeJID -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe SomeJID
mFrom)
        , (String
"to", SomeJID -> String
forall a. Show a => a -> String
show (SomeJID -> String) -> Maybe SomeJID -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe SomeJID
mTo)
        , (String
"id", String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack Text
mId)
        , (String
"type", String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ MessageType -> String
forall a. Show a => a -> String
show MessageType
mType)
        ]
      bodyAttrs :: [(String, String)]
bodyAttrs = [(String, Maybe String)] -> [(String, String)]
forall a. [(String, Maybe a)] -> [(String, a)]
toAttrList
        [ (String
"subject", Text -> String
T.unpack (Text -> String) -> Maybe Text -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Text -> Bool) -> Text -> Maybe Text
forall (m :: * -> *) x. Alternative m => (x -> Bool) -> x -> m x
condToAlt (Bool -> Bool
not (Bool -> Bool) -> (Text -> Bool) -> Text -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Bool
T.null) Text
mSubject)
        , (String
"thread", Text -> String
T.unpack (Text -> String) -> Maybe Text -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Text -> Bool) -> Text -> Maybe Text
forall (m :: * -> *) x. Alternative m => (x -> Bool) -> x -> m x
condToAlt (Bool -> Bool
not (Bool -> Bool) -> (Text -> Bool) -> Text -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Bool
T.null) Text
mThread)
        ]

instance {-# OVERLAPPING #-} StanzaEncoder 'Presence 'Outgoing e Node where
  encodeStanza :: Stanza 'Presence 'Outgoing e -> Node
encodeStanza MkPresence{ pPurpose :: forall (p :: StanzaPurpose) ext. Stanza 'Presence p ext -> Sing p
pPurpose = Sing 'Outgoing
SOutgoing, Maybe Integer
Maybe SomeJID
Text
ShowType
PresenceType
DataByPurpose 'Outgoing e
pExt :: forall (p :: StanzaPurpose) ext.
Stanza 'Presence p ext -> DataByPurpose p ext
pPriority :: forall (p :: StanzaPurpose) ext.
Stanza 'Presence p ext -> Maybe Integer
pStatus :: forall (p :: StanzaPurpose) ext. Stanza 'Presence p ext -> Text
pShowType :: forall (p :: StanzaPurpose) ext. Stanza 'Presence p ext -> ShowType
pType :: forall (p :: StanzaPurpose) ext.
Stanza 'Presence p ext -> PresenceType
pId :: forall (p :: StanzaPurpose) ext. Stanza 'Presence p ext -> Text
pTo :: forall (p :: StanzaPurpose) ext.
Stanza 'Presence p ext -> Maybe SomeJID
pFrom :: forall (p :: StanzaPurpose) ext.
Stanza 'Presence p ext -> Maybe SomeJID
pExt :: DataByPurpose 'Outgoing e
pPriority :: Maybe Integer
pStatus :: Text
pShowType :: ShowType
pType :: PresenceType
pId :: Text
pTo :: Maybe SomeJID
pFrom :: Maybe SomeJID
..} = [Node] -> Node
forall a. [a] -> a
head [xml|
    <presence *{attrs} xml:lang="en">
      ^{pExt}
    |]
    where
      attrs :: [(String, String)]
attrs = [(String, Maybe String)] -> [(String, String)]
forall a. [(String, Maybe a)] -> [(String, a)]
toAttrList
        [ (String
"from", SomeJID -> String
forall a. Show a => a -> String
show (SomeJID -> String) -> Maybe SomeJID -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe SomeJID
pFrom)
        , (String
"to", SomeJID -> String
forall a. Show a => a -> String
show (SomeJID -> String) -> Maybe SomeJID -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe SomeJID
pTo)
        , (String
"id", Text -> String
T.unpack (Text -> String) -> Maybe Text -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Text -> Bool) -> Text -> Maybe Text
forall (m :: * -> *) x. Alternative m => (x -> Bool) -> x -> m x
condToAlt (Bool -> Bool
not (Bool -> Bool) -> (Text -> Bool) -> Text -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Bool
T.null) Text
pId)
        , (String
"type", PresenceType -> String
forall a. Show a => a -> String
show (PresenceType -> String) -> Maybe PresenceType -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (PresenceType -> Bool) -> PresenceType -> Maybe PresenceType
forall (m :: * -> *) x. Alternative m => (x -> Bool) -> x -> m x
condToAlt (PresenceType -> PresenceType -> Bool
forall a. Eq a => a -> a -> Bool
/= PresenceType
Default) PresenceType
pType)
        , (String
"show", ShowType -> String
forall a. Show a => a -> String
show (ShowType -> String) -> Maybe ShowType -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (ShowType -> Bool) -> ShowType -> Maybe ShowType
forall (m :: * -> *) x. Alternative m => (x -> Bool) -> x -> m x
condToAlt (ShowType -> ShowType -> Bool
forall a. Eq a => a -> a -> Bool
/= ShowType
Available) ShowType
pShowType)
        , (String
"status", Text -> String
T.unpack (Text -> String) -> Maybe Text -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Text -> Bool) -> Text -> Maybe Text
forall (m :: * -> *) x. Alternative m => (x -> Bool) -> x -> m x
condToAlt (Bool -> Bool
not (Bool -> Bool) -> (Text -> Bool) -> Text -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Bool
T.null) Text
pStatus)
        , (String
"priority", Integer -> String
forall a. Show a => a -> String
show (Integer -> String) -> Maybe Integer -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Integer
pPriority)
        ]

instance {-# OVERLAPPING #-} StanzaEncoder 'IQ 'Outgoing e Node where
  encodeStanza :: Stanza 'IQ 'Outgoing e -> Node
encodeStanza MkIQ{ iqPurpose :: forall (p :: StanzaPurpose) ext. Stanza 'IQ p ext -> Sing p
iqPurpose = Sing 'Outgoing
SOutgoing, Maybe SomeJID
Text
IQType
DataByPurpose 'Outgoing e
iqBody :: forall (p :: StanzaPurpose) ext.
Stanza 'IQ p ext -> DataByPurpose p ext
iqType :: forall (p :: StanzaPurpose) ext. Stanza 'IQ p ext -> IQType
iqId :: forall (p :: StanzaPurpose) ext. Stanza 'IQ p ext -> Text
iqTo :: forall (p :: StanzaPurpose) ext. Stanza 'IQ p ext -> Maybe SomeJID
iqFrom :: forall (p :: StanzaPurpose) ext. Stanza 'IQ p ext -> Maybe SomeJID
iqBody :: DataByPurpose 'Outgoing e
iqType :: IQType
iqId :: Text
iqTo :: Maybe SomeJID
iqFrom :: Maybe SomeJID
..} = [Node] -> Node
forall a. [a] -> a
head [xml|
    <iq *{attrs} xml:lang="en">
      ^{iqBody}
  |]
    where
      attrs :: [(String, String)]
attrs = [(String, Maybe String)] -> [(String, String)]
forall a. [(String, Maybe a)] -> [(String, a)]
toAttrList
        [ (String
"from", SomeJID -> String
forall a. Show a => a -> String
show (SomeJID -> String) -> Maybe SomeJID -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe SomeJID
iqFrom)
        , (String
"to", SomeJID -> String
forall a. Show a => a -> String
show (SomeJID -> String) -> Maybe SomeJID -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe SomeJID
iqTo)
        , (String
"id", String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack Text
iqId)
        , (String
"type", String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ IQType -> String
forall a. Show a => a -> String
show IQType
iqType)
        ]

instance StanzaEncoder t 'Outgoing e Node where
  encodeStanza :: Stanza t 'Outgoing e -> Node
encodeStanza s :: Stanza t 'Outgoing e
s@MkPresence{} = Stanza t 'Outgoing e -> Node
forall (t :: StanzaType) (p :: StanzaPurpose) e a.
StanzaEncoder t p e a =>
Stanza t p e -> a
encodeStanza Stanza t 'Outgoing e
s
  encodeStanza s :: Stanza t 'Outgoing e
s@MkMessage{}  = Stanza t 'Outgoing e -> Node
forall (t :: StanzaType) (p :: StanzaPurpose) e a.
StanzaEncoder t p e a =>
Stanza t p e -> a
encodeStanza Stanza t 'Outgoing e
s
  encodeStanza s :: Stanza t 'Outgoing e
s@MkIQ{}       = Stanza t 'Outgoing e -> Node
forall (t :: StanzaType) (p :: StanzaPurpose) e a.
StanzaEncoder t p e a =>
Stanza t p e -> a
encodeStanza Stanza t 'Outgoing e
s

instance FromXML e => StanzaDecoder 'Message 'Incoming e (Content Posn) where
  decodeStanza :: Content Posn -> Maybe (Stanza 'Message 'Incoming e)
decodeStanza Content Posn
m =
    let content :: [Content Posn]
content = (String -> String) -> String -> CFilter Posn
forall i. (String -> String) -> String -> CFilter i
xtract String -> String
forall a. a -> a
id String
"/message/*" Content Posn
m
    in
      Stanza 'Message 'Incoming e -> Maybe (Stanza 'Message 'Incoming e)
forall a. a -> Maybe a
Just (Stanza 'Message 'Incoming e
 -> Maybe (Stanza 'Message 'Incoming e))
-> Stanza 'Message 'Incoming e
-> Maybe (Stanza 'Message 'Incoming e)
forall a b. (a -> b) -> a -> b
$ MkMessage :: forall (p :: StanzaPurpose) ext.
Maybe SomeJID
-> Maybe SomeJID
-> Text
-> MessageType
-> Text
-> Text
-> Text
-> DataByPurpose p ext
-> Sing p
-> Stanza 'Message p ext
MkMessage
        { mFrom :: Maybe SomeJID
mFrom    = Text -> Maybe SomeJID
forall a. Read a => Text -> Maybe a
mread (Text -> Maybe SomeJID) -> Text -> Maybe SomeJID
forall a b. (a -> b) -> a -> b
$ Text -> Content Posn -> Text
txtpat Text
"/message/@from" Content Posn
m
        , mTo :: Maybe SomeJID
mTo      = Text -> Maybe SomeJID
forall a. Read a => Text -> Maybe a
mread (Text -> Maybe SomeJID) -> Text -> Maybe SomeJID
forall a b. (a -> b) -> a -> b
$ Text -> Content Posn -> Text
txtpat Text
"/message/@to" Content Posn
m
        , mId :: Text
mId      = [Content Posn] -> Text
forall i. [Content i] -> Text
getText_ ([Content Posn] -> Text) -> [Content Posn] -> Text
forall a b. (a -> b) -> a -> b
$ (String -> String) -> String -> CFilter Posn
forall i. (String -> String) -> String -> CFilter i
xtract String -> String
forall a. a -> a
id String
"/message/@id" Content Posn
m
        , mType :: MessageType
mType    = String -> MessageType
forall a. Read a => String -> a
read (String -> MessageType) -> String -> MessageType
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ [Content Posn] -> Text
forall i. [Content i] -> Text
getText_ ([Content Posn] -> Text) -> [Content Posn] -> Text
forall a b. (a -> b) -> a -> b
$ (String -> String) -> String -> CFilter Posn
forall i. (String -> String) -> String -> CFilter i
xtract String -> String
forall a. a -> a
id String
"/message/@type" Content Posn
m
        , mSubject :: Text
mSubject = [Content Posn] -> Text
forall i. [Content i] -> Text
getText_ ([Content Posn] -> Text) -> [Content Posn] -> Text
forall a b. (a -> b) -> a -> b
$ (String -> String) -> String -> CFilter Posn
forall i. (String -> String) -> String -> CFilter i
xtract String -> String
forall a. a -> a
id String
"/message/subject/-" Content Posn
m
        , mBody :: Text
mBody    = [Content Posn] -> Text
forall i. [Content i] -> Text
getText_ ([Content Posn] -> Text) -> [Content Posn] -> Text
forall a b. (a -> b) -> a -> b
$ (String -> String) -> String -> CFilter Posn
forall i. (String -> String) -> String -> CFilter i
xtract String -> String
forall a. a -> a
id String
"/message/body/-" Content Posn
m
        , mThread :: Text
mThread  = [Content Posn] -> Text
forall i. [Content i] -> Text
getText_ ([Content Posn] -> Text) -> [Content Posn] -> Text
forall a b. (a -> b) -> a -> b
$ (String -> String) -> String -> CFilter Posn
forall i. (String -> String) -> String -> CFilter i
xtract String -> String
forall a. a -> a
id String
"/message/thread/-" Content Posn
m
        , mExt :: DataByPurpose 'Incoming e
mExt     = Either [Content Posn] e
-> (e -> Either [Content Posn] e)
-> Maybe e
-> Either [Content Posn] e
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ([Content Posn] -> Either [Content Posn] e
forall a b. a -> Either a b
Left [Content Posn]
content) e -> Either [Content Posn] e
forall a b. b -> Either a b
Right (Maybe e -> Either [Content Posn] e)
-> Maybe e -> Either [Content Posn] e
forall a b. (a -> b) -> a -> b
$ [e] -> Maybe e
forall a. [a] -> Maybe a
listToMaybe ([e] -> Maybe e) -> [e] -> Maybe e
forall a b. (a -> b) -> a -> b
$ (Content Posn -> Maybe e) -> [Content Posn] -> [e]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Content Posn -> Maybe e
forall a. FromXML a => Content Posn -> Maybe a
decodeXml
                                                                         [Content Posn]
content
        , mPurpose :: Sing 'Incoming
mPurpose = Sing 'Incoming
SIncoming
        }

instance FromXML e => StanzaDecoder 'Presence 'Incoming e (Content Posn) where
  decodeStanza :: Content Posn -> Maybe (Stanza 'Presence 'Incoming e)
decodeStanza Content Posn
m =
    let content :: [Content Posn]
content = (String -> String) -> String -> CFilter Posn
forall i. (String -> String) -> String -> CFilter i
xtract String -> String
forall a. a -> a
id String
"/presence/*" Content Posn
m
    in
      Stanza 'Presence 'Incoming e
-> Maybe (Stanza 'Presence 'Incoming e)
forall a. a -> Maybe a
Just (Stanza 'Presence 'Incoming e
 -> Maybe (Stanza 'Presence 'Incoming e))
-> Stanza 'Presence 'Incoming e
-> Maybe (Stanza 'Presence 'Incoming e)
forall a b. (a -> b) -> a -> b
$ MkPresence :: forall (p :: StanzaPurpose) ext.
Maybe SomeJID
-> Maybe SomeJID
-> Text
-> PresenceType
-> ShowType
-> Text
-> Maybe Integer
-> DataByPurpose p ext
-> Sing p
-> Stanza 'Presence p ext
MkPresence
        { pFrom :: Maybe SomeJID
pFrom     = Text -> Maybe SomeJID
forall a. Read a => Text -> Maybe a
mread (Text -> Maybe SomeJID) -> Text -> Maybe SomeJID
forall a b. (a -> b) -> a -> b
$ Text -> Content Posn -> Text
txtpat Text
"/presence/@from" Content Posn
m
        , pTo :: Maybe SomeJID
pTo       = Text -> Maybe SomeJID
forall a. Read a => Text -> Maybe a
mread (Text -> Maybe SomeJID) -> Text -> Maybe SomeJID
forall a b. (a -> b) -> a -> b
$ Text -> Content Posn -> Text
txtpat Text
"/presence/@to" Content Posn
m
        , pId :: Text
pId       = Text -> Content Posn -> Text
txtpat Text
"/presence/@id" Content Posn
m
        , pType :: PresenceType
pType     = String -> PresenceType
forall a. Read a => String -> a
read (String -> PresenceType) -> String -> PresenceType
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ Text -> Content Posn -> Text
txtpat Text
"/presence/@type" Content Posn
m
        , pShowType :: ShowType
pShowType = String -> ShowType
forall a. Read a => String -> a
read (String -> ShowType) -> String -> ShowType
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ Text -> Content Posn -> Text
txtpat Text
"/presence/show/-" Content Posn
m
        , pStatus :: Text
pStatus   = Text -> Content Posn -> Text
txtpat Text
"/presence/status/-" Content Posn
m
        , pPriority :: Maybe Integer
pPriority = Text -> Maybe Integer
forall a. Read a => Text -> Maybe a
mread (Text -> Maybe Integer) -> Text -> Maybe Integer
forall a b. (a -> b) -> a -> b
$ Text -> Content Posn -> Text
txtpat Text
"/presence/priority/-" Content Posn
m
        , pPurpose :: Sing 'Incoming
pPurpose  = Sing 'Incoming
SIncoming
        , pExt :: DataByPurpose 'Incoming e
pExt = Either [Content Posn] e
-> (e -> Either [Content Posn] e)
-> Maybe e
-> Either [Content Posn] e
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ([Content Posn] -> Either [Content Posn] e
forall a b. a -> Either a b
Left [Content Posn]
content) e -> Either [Content Posn] e
forall a b. b -> Either a b
Right (Maybe e -> Either [Content Posn] e)
-> Maybe e -> Either [Content Posn] e
forall a b. (a -> b) -> a -> b
$ [e] -> Maybe e
forall a. [a] -> Maybe a
listToMaybe ([e] -> Maybe e) -> [e] -> Maybe e
forall a b. (a -> b) -> a -> b
$ (Content Posn -> Maybe e) -> [Content Posn] -> [e]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Content Posn -> Maybe e
forall a. FromXML a => Content Posn -> Maybe a
decodeXml [Content Posn]
content
        }

instance FromXML e => StanzaDecoder 'IQ 'Incoming e (Content Posn) where
  decodeStanza :: Content Posn -> Maybe (Stanza 'IQ 'Incoming e)
decodeStanza Content Posn
m =
    let content :: [Content Posn]
content = (String -> String) -> String -> CFilter Posn
forall i. (String -> String) -> String -> CFilter i
xtract String -> String
forall a. a -> a
id String
"/iq/*" Content Posn
m
    in
      Stanza 'IQ 'Incoming e -> Maybe (Stanza 'IQ 'Incoming e)
forall a. a -> Maybe a
Just MkIQ :: forall (p :: StanzaPurpose) ext.
Maybe SomeJID
-> Maybe SomeJID
-> Text
-> IQType
-> DataByPurpose p ext
-> Sing p
-> Stanza 'IQ p ext
MkIQ
        { iqFrom :: Maybe SomeJID
iqFrom    = Text -> Maybe SomeJID
forall a. Read a => Text -> Maybe a
mread (Text -> Maybe SomeJID) -> Text -> Maybe SomeJID
forall a b. (a -> b) -> a -> b
$ Text -> Content Posn -> Text
txtpat Text
"/iq/@from" Content Posn
m
        , iqTo :: Maybe SomeJID
iqTo      = Text -> Maybe SomeJID
forall a. Read a => Text -> Maybe a
mread (Text -> Maybe SomeJID) -> Text -> Maybe SomeJID
forall a b. (a -> b) -> a -> b
$ Text -> Content Posn -> Text
txtpat Text
"/iq/@to" Content Posn
m
        , iqId :: Text
iqId      = Text -> Content Posn -> Text
txtpat Text
"/iq/@id" Content Posn
m
        , iqType :: IQType
iqType    = String -> IQType
forall a. Read a => String -> a
read (String -> IQType) -> String -> IQType
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ Text -> Content Posn -> Text
txtpat Text
"/iq/@type" Content Posn
m
        , iqBody :: DataByPurpose 'Incoming e
iqBody = Either [Content Posn] e
-> (e -> Either [Content Posn] e)
-> Maybe e
-> Either [Content Posn] e
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ([Content Posn] -> Either [Content Posn] e
forall a b. a -> Either a b
Left [Content Posn]
content) e -> Either [Content Posn] e
forall a b. b -> Either a b
Right (Maybe e -> Either [Content Posn] e)
-> Maybe e -> Either [Content Posn] e
forall a b. (a -> b) -> a -> b
$ [e] -> Maybe e
forall a. [a] -> Maybe a
listToMaybe ([e] -> Maybe e) -> [e] -> Maybe e
forall a b. (a -> b) -> a -> b
$ (Content Posn -> Maybe e) -> [Content Posn] -> [e]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Content Posn -> Maybe e
forall a. FromXML a => Content Posn -> Maybe a
decodeXml
                                                                      [Content Posn]
content
        , iqPurpose :: Sing 'Incoming
iqPurpose = Sing 'Incoming
SIncoming
        }