packages feed

pontarius-xmpp 0.4.0.2 → 0.4.1.0

raw patch · 24 files changed

+1034/−320 lines, 24 filesdep +HUnitdep +configuratordep +exceptionsdep ~basedep ~hsloggerdep ~mtlnew-uploaderPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: HUnit, configurator, exceptions, lens-family, profunctors, x509-system

Dependency ranges changed: base, hslogger, mtl, network, stm, text, tls, transformers, xml-picklers, xml-types

API changes (from Hackage documentation)

+ Network.Xmpp: IQRequestSendError :: XmppFailure -> IQRequestError
+ Network.Xmpp: IQRequestTimeout :: IQRequestError
+ Network.Xmpp: IQRequestUnpickleError :: UnpickleError -> IQRequestError
+ Network.Xmpp: class IQRequestClass a where data family IQResponseType a
+ Network.Xmpp: data IQRequestError
+ Network.Xmpp: enablePresenceTracking :: SessionConfiguration -> Bool
+ Network.Xmpp: iqErrorAttributes :: IQError -> ![ExtendedAttribute]
+ Network.Xmpp: iqRequestAttributes :: IQRequest -> ![ExtendedAttribute]
+ Network.Xmpp: iqResultAttributes :: IQResult -> ![ExtendedAttribute]
+ Network.Xmpp: messageAttributes :: Message -> ![ExtendedAttribute]
+ Network.Xmpp: messageErrorAttributes :: MessageError -> ![ExtendedAttribute]
+ Network.Xmpp: onPresenceChange :: SessionConfiguration -> Maybe (Jid -> PeerStatus -> PeerStatus -> IO ())
+ Network.Xmpp: pickleRequest :: IQRequestClass a => PU Element a
+ Network.Xmpp: pickleResponse :: IQRequestClass a => PU [Element] (IQResponseType a)
+ Network.Xmpp: presenceAttributes :: Presence -> ![ExtendedAttribute]
+ Network.Xmpp: presenceErrorAttributes :: PresenceError -> ![ExtendedAttribute]
+ Network.Xmpp: requestNamespace :: IQRequestClass a => a -> Text
+ Network.Xmpp: requestType :: IQRequestClass a => a -> IQRequestType
+ Network.Xmpp: runIQHandler :: IQRequestClass a => IQRequestHandler a -> Session -> IO ()
+ Network.Xmpp: sendIQRequest :: (IQRequestClass a, MonadError IQRequestError m, MonadIO m) => Maybe Integer -> Maybe Jid -> a -> Session -> m (Either IQError (IQResponseType a))
+ Network.Xmpp: streamState :: Session -> STM ConnectionState
+ Network.Xmpp: type IQRequestHandler a = a -> IO (Either StanzaError (IQResponseType a))
+ Network.Xmpp.IM: PeerAvailable :: (Maybe IMPresence) -> PeerStatus
+ Network.Xmpp.IM: PeerUnavailable :: PeerStatus
+ Network.Xmpp.IM: data PeerStatus
+ Network.Xmpp.IM: getAvailablePeers :: Session -> STM [Jid]
+ Network.Xmpp.IM: getEntityStatus :: Jid -> Session -> STM PeerStatus
+ Network.Xmpp.IM: getPeerEntities :: Jid -> Session -> STM (Map Jid (Maybe IMPresence))
+ Network.Xmpp.IM: getRosterSTM :: Session -> STM Roster
+ Network.Xmpp.IM: isPeerAvailable :: Jid -> Session -> STM Bool
+ Network.Xmpp.Internal: (+++) :: ByteString -> ByteString -> ByteString
+ Network.Xmpp.Internal: (<~) :: Jid -> Jid -> Bool
+ Network.Xmpp.Internal: Auth :: StanzaErrorType
+ Network.Xmpp.Internal: AuthIllegalCredentials :: AuthFailure
+ Network.Xmpp.Internal: AuthNoAcceptableMechanism :: [Text] -> AuthFailure
+ Network.Xmpp.Internal: AuthOtherFailure :: AuthFailure
+ Network.Xmpp.Internal: AuthSaslFailure :: SaslFailure -> AuthFailure
+ Network.Xmpp.Internal: AuthStreamFailure :: XmppFailure -> AuthFailure
+ Network.Xmpp.Internal: Available :: PresenceType
+ Network.Xmpp.Internal: BadRequest :: StanzaErrorCondition
+ Network.Xmpp.Internal: Both :: Subscription
+ Network.Xmpp.Internal: Cancel :: StanzaErrorType
+ Network.Xmpp.Internal: Chat :: MessageType
+ Network.Xmpp.Internal: Closed :: ConnectionState
+ Network.Xmpp.Internal: Conflict :: StanzaErrorCondition
+ Network.Xmpp.Internal: Continue :: StanzaErrorType
+ Network.Xmpp.Internal: EventHandlers :: (XmppFailure -> IO ()) -> EventHandlers
+ Network.Xmpp.Internal: FeatureNotImplemented :: StanzaErrorCondition
+ Network.Xmpp.Internal: Finished :: ConnectionState
+ Network.Xmpp.Internal: Forbidden :: StanzaErrorCondition
+ Network.Xmpp.Internal: From :: Subscription
+ Network.Xmpp.Internal: Get :: IQRequestType
+ Network.Xmpp.Internal: Gone :: (Maybe NonemptyText) -> StanzaErrorCondition
+ Network.Xmpp.Internal: GroupChat :: MessageType
+ Network.Xmpp.Internal: Headline :: MessageType
+ Network.Xmpp.Internal: IMP :: Maybe ShowStatus -> Maybe Text -> Maybe Int -> IMPresence
+ Network.Xmpp.Internal: IQError :: !Text -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !StanzaError -> !(Maybe Element) -> ![ExtendedAttribute] -> IQError
+ Network.Xmpp.Internal: IQRequest :: !Text -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !IQRequestType -> !Element -> ![ExtendedAttribute] -> IQRequest
+ Network.Xmpp.Internal: IQRequestSendError :: XmppFailure -> IQRequestError
+ Network.Xmpp.Internal: IQRequestTicket :: (Either StanzaError (Maybe Element) -> [ExtendedAttribute] -> IO (Maybe (Either XmppFailure ()))) -> IQRequest -> [Annotation] -> IQRequestTicket
+ Network.Xmpp.Internal: IQRequestTimeout :: IQRequestError
+ Network.Xmpp.Internal: IQRequestUnpickleError :: UnpickleError -> IQRequestError
+ Network.Xmpp.Internal: IQResponseError :: IQError -> IQResponse
+ Network.Xmpp.Internal: IQResponseResult :: IQResult -> IQResponse
+ Network.Xmpp.Internal: IQResult :: !Text -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !(Maybe Element) -> ![ExtendedAttribute] -> IQResult
+ Network.Xmpp.Internal: IQSendError :: XmppFailure -> IQSendError
+ Network.Xmpp.Internal: IQTimeOut :: IQSendError
+ Network.Xmpp.Internal: InstantMessage :: Maybe MessageThread -> [MessageSubject] -> [MessageBody] -> InstantMessage
+ Network.Xmpp.Internal: InternalServerError :: StanzaErrorCondition
+ Network.Xmpp.Internal: Interrupt :: (TMVar ()) -> Interrupt
+ Network.Xmpp.Internal: Item :: Bool -> Bool -> Jid -> Maybe Text -> Subscription -> [Text] -> Item
+ Network.Xmpp.Internal: ItemNotFound :: StanzaErrorCondition
+ Network.Xmpp.Internal: Jid :: !(Maybe NonemptyText) -> !NonemptyText -> !(Maybe NonemptyText) -> Jid
+ Network.Xmpp.Internal: JidMalformed :: StanzaErrorCondition
+ Network.Xmpp.Internal: LangTag :: !Text -> ![Text] -> LangTag
+ Network.Xmpp.Internal: Message :: !(Maybe Text) -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !MessageType -> ![Element] -> ![ExtendedAttribute] -> Message
+ Network.Xmpp.Internal: MessageBody :: Maybe LangTag -> Text -> MessageBody
+ Network.Xmpp.Internal: MessageError :: !(Maybe Text) -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !StanzaError -> ![Element] -> ![ExtendedAttribute] -> MessageError
+ Network.Xmpp.Internal: MessageSubject :: Maybe LangTag -> Text -> MessageSubject
+ Network.Xmpp.Internal: MessageThread :: Text -> Maybe Text -> MessageThread
+ Network.Xmpp.Internal: Modify :: StanzaErrorType
+ Network.Xmpp.Internal: None :: Subscription
+ Network.Xmpp.Internal: Nonempty :: Text -> NonemptyText
+ Network.Xmpp.Internal: Normal :: MessageType
+ Network.Xmpp.Internal: NotAcceptable :: StanzaErrorCondition
+ Network.Xmpp.Internal: NotAllowed :: StanzaErrorCondition
+ Network.Xmpp.Internal: NotAuthorized :: StanzaErrorCondition
+ Network.Xmpp.Internal: Plain :: ConnectionState
+ Network.Xmpp.Internal: PolicyViolation :: StanzaErrorCondition
+ Network.Xmpp.Internal: Presence :: !(Maybe Text) -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !PresenceType -> ![Element] -> ![ExtendedAttribute] -> Presence
+ Network.Xmpp.Internal: PresenceError :: !(Maybe Text) -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !StanzaError -> ![Element] -> ![ExtendedAttribute] -> PresenceError
+ Network.Xmpp.Internal: Probe :: PresenceType
+ Network.Xmpp.Internal: Query :: Maybe Text -> [QueryItem] -> Query
+ Network.Xmpp.Internal: QueryItem :: Maybe Bool -> Bool -> Jid -> Maybe Text -> Maybe Subscription -> [Text] -> QueryItem
+ Network.Xmpp.Internal: RecipientUnavailable :: StanzaErrorCondition
+ Network.Xmpp.Internal: Redirect :: (Maybe NonemptyText) -> StanzaErrorCondition
+ Network.Xmpp.Internal: RegistrationRequired :: StanzaErrorCondition
+ Network.Xmpp.Internal: RemoteServerNotFound :: StanzaErrorCondition
+ Network.Xmpp.Internal: RemoteServerTimeout :: StanzaErrorCondition
+ Network.Xmpp.Internal: Remove :: Subscription
+ Network.Xmpp.Internal: ResourceConstraint :: StanzaErrorCondition
+ Network.Xmpp.Internal: Roster :: Maybe Text -> Map Jid Item -> Roster
+ Network.Xmpp.Internal: SaslAborted :: SaslError
+ Network.Xmpp.Internal: SaslAccountDisabled :: SaslError
+ Network.Xmpp.Internal: SaslChallenge :: (Maybe Text) -> SaslElement
+ Network.Xmpp.Internal: SaslCredentialsExpired :: SaslError
+ Network.Xmpp.Internal: SaslEncryptionRequired :: SaslError
+ Network.Xmpp.Internal: SaslFailure :: SaslError -> Maybe (Maybe LangTag, Text) -> SaslFailure
+ Network.Xmpp.Internal: SaslIncorrectEncoding :: SaslError
+ Network.Xmpp.Internal: SaslInvalidAuthzid :: SaslError
+ Network.Xmpp.Internal: SaslInvalidMechanism :: SaslError
+ Network.Xmpp.Internal: SaslMalformedRequest :: SaslError
+ Network.Xmpp.Internal: SaslMechanismTooWeak :: SaslError
+ Network.Xmpp.Internal: SaslNotAuthorized :: SaslError
+ Network.Xmpp.Internal: SaslSuccess :: (Maybe Text) -> SaslElement
+ Network.Xmpp.Internal: SaslTemporaryAuthFailure :: SaslError
+ Network.Xmpp.Internal: Secured :: ConnectionState
+ Network.Xmpp.Internal: ServiceUnavailable :: StanzaErrorCondition
+ Network.Xmpp.Internal: Session :: TChan (Stanza, [Annotation]) -> TVar IQHandlers -> WriteSemaphore -> ThreadId -> IO Text -> TMVar Stream -> TMVar EventHandlers -> IO () -> TVar Roster -> TVar Peers -> SessionConfiguration -> (Stanza -> IO (Either XmppFailure ())) -> HostName -> Maybe (ConnectionState -> [SaslHandler], Maybe Text) -> TVar Int -> Session
+ Network.Xmpp.Internal: SessionConfiguration :: StreamConfiguration -> (Session -> XmppFailure -> IO ()) -> IO (IO Text) -> [Plugin] -> Bool -> Bool -> Maybe (Jid -> PeerStatus -> PeerStatus -> IO ()) -> SessionConfiguration
+ Network.Xmpp.Internal: Set :: IQRequestType
+ Network.Xmpp.Internal: StanzaError :: StanzaErrorType -> StanzaErrorCondition -> Maybe (Maybe LangTag, NonemptyText) -> Maybe Element -> StanzaError
+ Network.Xmpp.Internal: StatusAway :: ShowStatus
+ Network.Xmpp.Internal: StatusChat :: ShowStatus
+ Network.Xmpp.Internal: StatusDnd :: ShowStatus
+ Network.Xmpp.Internal: StatusXa :: ShowStatus
+ Network.Xmpp.Internal: StreamBadFormat :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamBadNamespacePrefix :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamCloseError :: ([Element], XmppFailure) -> XmppFailure
+ Network.Xmpp.Internal: StreamConflict :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamConnectionTimeout :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamEndFailure :: XmppFailure
+ Network.Xmpp.Internal: StreamErrorFailure :: StreamErrorInfo -> XmppFailure
+ Network.Xmpp.Internal: StreamErrorInfo :: !StreamErrorCondition -> !(Maybe (Maybe LangTag, NonemptyText)) -> !(Maybe Element) -> StreamErrorInfo
+ Network.Xmpp.Internal: StreamHostGone :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamHostUnknown :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamImproperAddressing :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamInternalServerError :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamInvalidFrom :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamInvalidNamespace :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamInvalidXml :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamNotAuthorized :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamNotWellFormed :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamPolicyViolation :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamRemoteConnectionFailed :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamReset :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamResourceConstraint :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamRestrictedXml :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamSeeOtherHost :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamSystemShutdown :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamUndefinedCondition :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamUnsupportedEncoding :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamUnsupportedFeature :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamUnsupportedStanzaType :: StreamErrorCondition
+ Network.Xmpp.Internal: StreamUnsupportedVersion :: StreamErrorCondition
+ Network.Xmpp.Internal: Subscribe :: PresenceType
+ Network.Xmpp.Internal: Subscribed :: PresenceType
+ Network.Xmpp.Internal: SubscriptionRequired :: StanzaErrorCondition
+ Network.Xmpp.Internal: TcpConnectionFailure :: XmppFailure
+ Network.Xmpp.Internal: TlsError :: XmppTlsError -> XmppFailure
+ Network.Xmpp.Internal: TlsNoServerSupport :: XmppFailure
+ Network.Xmpp.Internal: TlsStreamSecured :: XmppFailure
+ Network.Xmpp.Internal: To :: Subscription
+ Network.Xmpp.Internal: Unavailable :: PresenceType
+ Network.Xmpp.Internal: UndefinedCondition :: StanzaErrorCondition
+ Network.Xmpp.Internal: UnexpectedRequest :: StanzaErrorCondition
+ Network.Xmpp.Internal: Unsubscribe :: PresenceType
+ Network.Xmpp.Internal: Unsubscribed :: PresenceType
+ Network.Xmpp.Internal: UseConnection :: (ErrorT XmppFailure IO StreamHandle) -> ConnectionDetails
+ Network.Xmpp.Internal: UseHost :: HostName -> PortID -> ConnectionDetails
+ Network.Xmpp.Internal: UseRealm :: ConnectionDetails
+ Network.Xmpp.Internal: UseSrv :: HostName -> ConnectionDetails
+ Network.Xmpp.Internal: Version :: !Integer -> !Integer -> Version
+ Network.Xmpp.Internal: Wait :: StanzaErrorType
+ Network.Xmpp.Internal: XmppAuthFailure :: AuthFailure -> XmppFailure
+ Network.Xmpp.Internal: XmppIOException :: IOException -> XmppFailure
+ Network.Xmpp.Internal: XmppIllegalTcpDetails :: XmppFailure
+ Network.Xmpp.Internal: XmppInvalidXml :: String -> XmppFailure
+ Network.Xmpp.Internal: XmppNoStream :: XmppFailure
+ Network.Xmpp.Internal: XmppOtherFailure :: XmppFailure
+ Network.Xmpp.Internal: XmppTlsError :: TLSError -> XmppTlsError
+ Network.Xmpp.Internal: XmppTlsException :: TLSException -> XmppTlsError
+ Network.Xmpp.Internal: answerIM :: [MessageBody] -> Message -> Maybe Message
+ Network.Xmpp.Internal: answerIQ :: IQRequestTicket -> Either StanzaError (Maybe Element) -> [ExtendedAttribute] -> IO (Maybe (Either XmppFailure ()))
+ Network.Xmpp.Internal: answerMessage :: Message -> [Element] -> Maybe Message
+ Network.Xmpp.Internal: answerTicket :: IQRequestTicket -> Either StanzaError (Maybe Element) -> [ExtendedAttribute] -> IO (Maybe (Either XmppFailure ()))
+ Network.Xmpp.Internal: bodyContent :: MessageBody -> Text
+ Network.Xmpp.Internal: bodyLang :: MessageBody -> Maybe LangTag
+ Network.Xmpp.Internal: bufferSrc :: Source (ErrorT XmppFailure IO) o -> IO (ConduitM i o (ErrorT XmppFailure IO) ())
+ Network.Xmpp.Internal: catchPush :: IO () -> IO (Either XmppFailure ())
+ Network.Xmpp.Internal: checkHostName :: Text -> Maybe Text
+ Network.Xmpp.Internal: class IQRequestClass a where data family IQResponseType a
+ Network.Xmpp.Internal: client :: (MonadIO m, CPRG rng) => ClientParams -> rng -> Backend -> m Context
+ Network.Xmpp.Internal: closeConnection :: Session -> IO ()
+ Network.Xmpp.Internal: closeStreams :: Stream -> IO ()
+ Network.Xmpp.Internal: closeStreams' :: StateT StreamState IO ()
+ Network.Xmpp.Internal: conf :: Session -> SessionConfiguration
+ Network.Xmpp.Internal: connPersist :: TMVar (ByteString -> IO a) -> IO ()
+ Network.Xmpp.Internal: connect :: HostName -> StreamConfiguration -> ErrorT XmppFailure IO (Maybe StreamHandle)
+ Network.Xmpp.Internal: connectSrv :: ResolvConf -> String -> ErrorT XmppFailure IO (Maybe Handle)
+ Network.Xmpp.Internal: connectTcp :: [(HostName, PortID)] -> IO (Maybe Handle)
+ Network.Xmpp.Internal: connectionClosedHandler :: EventHandlers -> XmppFailure -> IO ()
+ Network.Xmpp.Internal: createStream :: HostName -> StreamConfiguration -> ErrorT XmppFailure IO (Stream)
+ Network.Xmpp.Internal: data AuthFailure
+ Network.Xmpp.Internal: data ConnectionDetails
+ Network.Xmpp.Internal: data ConnectionState
+ Network.Xmpp.Internal: data EventHandlers
+ Network.Xmpp.Internal: data IMPresence
+ Network.Xmpp.Internal: data IQError
+ Network.Xmpp.Internal: data IQRequest
+ Network.Xmpp.Internal: data IQRequestError
+ Network.Xmpp.Internal: data IQRequestTicket
+ Network.Xmpp.Internal: data IQRequestType
+ Network.Xmpp.Internal: data IQResponse
+ Network.Xmpp.Internal: data IQResult
+ Network.Xmpp.Internal: data IQSendError
+ Network.Xmpp.Internal: data InstantMessage
+ Network.Xmpp.Internal: data Interrupt
+ Network.Xmpp.Internal: data Item
+ Network.Xmpp.Internal: data Jid
+ Network.Xmpp.Internal: data LangTag
+ Network.Xmpp.Internal: data Message
+ Network.Xmpp.Internal: data MessageBody
+ Network.Xmpp.Internal: data MessageError
+ Network.Xmpp.Internal: data MessageSubject
+ Network.Xmpp.Internal: data MessageThread
+ Network.Xmpp.Internal: data MessageType
+ Network.Xmpp.Internal: data Presence
+ Network.Xmpp.Internal: data PresenceError
+ Network.Xmpp.Internal: data PresenceType
+ Network.Xmpp.Internal: data Query
+ Network.Xmpp.Internal: data QueryItem
+ Network.Xmpp.Internal: data Roster
+ Network.Xmpp.Internal: data SaslElement
+ Network.Xmpp.Internal: data SaslError
+ Network.Xmpp.Internal: data SaslFailure
+ Network.Xmpp.Internal: data Session
+ Network.Xmpp.Internal: data SessionConfiguration
+ Network.Xmpp.Internal: data ShowStatus
+ Network.Xmpp.Internal: data StanzaError
+ Network.Xmpp.Internal: data StanzaErrorCondition
+ Network.Xmpp.Internal: data StanzaErrorType
+ Network.Xmpp.Internal: data StreamErrorCondition
+ Network.Xmpp.Internal: data StreamErrorInfo
+ Network.Xmpp.Internal: data Subscription
+ Network.Xmpp.Internal: data Version
+ Network.Xmpp.Internal: data XmppFailure
+ Network.Xmpp.Internal: data XmppTlsError
+ Network.Xmpp.Internal: debugConduit :: (Show o, MonadIO m) => ConduitM o o m b
+ Network.Xmpp.Internal: debugOut :: MonadIO m => ByteString -> m ()
+ Network.Xmpp.Internal: digestMd5 :: Username -> Maybe AuthZID -> Password -> SaslHandler
+ Network.Xmpp.Internal: domainpart :: Jid -> Text
+ Network.Xmpp.Internal: domainpart_ :: Jid -> !NonemptyText
+ Network.Xmpp.Internal: dupSession :: Session -> IO Session
+ Network.Xmpp.Internal: elements :: MonadError XmppFailure m => Conduit Event m Element
+ Network.Xmpp.Internal: enablePresenceTracking :: SessionConfiguration -> Bool
+ Network.Xmpp.Internal: enableRoster :: SessionConfiguration -> Bool
+ Network.Xmpp.Internal: endSession :: Session -> IO ()
+ Network.Xmpp.Internal: errorCondition :: StreamErrorInfo -> !StreamErrorCondition
+ Network.Xmpp.Internal: errorText :: StreamErrorInfo -> !(Maybe (Maybe LangTag, NonemptyText))
+ Network.Xmpp.Internal: errorXml :: StreamErrorInfo -> !(Maybe Element)
+ Network.Xmpp.Internal: eventHandlers :: Session -> TMVar EventHandlers
+ Network.Xmpp.Internal: filterMessages :: (MessageError -> Bool) -> (Message -> Bool) -> Session -> IO (Either MessageError Message)
+ Network.Xmpp.Internal: filterMessagesA :: (Annotated MessageError -> Bool) -> (Annotated Message -> Bool) -> Session -> IO (Either (Annotated MessageError) (Annotated Message))
+ Network.Xmpp.Internal: fixDnsResult :: Either e a -> Maybe a
+ Network.Xmpp.Internal: flattenAttrs :: [(Name, [Content])] -> [(Name, Text)]
+ Network.Xmpp.Internal: fromItem :: Item -> QueryItem
+ Network.Xmpp.Internal: fromNonempty :: NonemptyText -> Text
+ Network.Xmpp.Internal: getAnnotation :: Typeable b => Annotated a -> Maybe b
+ Network.Xmpp.Internal: getFeatures :: Session -> IO StreamFeatures
+ Network.Xmpp.Internal: getIM :: Message -> Maybe InstantMessage
+ Network.Xmpp.Internal: getIMPresence :: Presence -> Maybe IMPresence
+ Network.Xmpp.Internal: getJid :: Session -> IO (Maybe Jid)
+ Network.Xmpp.Internal: getMessage :: Session -> IO Message
+ Network.Xmpp.Internal: getMessageA :: Session -> IO (Annotated Message)
+ Network.Xmpp.Internal: getRoster :: Session -> IO Roster
+ Network.Xmpp.Internal: getRosterSTM :: Session -> STM Roster
+ Network.Xmpp.Internal: getStanza :: Session -> IO (Stanza, [Annotation])
+ Network.Xmpp.Internal: getStanzaChan :: Session -> TChan (Stanza, [Annotation])
+ Network.Xmpp.Internal: handleRoster :: Maybe Jid -> TVar Roster -> StanzaHandler
+ Network.Xmpp.Internal: handleToStreamHandle :: Handle -> StreamHandle
+ Network.Xmpp.Internal: hashToken :: Hash ctx hash => hash
+ Network.Xmpp.Internal: idGenerator :: Session -> IO Text
+ Network.Xmpp.Internal: imBody :: InstantMessage -> [MessageBody]
+ Network.Xmpp.Internal: imPresence :: IMPresence
+ Network.Xmpp.Internal: imSubject :: InstantMessage -> [MessageSubject]
+ Network.Xmpp.Internal: imThread :: InstantMessage -> Maybe MessageThread
+ Network.Xmpp.Internal: imToElements :: InstantMessage -> [Element]
+ Network.Xmpp.Internal: initRoster :: Session -> IO ()
+ Network.Xmpp.Internal: instantMessage :: InstantMessage
+ Network.Xmpp.Internal: iqErrorAttributes :: IQError -> ![ExtendedAttribute]
+ Network.Xmpp.Internal: iqErrorFrom :: IQError -> !(Maybe Jid)
+ Network.Xmpp.Internal: iqErrorID :: IQError -> !Text
+ Network.Xmpp.Internal: iqErrorLangTag :: IQError -> !(Maybe LangTag)
+ Network.Xmpp.Internal: iqErrorPayload :: IQError -> !(Maybe Element)
+ Network.Xmpp.Internal: iqErrorStanzaError :: IQError -> !StanzaError
+ Network.Xmpp.Internal: iqErrorTo :: IQError -> !(Maybe Jid)
+ Network.Xmpp.Internal: iqHandlers :: Session -> TVar IQHandlers
+ Network.Xmpp.Internal: iqRequestAnnotations :: IQRequestTicket -> [Annotation]
+ Network.Xmpp.Internal: iqRequestAttributes :: IQRequest -> ![ExtendedAttribute]
+ Network.Xmpp.Internal: iqRequestBody :: IQRequestTicket -> IQRequest
+ Network.Xmpp.Internal: iqRequestFrom :: IQRequest -> !(Maybe Jid)
+ Network.Xmpp.Internal: iqRequestID :: IQRequest -> !Text
+ Network.Xmpp.Internal: iqRequestLangTag :: IQRequest -> !(Maybe LangTag)
+ Network.Xmpp.Internal: iqRequestPayload :: IQRequest -> !Element
+ Network.Xmpp.Internal: iqRequestTo :: IQRequest -> !(Maybe Jid)
+ Network.Xmpp.Internal: iqRequestType :: IQRequest -> !IQRequestType
+ Network.Xmpp.Internal: iqResultAttributes :: IQResult -> ![ExtendedAttribute]
+ Network.Xmpp.Internal: iqResultFrom :: IQResult -> !(Maybe Jid)
+ Network.Xmpp.Internal: iqResultID :: IQResult -> !Text
+ Network.Xmpp.Internal: iqResultLangTag :: IQResult -> !(Maybe LangTag)
+ Network.Xmpp.Internal: iqResultPayload :: IQResult -> !(Maybe Element)
+ Network.Xmpp.Internal: iqResultTo :: IQResult -> !(Maybe Jid)
+ Network.Xmpp.Internal: isBare :: Jid -> Bool
+ Network.Xmpp.Internal: isFull :: Jid -> Bool
+ Network.Xmpp.Internal: items :: Roster -> Map Jid Item
+ Network.Xmpp.Internal: jid :: QuasiQuoter
+ Network.Xmpp.Internal: jidFromText :: Text -> Maybe Jid
+ Network.Xmpp.Internal: jidFromTexts :: Maybe Text -> Text -> Maybe Text -> Maybe Jid
+ Network.Xmpp.Internal: jidQ :: QuasiQuoter
+ Network.Xmpp.Internal: jidToText :: Jid -> Text
+ Network.Xmpp.Internal: jidToTexts :: Jid -> (Maybe Text, Text, Maybe Text)
+ Network.Xmpp.Internal: killStream :: Stream -> IO (Either XmppFailure ())
+ Network.Xmpp.Internal: langTagFromText :: Text -> Maybe LangTag
+ Network.Xmpp.Internal: langTagQ :: QuasiQuoter
+ Network.Xmpp.Internal: langTagToText :: LangTag -> Text
+ Network.Xmpp.Internal: listenIQ :: IQRequestType -> Text -> Session -> IO (Either (STM IQRequestTicket) (STM IQRequestTicket))
+ Network.Xmpp.Internal: lmb :: [t] -> Maybe [t]
+ Network.Xmpp.Internal: localpart :: Jid -> Maybe Text
+ Network.Xmpp.Internal: localpart_ :: Jid -> !(Maybe NonemptyText)
+ Network.Xmpp.Internal: majorVersion :: Version -> !Integer
+ Network.Xmpp.Internal: makeNonce :: IO ByteString
+ Network.Xmpp.Internal: mbl :: Maybe [a] -> [a]
+ Network.Xmpp.Internal: merge :: [ByteString] -> ByteString
+ Network.Xmpp.Internal: message :: Message
+ Network.Xmpp.Internal: messageAttributes :: Message -> ![ExtendedAttribute]
+ Network.Xmpp.Internal: messageError :: MessageError
+ Network.Xmpp.Internal: messageErrorAttributes :: MessageError -> ![ExtendedAttribute]
+ Network.Xmpp.Internal: messageErrorFrom :: MessageError -> !(Maybe Jid)
+ Network.Xmpp.Internal: messageErrorID :: MessageError -> !(Maybe Text)
+ Network.Xmpp.Internal: messageErrorLangTag :: MessageError -> !(Maybe LangTag)
+ Network.Xmpp.Internal: messageErrorPayload :: MessageError -> ![Element]
+ Network.Xmpp.Internal: messageErrorS :: Stanza
+ Network.Xmpp.Internal: messageErrorStanzaError :: MessageError -> !StanzaError
+ Network.Xmpp.Internal: messageErrorTo :: MessageError -> !(Maybe Jid)
+ Network.Xmpp.Internal: messageFrom :: Message -> !(Maybe Jid)
+ Network.Xmpp.Internal: messageID :: Message -> !(Maybe Text)
+ Network.Xmpp.Internal: messageLangTag :: Message -> !(Maybe LangTag)
+ Network.Xmpp.Internal: messagePayload :: Message -> ![Element]
+ Network.Xmpp.Internal: messageS :: Stanza
+ Network.Xmpp.Internal: messageTo :: Message -> !(Maybe Jid)
+ Network.Xmpp.Internal: messageType :: Message -> !MessageType
+ Network.Xmpp.Internal: minorVersion :: Version -> !Integer
+ Network.Xmpp.Internal: mkBackend :: StreamHandle -> Backend
+ Network.Xmpp.Internal: mkReadBuffer :: IO ByteString -> IO (Int -> IO ByteString)
+ Network.Xmpp.Internal: mkStanzaError :: StanzaErrorCondition -> StanzaError
+ Network.Xmpp.Internal: mkStream :: StreamState -> IO Stream
+ Network.Xmpp.Internal: modifyHandlers :: (EventHandlers -> EventHandlers) -> Session -> IO ()
+ Network.Xmpp.Internal: newSession :: Stream -> SessionConfiguration -> HostName -> Maybe (ConnectionState -> [SaslHandler], Maybe Text) -> IO (Either XmppFailure Session)
+ Network.Xmpp.Internal: newStanzaID :: Session -> IO Text
+ Network.Xmpp.Internal: newtype NonemptyText
+ Network.Xmpp.Internal: nodeprepProfile :: StringPrepProfile
+ Network.Xmpp.Internal: nonAsciiSpaces :: Set Char
+ Network.Xmpp.Internal: nonEmpty :: Text -> Maybe NonemptyText
+ Network.Xmpp.Internal: normalizePassword :: Text -> Maybe Text
+ Network.Xmpp.Internal: normalizeUsername :: Text -> Maybe Text
+ Network.Xmpp.Internal: nsHack :: Element -> Element
+ Network.Xmpp.Internal: onConnectionClosed :: SessionConfiguration -> Session -> XmppFailure -> IO ()
+ Network.Xmpp.Internal: onPresenceChange :: SessionConfiguration -> Maybe (Jid -> PeerStatus -> PeerStatus -> IO ())
+ Network.Xmpp.Internal: openElementFromEvents :: StreamSink Element
+ Network.Xmpp.Internal: openElementToEvents :: Element -> [Event]
+ Network.Xmpp.Internal: pairs :: ByteString -> Either String Pairs
+ Network.Xmpp.Internal: parseJid :: String -> Jid
+ Network.Xmpp.Internal: parseLangTag :: String -> LangTag
+ Network.Xmpp.Internal: pickleElem :: PU [Node] a -> a -> Element
+ Network.Xmpp.Internal: pickleRequest :: IQRequestClass a => PU Element a
+ Network.Xmpp.Internal: pickleResponse :: IQRequestClass a => PU [Element] (IQResponseType a)
+ Network.Xmpp.Internal: plain :: Username -> Maybe AuthZID -> Password -> SaslHandler
+ Network.Xmpp.Internal: plugins :: SessionConfiguration -> [Plugin]
+ Network.Xmpp.Internal: prepCredentials :: Text -> Maybe Text -> Text -> ErrorT AuthFailure (StateT StreamState IO) (Text, Maybe Text, Text)
+ Network.Xmpp.Internal: presTo :: Presence -> Jid -> Presence
+ Network.Xmpp.Internal: presence :: Presence
+ Network.Xmpp.Internal: presenceAttributes :: Presence -> ![ExtendedAttribute]
+ Network.Xmpp.Internal: presenceErrorAttributes :: PresenceError -> ![ExtendedAttribute]
+ Network.Xmpp.Internal: presenceErrorFrom :: PresenceError -> !(Maybe Jid)
+ Network.Xmpp.Internal: presenceErrorID :: PresenceError -> !(Maybe Text)
+ Network.Xmpp.Internal: presenceErrorLangTag :: PresenceError -> !(Maybe LangTag)
+ Network.Xmpp.Internal: presenceErrorPayload :: PresenceError -> ![Element]
+ Network.Xmpp.Internal: presenceErrorStanzaError :: PresenceError -> !StanzaError
+ Network.Xmpp.Internal: presenceErrorTo :: PresenceError -> !(Maybe Jid)
+ Network.Xmpp.Internal: presenceFrom :: Presence -> !(Maybe Jid)
+ Network.Xmpp.Internal: presenceID :: Presence -> !(Maybe Text)
+ Network.Xmpp.Internal: presenceLangTag :: Presence -> !(Maybe LangTag)
+ Network.Xmpp.Internal: presenceOffline :: Presence
+ Network.Xmpp.Internal: presenceOnline :: Presence
+ Network.Xmpp.Internal: presencePayload :: Presence -> ![Element]
+ Network.Xmpp.Internal: presenceRef :: Session -> TVar Peers
+ Network.Xmpp.Internal: presenceS :: Stanza
+ Network.Xmpp.Internal: presenceSubscribe :: Jid -> Presence
+ Network.Xmpp.Internal: presenceSubscribed :: Jid -> Presence
+ Network.Xmpp.Internal: presenceTo :: Presence -> !(Maybe Jid)
+ Network.Xmpp.Internal: presenceType :: Presence -> !PresenceType
+ Network.Xmpp.Internal: presenceUnsubscribe :: Jid -> Presence
+ Network.Xmpp.Internal: presenceUnsubscribed :: Jid -> Presence
+ Network.Xmpp.Internal: primaryTag :: LangTag -> !Text
+ Network.Xmpp.Internal: priority :: IMPresence -> Maybe Int
+ Network.Xmpp.Internal: pullChallenge :: ErrorT AuthFailure (StateT StreamState IO) (Maybe ByteString)
+ Network.Xmpp.Internal: pullElement :: StateT StreamState IO (Either XmppFailure Element)
+ Network.Xmpp.Internal: pullFinalMessage :: ErrorT AuthFailure (StateT StreamState IO) (Maybe ByteString)
+ Network.Xmpp.Internal: pullMessage :: Session -> IO (Either MessageError Message)
+ Network.Xmpp.Internal: pullMessageA :: Session -> IO (Either (Annotated MessageError) (Annotated Message))
+ Network.Xmpp.Internal: pullPresence :: Session -> IO (Either PresenceError Presence)
+ Network.Xmpp.Internal: pullPresenceA :: Session -> IO (Either (Annotated PresenceError) (Annotated Presence))
+ Network.Xmpp.Internal: pullSaslElement :: ErrorT AuthFailure (StateT StreamState IO) SaslElement
+ Network.Xmpp.Internal: pullSuccess :: ErrorT AuthFailure (StateT StreamState IO) (Maybe Text)
+ Network.Xmpp.Internal: pullUnpickle :: PU [Node] a -> StateT StreamState IO (Either XmppFailure a)
+ Network.Xmpp.Internal: pushElement :: Element -> StateT StreamState IO (Either XmppFailure ())
+ Network.Xmpp.Internal: pushOpenElement :: Element -> StateT StreamState IO (Either XmppFailure ())
+ Network.Xmpp.Internal: pushXmlDecl :: StateT StreamState IO (Either XmppFailure ())
+ Network.Xmpp.Internal: qiApproved :: QueryItem -> Maybe Bool
+ Network.Xmpp.Internal: qiAsk :: QueryItem -> Bool
+ Network.Xmpp.Internal: qiGroups :: QueryItem -> [Text]
+ Network.Xmpp.Internal: qiJid :: QueryItem -> Jid
+ Network.Xmpp.Internal: qiName :: QueryItem -> Maybe Text
+ Network.Xmpp.Internal: qiSubscription :: QueryItem -> Maybe Subscription
+ Network.Xmpp.Internal: queryItems :: Query -> [QueryItem]
+ Network.Xmpp.Internal: queryVer :: Query -> Maybe Text
+ Network.Xmpp.Internal: quote :: ByteString -> ByteString
+ Network.Xmpp.Internal: readMaybe_ :: Read a => String -> Maybe a
+ Network.Xmpp.Internal: readWorker :: (Stanza -> IO ()) -> (XmppFailure -> IO ()) -> TMVar Stream -> IO a
+ Network.Xmpp.Internal: readerThread :: Session -> ThreadId
+ Network.Xmpp.Internal: reconnect :: Integer -> Session -> IO (Bool, [XmppFailure])
+ Network.Xmpp.Internal: reconnect' :: Session -> IO Integer
+ Network.Xmpp.Internal: reconnectNow :: Session -> IO (Maybe XmppFailure)
+ Network.Xmpp.Internal: reconnectWait :: Session -> TVar Int
+ Network.Xmpp.Internal: renderElement :: Element -> ByteString
+ Network.Xmpp.Internal: renderOpenElement :: Element -> ByteString
+ Network.Xmpp.Internal: requestNamespace :: IQRequestClass a => a -> Text
+ Network.Xmpp.Internal: requestType :: IQRequestClass a => a -> IQRequestType
+ Network.Xmpp.Internal: resolvAndConnectTcp :: ResolvSeed -> Domain -> Int -> IO (Maybe Handle)
+ Network.Xmpp.Internal: resolvSrvsAndConnectTcp :: ResolvSeed -> [(Domain, Int)] -> IO (Maybe Handle)
+ Network.Xmpp.Internal: resourcepart :: Jid -> Maybe Text
+ Network.Xmpp.Internal: resourcepart_ :: Jid -> !(Maybe NonemptyText)
+ Network.Xmpp.Internal: resourceprepProfile :: StringPrepProfile
+ Network.Xmpp.Internal: respond :: Maybe ByteString -> ErrorT AuthFailure (StateT StreamState IO) ()
+ Network.Xmpp.Internal: restartStream :: StateT StreamState IO (Either XmppFailure ())
+ Network.Xmpp.Internal: rethrowErrorCall :: IO a -> IO a
+ Network.Xmpp.Internal: retrieveRoster :: Maybe Roster -> Session -> IO (Maybe Roster)
+ Network.Xmpp.Internal: riApproved :: Item -> Bool
+ Network.Xmpp.Internal: riAsk :: Item -> Bool
+ Network.Xmpp.Internal: riGroups :: Item -> [Text]
+ Network.Xmpp.Internal: riJid :: Item -> Jid
+ Network.Xmpp.Internal: riName :: Item -> Maybe Text
+ Network.Xmpp.Internal: riSubscription :: Item -> Subscription
+ Network.Xmpp.Internal: rosterAdd :: Jid -> Maybe Text -> [Text] -> Session -> IO (Either IQSendError (Annotated IQResponse))
+ Network.Xmpp.Internal: rosterRef :: Session -> TVar Roster
+ Network.Xmpp.Internal: rosterRemove :: Jid -> Session -> IO Bool
+ Network.Xmpp.Internal: rosterSet :: Jid -> Maybe Text -> [Text] -> Session -> IO (Either IQSendError (Annotated IQResponse))
+ Network.Xmpp.Internal: runConnectionClosedHandler :: Session -> XmppFailure -> IO ()
+ Network.Xmpp.Internal: runEventsSink :: Sink Event (ErrorT XmppFailure IO) b -> StateT StreamState IO (Either XmppFailure b)
+ Network.Xmpp.Internal: runHandler :: (EventHandlers -> IO a) -> Session -> IO a
+ Network.Xmpp.Internal: runIQHandler :: IQRequestClass a => IQRequestHandler a -> Session -> IO ()
+ Network.Xmpp.Internal: sRealm :: Session -> HostName
+ Network.Xmpp.Internal: sSaslCredentials :: Session -> Maybe (ConnectionState -> [SaslHandler], Maybe Text)
+ Network.Xmpp.Internal: sanitizeIM :: InstantMessage -> InstantMessage
+ Network.Xmpp.Internal: saslFailureCondition :: SaslFailure -> SaslError
+ Network.Xmpp.Internal: saslFailureText :: SaslFailure -> Maybe (Maybe LangTag, Text)
+ Network.Xmpp.Internal: saslFromJust :: Maybe a -> ErrorT AuthFailure (StateT StreamState IO) a
+ Network.Xmpp.Internal: saslInit :: Text -> Maybe ByteString -> ErrorT AuthFailure (StateT StreamState IO) ()
+ Network.Xmpp.Internal: saslInitE :: Text -> Maybe Text -> Element
+ Network.Xmpp.Internal: saslPrepQuery :: StringPrepProfile
+ Network.Xmpp.Internal: saslPrepStore :: StringPrepProfile
+ Network.Xmpp.Internal: saslResponseE :: Maybe Text -> Element
+ Network.Xmpp.Internal: scram :: Hash ctx hash => hash -> Text -> Maybe Text -> Text -> ErrorT AuthFailure (StateT StreamState IO) ()
+ Network.Xmpp.Internal: scramSha1 :: Username -> Maybe AuthZID -> Password -> SaslHandler
+ Network.Xmpp.Internal: semWrite :: WriteSemaphore -> ByteString -> IO (Either XmppFailure ())
+ Network.Xmpp.Internal: sendIQ :: Maybe Integer -> Maybe Jid -> IQRequestType -> Maybe LangTag -> Element -> [ExtendedAttribute] -> Session -> IO (Either XmppFailure (STM (Maybe (Annotated IQResponse))))
+ Network.Xmpp.Internal: sendIQ' :: Maybe Integer -> Maybe Jid -> IQRequestType -> Maybe LangTag -> Element -> [ExtendedAttribute] -> Session -> IO (Either IQSendError IQResponse)
+ Network.Xmpp.Internal: sendIQA' :: Maybe Integer -> Maybe Jid -> IQRequestType -> Maybe LangTag -> Element -> [ExtendedAttribute] -> Session -> IO (Either IQSendError (Annotated IQResponse))
+ Network.Xmpp.Internal: sendIQRequest :: (IQRequestClass a, MonadError IQRequestError m, MonadIO m) => Maybe Integer -> Maybe Jid -> a -> Session -> m (Either IQError (IQResponseType a))
+ Network.Xmpp.Internal: sendMessage :: Message -> Session -> IO (Either XmppFailure ())
+ Network.Xmpp.Internal: sendPresence :: Presence -> Session -> IO (Either XmppFailure ())
+ Network.Xmpp.Internal: sendRawStanza :: Stanza -> Session -> IO (Either XmppFailure ())
+ Network.Xmpp.Internal: sendStanza :: Stanza -> Session -> IO (Either XmppFailure ())
+ Network.Xmpp.Internal: sendStanza' :: Session -> Stanza -> IO (Either XmppFailure ())
+ Network.Xmpp.Internal: session :: HostName -> AuthData -> SessionConfiguration -> IO (Either XmppFailure Session)
+ Network.Xmpp.Internal: sessionStanzaIDs :: SessionConfiguration -> IO (IO Text)
+ Network.Xmpp.Internal: sessionStreamConfiguration :: SessionConfiguration -> StreamConfiguration
+ Network.Xmpp.Internal: setConnectionClosedHandler :: (XmppFailure -> Session -> IO ()) -> Session -> IO ()
+ Network.Xmpp.Internal: showPort :: PortID -> String
+ Network.Xmpp.Internal: showStatus :: IMPresence -> Maybe ShowStatus
+ Network.Xmpp.Internal: simpleAuth :: Username -> Password -> AuthData
+ Network.Xmpp.Internal: simpleIM :: Jid -> Text -> Message
+ Network.Xmpp.Internal: sourceStreamHandle :: (MonadIO m, MonadError XmppFailure m) => StreamHandle -> ConduitM i ByteString m ()
+ Network.Xmpp.Internal: srvLookup :: Text -> ResolvSeed -> ErrorT XmppFailure IO (Maybe [(Domain, Int)])
+ Network.Xmpp.Internal: stanzaCh :: Session -> TChan (Stanza, [Annotation])
+ Network.Xmpp.Internal: stanzaErrorApplicationSpecificCondition :: StanzaError -> Maybe Element
+ Network.Xmpp.Internal: stanzaErrorCondition :: StanzaError -> StanzaErrorCondition
+ Network.Xmpp.Internal: stanzaErrorText :: StanzaError -> Maybe (Maybe LangTag, NonemptyText)
+ Network.Xmpp.Internal: stanzaErrorType :: StanzaError -> StanzaErrorType
+ Network.Xmpp.Internal: startStream :: StateT StreamState IO (Either XmppFailure ())
+ Network.Xmpp.Internal: startThreadsWith :: TMVar (ByteString -> IO (Either XmppFailure ())) -> (Stanza -> IO ()) -> TMVar EventHandlers -> Stream -> IO (Either XmppFailure (IO (), TMVar Stream, ThreadId))
+ Network.Xmpp.Internal: starttlsE :: Element
+ Network.Xmpp.Internal: status :: IMPresence -> Maybe Text
+ Network.Xmpp.Internal: stopThreads :: Session -> IO ()
+ Network.Xmpp.Internal: streamRef :: Session -> TMVar Stream
+ Network.Xmpp.Internal: streamS :: Maybe Jid -> StreamSink (Either Element (Text, Maybe Jid, Maybe Jid, Maybe Text, Maybe LangTag, StreamFeatures))
+ Network.Xmpp.Internal: streamState :: Session -> STM ConnectionState
+ Network.Xmpp.Internal: streamUnpickleElem :: PU [Node] a -> Element -> StreamSink a
+ Network.Xmpp.Internal: subjectContent :: MessageSubject -> Text
+ Network.Xmpp.Internal: subjectLang :: MessageSubject -> Maybe LangTag
+ Network.Xmpp.Internal: subtags :: LangTag -> ![Text]
+ Network.Xmpp.Internal: text :: NonemptyText -> Text
+ Network.Xmpp.Internal: threadID :: MessageThread -> Text
+ Network.Xmpp.Internal: threadParent :: MessageThread -> Maybe Text
+ Network.Xmpp.Internal: throwOutJunk :: Monad m => ConduitM Event a m ()
+ Network.Xmpp.Internal: timeout :: Maybe Integer
+ Network.Xmpp.Internal: tlsinit :: (MonadIO m, MonadIO m1) => ClientParams -> Backend -> m (Source m1 ByteString, Sink ByteString m1 (), ByteString -> IO (), Int -> m1 ByteString, Context)
+ Network.Xmpp.Internal: toBare :: Jid -> Jid
+ Network.Xmpp.Internal: toItem :: QueryItem -> Item
+ Network.Xmpp.Internal: toPairs :: ByteString -> ErrorT AuthFailure (StateT StreamState IO) Pairs
+ Network.Xmpp.Internal: toSpace :: Char -> Text
+ Network.Xmpp.Internal: tryIOError :: IO a -> IO (Either IOError a)
+ Network.Xmpp.Internal: type Annotated a = (a, [Annotation])
+ Network.Xmpp.Internal: type AuthData = Maybe (ConnectionState -> [SaslHandler], Maybe Resource)
+ Network.Xmpp.Internal: type AuthZID = Text
+ Network.Xmpp.Internal: type ExtendedAttribute = (Name, Text)
+ Network.Xmpp.Internal: type IQHandlers = (Map (IQRequestType, Text) (TChan IQRequestTicket), Map Text (Either (Maybe Jid) Jid, TMVar (Maybe (Annotated IQResponse))))
+ Network.Xmpp.Internal: type IQRequestHandler a = a -> IO (Either StanzaError (IQResponseType a))
+ Network.Xmpp.Internal: type Pairs = [(ByteString, ByteString)]
+ Network.Xmpp.Internal: type Password = Text
+ Network.Xmpp.Internal: type Resource = Text
+ Network.Xmpp.Internal: type StanzaHandler = (Stanza -> IO (Either XmppFailure ())) -> Stanza -> [Annotation] -> IO [(Stanza, [Annotation])]
+ Network.Xmpp.Internal: type StreamSink a = ConduitM Event Void (ErrorT XmppFailure IO) a
+ Network.Xmpp.Internal: type Username = Text
+ Network.Xmpp.Internal: type WriteSemaphore = TMVar (ByteString -> IO (Either XmppFailure ()))
+ Network.Xmpp.Internal: unlistenIQ :: IQRequestType -> Text -> Session -> IO ()
+ Network.Xmpp.Internal: unpickleElem :: PU [Node] a -> Element -> Either UnpickleError a
+ Network.Xmpp.Internal: ver :: Roster -> Maybe Text
+ Network.Xmpp.Internal: versionFromText :: Text -> Maybe Version
+ Network.Xmpp.Internal: waitForMessage :: (Message -> Bool) -> Session -> IO Message
+ Network.Xmpp.Internal: waitForMessageA :: (Annotated Message -> Bool) -> Session -> IO (Annotated Message)
+ Network.Xmpp.Internal: waitForMessageError :: (MessageError -> Bool) -> Session -> IO MessageError
+ Network.Xmpp.Internal: waitForMessageErrorA :: (Annotated MessageError -> Bool) -> Session -> IO (Annotated MessageError)
+ Network.Xmpp.Internal: waitForPresence :: (Presence -> Bool) -> Session -> IO Presence
+ Network.Xmpp.Internal: waitForPresenceA :: (Annotated Presence -> Bool) -> Session -> IO (Annotated Presence)
+ Network.Xmpp.Internal: waitForStream :: Session -> IO ()
+ Network.Xmpp.Internal: withConnection :: (Stream -> IO (b, Stream)) -> Session -> IO (Either XmppFailure b)
+ Network.Xmpp.Internal: withIM :: Message -> InstantMessage -> Message
+ Network.Xmpp.Internal: withIMPresence :: IMPresence -> Presence -> Presence
+ Network.Xmpp.Internal: withStream' :: StateT StreamState IO a -> Stream -> IO a
+ Network.Xmpp.Internal: withTMVar :: TMVar a -> (a -> IO (c, a)) -> IO c
+ Network.Xmpp.Internal: wrapExceptions :: IO a -> IO (Either XmppFailure a)
+ Network.Xmpp.Internal: wrapIOException :: MonadIO m => IO a -> m (Either XmppFailure a)
+ Network.Xmpp.Internal: writeSemaphore :: Session -> WriteSemaphore
+ Network.Xmpp.Internal: xmlLang :: Name
+ Network.Xmpp.Internal: xmppDefaultParams :: ClientParams
+ Network.Xmpp.Internal: xmppDefaultParamsStrong :: ClientParams
+ Network.Xmpp.Internal: xmppNoStream :: StreamState
+ Network.Xmpp.Internal: xmppSasl :: [SaslHandler] -> Stream -> IO (Either XmppFailure (Maybe AuthFailure))
+ Network.Xmpp.Internal: xorBS :: ByteString -> ByteString -> ByteString
+ Network.Xmpp.Internal: xpChallenge :: PU [Node] (Maybe Text)
+ Network.Xmpp.Internal: xpExtendedAttrs :: PU [Attribute] [ExtendedAttribute]
+ Network.Xmpp.Internal: xpFailure :: PU [Node] SaslFailure
+ Network.Xmpp.Internal: xpIM :: PU [Element] InstantMessage
+ Network.Xmpp.Internal: xpIMPresence :: PU [Element] IMPresence
+ Network.Xmpp.Internal: xpIQError :: PU [Node] IQError
+ Network.Xmpp.Internal: xpIQRequest :: PU [Node] IQRequest
+ Network.Xmpp.Internal: xpIQRequestType :: PU Text IQRequestType
+ Network.Xmpp.Internal: xpIQResult :: PU [Node] IQResult
+ Network.Xmpp.Internal: xpItems :: PU [Node] [QueryItem]
+ Network.Xmpp.Internal: xpJid :: PU Text Jid
+ Network.Xmpp.Internal: xpLang :: PU Text LangTag
+ Network.Xmpp.Internal: xpLangTag :: PU [Attribute] (Maybe LangTag)
+ Network.Xmpp.Internal: xpMessage :: PU [Node] (Message)
+ Network.Xmpp.Internal: xpMessageBody :: PU [Element] [MessageBody]
+ Network.Xmpp.Internal: xpMessageError :: PU [Node] (MessageError)
+ Network.Xmpp.Internal: xpMessageSubject :: PU [Element] [MessageSubject]
+ Network.Xmpp.Internal: xpMessageThread :: PU [Element] (Maybe MessageThread)
+ Network.Xmpp.Internal: xpMessageType :: PU Text MessageType
+ Network.Xmpp.Internal: xpNodeElem :: PU [Node] a -> PU Element a
+ Network.Xmpp.Internal: xpNonemptyText :: PU Text NonemptyText
+ Network.Xmpp.Internal: xpPresence :: PU [Node] Presence
+ Network.Xmpp.Internal: xpPresenceError :: PU [Node] PresenceError
+ Network.Xmpp.Internal: xpPresenceType :: PU Text PresenceType
+ Network.Xmpp.Internal: xpQuery :: PU [Node] Query
+ Network.Xmpp.Internal: xpSaslElement :: PU [Node] SaslElement
+ Network.Xmpp.Internal: xpSaslError :: PU Text SaslError
+ Network.Xmpp.Internal: xpShow :: PU Text ShowStatus
+ Network.Xmpp.Internal: xpStanza :: PU [Node] Stanza
+ Network.Xmpp.Internal: xpStanzaError :: PU [Node] StanzaError
+ Network.Xmpp.Internal: xpStanzaErrorCondition :: PU [Node] StanzaErrorCondition
+ Network.Xmpp.Internal: xpStanzaErrorType :: PU Text StanzaErrorType
+ Network.Xmpp.Internal: xpStream :: PU [Node] (Text, Maybe Jid, Maybe Jid, Maybe Text, Maybe LangTag)
+ Network.Xmpp.Internal: xpStreamError :: PU [Node] StreamErrorInfo
+ Network.Xmpp.Internal: xpStreamErrorCondition :: PU Text StreamErrorCondition
+ Network.Xmpp.Internal: xpStreamFeatures :: PU [Node] StreamFeatures
+ Network.Xmpp.Internal: xpStreamStanza :: PU [Node] (Either StreamErrorInfo Stanza)
+ Network.Xmpp.Internal: xpSubscription :: PU Text Subscription
+ Network.Xmpp.Internal: xpSuccess :: PU [Node] (Maybe Text)
+ Network.Xmpp.Internal: zeroHandle :: StreamHandle
+ Network.Xmpp.Internal: zeroSource :: Source (ErrorT XmppFailure IO) a
+ Network.Xmpp.Lens: _IQError :: Prism Stanza IQError
+ Network.Xmpp.Lens: _IQRequest :: Prism Stanza IQRequest
+ Network.Xmpp.Lens: _IQResult :: Prism Stanza IQResult
+ Network.Xmpp.Lens: _JidText :: Prism Text Jid
+ Network.Xmpp.Lens: _Message :: Prism Stanza Message
+ Network.Xmpp.Lens: _MessageError :: Prism Stanza MessageError
+ Network.Xmpp.Lens: _Presence :: Prism Stanza Presence
+ Network.Xmpp.Lens: _PresenceError :: Prism Stanza PresenceError
+ Network.Xmpp.Lens: _isBare :: Prism Jid Jid
+ Network.Xmpp.Lens: _isFull :: Prism Jid Jid
+ Network.Xmpp.Lens: clientServerIdentificationL :: Lens ClientParams (String, ByteString)
+ Network.Xmpp.Lens: clientSupportedL :: Lens ClientParams Supported
+ Network.Xmpp.Lens: clientUseServerNameIndicationL :: Lens ClientParams Bool
+ Network.Xmpp.Lens: mkIso :: (a -> b) -> (b -> a) -> Iso a b
+ Network.Xmpp.Lens: mkLens :: (a -> b) -> (b -> a -> a) -> Lens a b
+ Network.Xmpp.Lens: onPresenceChangeL :: Lens SessionConfiguration (Maybe (Jid -> PeerStatus -> PeerStatus -> IO ()))
+ Network.Xmpp.Lens: prism' :: (b -> s) -> (s -> Maybe b) -> Prism s b
+ Network.Xmpp.Lens: supportedCiphersL :: Lens Supported [Cipher]
+ Network.Xmpp.Lens: supportedVersionsL :: Lens Supported [Version]
+ Network.Xmpp.Lens: tlsServerIdentificationL :: Lens SessionConfiguration (String, ByteString)
+ Network.Xmpp.Lens: tlsSupportedCiphersL :: Lens SessionConfiguration [Cipher]
+ Network.Xmpp.Lens: tlsSupportedVersionsL :: Lens SessionConfiguration [Version]
+ Network.Xmpp.Lens: tlsUseNameIndicationL :: Lens SessionConfiguration Bool
+ Network.Xmpp.Lens: type Iso a b = forall p f. (Profunctor p, Functor f) => p b (f b) -> p a (f a)
- Network.Xmpp: IQError :: !Text -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !StanzaError -> !(Maybe Element) -> IQError
+ Network.Xmpp: IQError :: !Text -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !StanzaError -> !(Maybe Element) -> ![ExtendedAttribute] -> IQError
- Network.Xmpp: IQRequest :: !Text -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !IQRequestType -> !Element -> IQRequest
+ Network.Xmpp: IQRequest :: !Text -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !IQRequestType -> !Element -> ![ExtendedAttribute] -> IQRequest
- Network.Xmpp: IQResult :: !Text -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !(Maybe Element) -> IQResult
+ Network.Xmpp: IQResult :: !Text -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !(Maybe Element) -> ![ExtendedAttribute] -> IQResult
- Network.Xmpp: Message :: !(Maybe Text) -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !MessageType -> ![Element] -> Message
+ Network.Xmpp: Message :: !(Maybe Text) -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !MessageType -> ![Element] -> ![ExtendedAttribute] -> Message
- Network.Xmpp: MessageError :: !(Maybe Text) -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !StanzaError -> ![Element] -> MessageError
+ Network.Xmpp: MessageError :: !(Maybe Text) -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !StanzaError -> ![Element] -> ![ExtendedAttribute] -> MessageError
- Network.Xmpp: Presence :: !(Maybe Text) -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !PresenceType -> ![Element] -> Presence
+ Network.Xmpp: Presence :: !(Maybe Text) -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !PresenceType -> ![Element] -> ![ExtendedAttribute] -> Presence
- Network.Xmpp: PresenceError :: !(Maybe Text) -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !StanzaError -> ![Element] -> PresenceError
+ Network.Xmpp: PresenceError :: !(Maybe Text) -> !(Maybe Jid) -> !(Maybe Jid) -> !(Maybe LangTag) -> !StanzaError -> ![Element] -> ![ExtendedAttribute] -> PresenceError
- Network.Xmpp: SessionConfiguration :: StreamConfiguration -> (Session -> XmppFailure -> IO ()) -> IO (IO Text) -> [Plugin] -> Bool -> SessionConfiguration
+ Network.Xmpp: SessionConfiguration :: StreamConfiguration -> (Session -> XmppFailure -> IO ()) -> IO (IO Text) -> [Plugin] -> Bool -> Bool -> Maybe (Jid -> PeerStatus -> PeerStatus -> IO ()) -> SessionConfiguration
- Network.Xmpp: answerIQ :: IQRequestTicket -> Either StanzaError (Maybe Element) -> IO (Maybe (Either XmppFailure ()))
+ Network.Xmpp: answerIQ :: IQRequestTicket -> Either StanzaError (Maybe Element) -> [ExtendedAttribute] -> IO (Maybe (Either XmppFailure ()))
- Network.Xmpp: sendIQ :: Maybe Integer -> Maybe Jid -> IQRequestType -> Maybe LangTag -> Element -> Session -> IO (Either XmppFailure (STM (Maybe (Annotated IQResponse))))
+ Network.Xmpp: sendIQ :: Maybe Integer -> Maybe Jid -> IQRequestType -> Maybe LangTag -> Element -> [ExtendedAttribute] -> Session -> IO (Either XmppFailure (STM (Maybe (Annotated IQResponse))))
- Network.Xmpp: sendIQ' :: Maybe Integer -> Maybe Jid -> IQRequestType -> Maybe LangTag -> Element -> Session -> IO (Either IQSendError IQResponse)
+ Network.Xmpp: sendIQ' :: Maybe Integer -> Maybe Jid -> IQRequestType -> Maybe LangTag -> Element -> [ExtendedAttribute] -> Session -> IO (Either IQSendError IQResponse)
- Network.Xmpp.Lens: set :: Lens a b -> b -> a -> a
+ Network.Xmpp.Lens: set :: Setter a a' b b' -> b' -> a -> a'
- Network.Xmpp.Lens: view :: Lens a b -> a -> b
+ Network.Xmpp.Lens: view :: FoldLike b a a' b b' -> a -> b

Files

pontarius-xmpp.cabal view
@@ -1,5 +1,5 @@ Name:          pontarius-xmpp-Version:       0.4.0.2+Version:       0.4.1.0 Cabal-Version: >= 1.9.2 Build-Type:    Custom License:       BSD3@@ -36,11 +36,6 @@ Library   hs-source-dirs: source   Exposed: True--  -- The only different between the below two blocks is that the first one caps-  -- the range for the `bytestring' package, and that the second one includes-  -- `template-haskell' for GHC 7.6.1 and above.-   Build-Depends: attoparsec           >=0.10.0.3                , base                 >4 && <5                , base64-bytestring    >=0.1.0.0@@ -53,25 +48,29 @@                , cryptohash-cryptoapi >=0.1                , data-default         >=0.2                , dns                  >=0.3.0+               , exceptions >= 0.6                , hslogger             >=1.1.0                , iproute              >=1.2.4+               , lens-family                , lifted-base          >=0.1.0.1                , mtl                  >=2.0.0.0                , network              >=2.3.1.0+               , profunctors          >= 4                , pureMD5              >=2.1.2.1-               , resourcet            >=0.3.0                , random               >=1.0.0.0+               , resourcet            >=0.3.0                , split                >=0.1.2.3-               , stm                  >=2.1.2.1+               , stm                  >=2.4                , stringprep           >=1.0.0                , text                 >=0.11.1.5                , tls                  >=1.2-               , transformers         >=0.2.2.0+               , transformers         >=0.3                , unbounded-delays     >=0.1                , void                 >=0.5.5-               , xml-types            >=0.3.1+               , x509-system          >=1.4                , xml-conduit          >=1.1.0.7                , xml-picklers         >=0.3.3+               , xml-types            >=0.3.1    If impl(ghc ==7.0.1) {     Build-Depends: bytestring         >=0.9.1.9 && <=0.9.2.1@@ -95,8 +94,11 @@                  , Network.Xmpp.Concurrent.Types                  , Network.Xmpp.IM.Message                  , Network.Xmpp.IM.Presence+                 , Network.Xmpp.IM.PresenceTracker                  , Network.Xmpp.IM.Roster                  , Network.Xmpp.IM.Roster.Types+                 , Network.Xmpp.IM.PresenceTracker+                 , Network.Xmpp.IM.PresenceTracker.Types                  , Network.Xmpp.Marshal                  , Network.Xmpp.Sasl                  , Network.Xmpp.Sasl.Common@@ -166,6 +168,31 @@                , QuickCheck                , derive                , quickcheck-instances++Test-Suite runtests+  Type: exitcode-stdio-1.0+  hs-source-dirs: tests+  main-is: Run.hs+  other-modules: Run.Payload+  GHC-Options: -Wall -threaded+  Build-Depends: base+               , HUnit+               , configurator+               , directory+               , filepath+               , hslogger+               , hspec+               , hspec-expectations+               , mtl+               , network+               , pontarius-xmpp+               , stm+               , text+               , xml-picklers+               , xml-types+               , tasty+               , tasty-hunit+               , tls  benchmark benchmarks   type: exitcode-stdio-1.0
source/Network/Xmpp.hs view
@@ -58,6 +58,7 @@   , closeConnection   , endSession   , waitForStream+  , streamState     -- ** Authentication handlers     -- | The use of 'scramSha1' is /recommended/, but 'digestMd5' might be     -- useful for interaction with older implementations.@@ -193,11 +194,15 @@   , IQResult(..)   , IQError(..)   , IQResponse(..)+  , IQRequestClass(..)+  , IQRequestHandler   , sendIQ   , sendIQ'+  , sendIQRequest   , answerIQ   , iqResult   , listenIQ+  , runIQHandler   , unlistenIQ   -- * Errors   , StanzaErrorType(..)@@ -207,6 +212,7 @@   , StanzaErrorCondition(..)   , SaslFailure(..)   , IQSendError(..)+  , IQRequestError(..)   -- * Threads   , dupSession   -- * Lenses
source/Network/Xmpp/Concurrent.hs view
@@ -40,6 +40,8 @@ import           Network.Xmpp.Concurrent.Types import           Network.Xmpp.IM.Roster import           Network.Xmpp.IM.Roster.Types+import           Network.Xmpp.IM.PresenceTracker+import           Network.Xmpp.IM.PresenceTracker.Types import           Network.Xmpp.Sasl import           Network.Xmpp.Sasl.Types import           Network.Xmpp.Stream@@ -87,14 +89,15 @@                 Nothing -> return . Just $ serviceUnavailable iq                 Just ch -> do                   sentRef <- newTMVar False-                  let answerT answer = do-                          let IQRequest iqid from _to lang _tp bd = iq+                  let answerT answer attrs = do+                          let IQRequest iqid from _to lang _tp bd _attrs = iq                               response = case answer of                                   Left er  -> IQErrorS $ IQError iqid Nothing                                                                   from lang er-                                                                  (Just bd)+                                                                  (Just bd) attrs                                   Right res -> IQResultS $ IQResult iqid Nothing                                                                     from lang res+                                                                    attrs                           Ex.bracketOnError (atomically $ takeTMVar sentRef)                                             (atomically .  tryPutTMVar sentRef)                                             $ \wasSent -> do@@ -114,8 +117,8 @@                   writeTChan ch $ IQRequestTicket answerT iq as                   return Nothing         maybe (return ()) (void . out) res-    serviceUnavailable (IQRequest iqid from _to lang _tp bd) =-        IQErrorS $ IQError iqid Nothing from lang err (Just bd)+    serviceUnavailable (IQRequest iqid from _to lang _tp bd _attrs) =+        IQErrorS $ IQError iqid Nothing from lang err (Just bd) []     err = StanzaError Cancel ServiceUnavailable Nothing Nothing      handleIQResponse :: TVar IQHandlers -> Either IQError IQResult -> IO ()@@ -164,30 +167,38 @@     iqHands  <- lift $ newTVarIO (Map.empty, Map.empty)     eh <- lift $ newEmptyTMVarIO     ros <- liftIO . newTVarIO $ Roster Nothing Map.empty+    peers <- liftIO . newTVarIO $ Peers Map.empty     rew <- lift $ newTVarIO 60     let out = writeStanza writeSem-    let rosterH = if (enableRoster config) then [handleRoster ros out]-                                           else []+    boundJid <- liftIO $ withStream' (gets streamJid) stream+    let rosterH = if (enableRoster config)+                  then [handleRoster boundJid ros out]+                  else []+    let presenceH = if (enablePresenceTracking config)+                    then [handlePresence (onPresenceChange config) peers out]+                    else []     (sStanza, ps) <- initPlugins out $ plugins config     let stanzaHandler = runHandlers $ List.concat                         [ inHandler <$> ps-                        , [ toChan stanzaChan out-                          , handleIQ iqHands out-                          ]+                        , [ toChan stanzaChan sStanza]+                        , presenceH                         , rosterH+                        , [ handleIQ iqHands sStanza]                         ]-    (kill, streamState, reader) <- ErrorT $ startThreadsWith writeSem stanzaHandler eh stream+    (kill, sState, reader) <- ErrorT $ startThreadsWith writeSem stanzaHandler+                                                        eh stream     idGen <- liftIO $ sessionStanzaIDs config     let sess = Session { stanzaCh = stanzaChan                        , iqHandlers = iqHands                        , writeSemaphore = writeSem                        , readerThread = reader                        , idGenerator = idGen-                       , streamRef = streamState+                       , streamRef = sState                        , eventHandlers = eh                        , stopThreads = kill                        , conf = config                        , rosterRef = ros+                       , presenceRef = peers                        , sendStanza' = sStanza                        , sRealm = realm                        , sSaslCredentials = mbSasl@@ -195,9 +206,11 @@                        }     liftIO . atomically $ putTMVar eh $ EventHandlers { connectionClosedHandler =                                                  onConnectionClosed config sess }+    -- Pass the new session to the plugins so they can "tie the knot"     liftIO . forM_ ps $ \p -> onSessionUp p sess     return sess   where+    -- Pass the stanza out action to each plugin     initPlugins out' = go out' []       where         go out ps' [] = return (out, ps')@@ -267,8 +280,6 @@                               then [plain uname Nothing pwd]                               else []                             , Nothing)--  -- | Reconnect immediately with the stored settings. Returns @Just@ the error -- when the reconnect attempt fails and Nothing when no failure was encountered.
source/Network/Xmpp/Concurrent/Basic.hs view
@@ -1,6 +1,7 @@ {-# OPTIONS_HADDOCK hide #-} module Network.Xmpp.Concurrent.Basic where +import           Control.Applicative import           Control.Concurrent.STM import qualified Control.Exception as Ex import           Control.Monad.State.Strict@@ -19,6 +20,7 @@ writeStanza :: WriteSemaphore -> Stanza -> IO (Either XmppFailure ()) writeStanza sem a = do     let outData = renderElement $ nsHack (pickleElem xpStanza a)+    debugOut outData     semWrite sem outData  @@ -69,3 +71,8 @@         Plain -> return ()         Secured -> return ()         _ -> retry++streamState :: Session -> STM ConnectionState+streamState Session{streamRef = sr}  = do+    s <- readTMVar sr+    streamConnectionState <$> (readTMVar $ unStream s)
source/Network/Xmpp/Concurrent/IQ.hs view
@@ -1,3 +1,6 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-} {-# OPTIONS_HADDOCK hide #-} module Network.Xmpp.Concurrent.IQ where @@ -6,12 +9,20 @@ import           Control.Concurrent.STM import           Control.Concurrent.Thread.Delay (delay) import           Control.Monad+import           Control.Monad.Error+import           Control.Monad.Trans import qualified Data.Map as Map+import           Data.Maybe import           Data.Text (Text)+import           Data.XML.Pickle import           Data.XML.Types+import           Lens.Family2 (toListOf, (&), (^.)) import           Network.Xmpp.Concurrent.Basic import           Network.Xmpp.Concurrent.Types+import           Network.Xmpp.Lens+import           Network.Xmpp.Stanza import           Network.Xmpp.Types+import           System.Log.Logger  -- | Sends an IQ, returns an STM action that returns the first inbound IQ with a -- matching ID that has type @result@ or @error@ or Nothing if the timeout was@@ -27,11 +38,12 @@        -> Maybe LangTag  -- ^ Language tag of the payload (@Nothing@ for                          -- default)        -> Element -- ^ The IQ body (there has to be exactly one)+       -> [ExtendedAttribute] -- ^ Additional stanza attributes        -> Session        -> IO (Either XmppFailure (STM (Maybe (Annotated IQResponse))))-sendIQ timeOut to tp lang body session = do+sendIQ timeOut t tp lang body attrs session = do     newId <- idGenerator session-    j <- case to of+    j <- case t of         Just t -> return $ Right t         Nothing -> Left <$> getJid session     ref <- atomically $ do@@ -40,7 +52,8 @@         (byNS, byId) <- readTVar (iqHandlers session)         writeTVar (iqHandlers session) (byNS, Map.insert newId value byId)         return resRef-    res <- sendStanza (IQRequestS $ IQRequest newId Nothing to lang tp body) session+    res <- sendStanza (IQRequestS $ IQRequest newId Nothing t lang tp body attrs)+                      session     case res of         Right () -> do             case timeOut of@@ -60,14 +73,15 @@  -- | Like 'sendIQ', but waits for the answer IQ. sendIQA' :: Maybe Integer-        -> Maybe Jid-        -> IQRequestType-        -> Maybe LangTag-        -> Element-        -> Session-        -> IO (Either IQSendError (Annotated IQResponse))-sendIQA' timeout to tp lang body session = do-    ref <- sendIQ timeout to tp lang body session+         -> Maybe Jid+         -> IQRequestType+         -> Maybe LangTag+         -> Element+         -> [ExtendedAttribute]+         -> Session+         -> IO (Either IQSendError (Annotated IQResponse))+sendIQA' timeout to tp lang body attrs session = do+    ref <- sendIQ timeout to tp lang body attrs session     either (return . Left . IQSendError) (fmap (maybe (Left IQTimeOut) Right)                                      . atomically) ref @@ -77,9 +91,11 @@         -> IQRequestType         -> Maybe LangTag         -> Element+        -> [ExtendedAttribute]         -> Session         -> IO (Either IQSendError IQResponse)-sendIQ' timeout to tp lang body session = fmap fst <$> sendIQA' timeout to tp lang body session+sendIQ' timeout to tp lang body attrs session =+    fmap fst <$> sendIQA' timeout to tp lang body attrs session  -- | Register your interest in inbound IQ stanzas of a specific type and -- namespace. The returned STM action yields the received, matching IQ stanzas.@@ -130,5 +146,67 @@ -- (False is returned in that case) answerIQ :: IQRequestTicket          -> Either StanzaError (Maybe Element)+         -> [ExtendedAttribute]          -> IO (Maybe (Either XmppFailure ()))-answerIQ ticket = answerTicket ticket+answerIQ = answerTicket+++-- Class++class IQRequestClass a where+    data IQResponseType a+    pickleRequest :: PU Element a+    pickleResponse :: PU [Element] (IQResponseType a)+    requestType :: a -> IQRequestType+    requestNamespace :: a -> Text++data IQRequestError = IQRequestSendError XmppFailure+                    | IQRequestTimeout+                    | IQRequestUnpickleError UnpickleError+                      deriving Show++-- | Send an IQ request. May throw IQSendError, UnpickleError,++sendIQRequest  :: (IQRequestClass a, MonadError IQRequestError m, MonadIO m) =>+                  Maybe Integer+               -> Maybe Jid+               -> a+               -> Session+               -> m (Either IQError (IQResponseType a))+sendIQRequest timeout t req con = do+    mbRes <- liftIO $ sendIQ' timeout t (requestType req) Nothing+                              (pickle pickleRequest req) [] con+    case mbRes of+        Left (IQTimeOut) -> throwError IQRequestTimeout+        Left (IQSendError e) -> throwError $ IQRequestSendError e+        Right (IQResponseError e) -> return $ Left e+        Right (IQResponseResult res) ->+              case unpickle pickleResponse (res & toListOf payloadT) of+                   Left e -> throwError $ IQRequestUnpickleError e+                   Right r -> return $ Right r++type IQRequestHandler a = a -> IO (Either StanzaError (IQResponseType a))++runIQHandler :: IQRequestClass a =>+                IQRequestHandler a+             -> Session+             -> IO ()+runIQHandler (handler :: a -> IO (Either StanzaError (IQResponseType a)))+             sess = do+    let prx = undefined :: a+        ns = (requestNamespace prx)+    mbChan <- listenIQ (requestType prx) ns sess+    case mbChan of+        Left _ -> warningM "Pontarius.Xmpp" $ "IQ namespace " ++ show ns+                            ++ " is already handled"+        Right getNext -> forever $ do+            ticket <- atomically getNext+            case unpickle pickleRequest (iqRequestBody ticket ^. payload) of+                Left _ -> answerIQ ticket (Left $ mkStanzaError BadRequest) []+                Right req -> do+                    res <- handler req+                    case res of+                        Left e -> answerIQ ticket (Left e) []+                        Right r -> do+                            let answer = (pickle pickleResponse r)+                            answerIQ ticket (Right $ listToMaybe answer ) []
source/Network/Xmpp/Concurrent/Presence.hs view
@@ -3,9 +3,12 @@  import Control.Applicative ((<$>)) import Control.Concurrent.STM-import Network.Xmpp.Types-import Network.Xmpp.Concurrent.Types+import Lens.Family2 hiding (to)+import Lens.Family2.Stock import Network.Xmpp.Concurrent.Basic+import Network.Xmpp.Concurrent.Types+import Network.Xmpp.Lens+import Network.Xmpp.Types  -- | Read a presence stanza from the inbound stanza channel, discards any other -- stanzas. Returns the presence stanza with annotations.@@ -40,4 +43,11 @@  -- | Send a presence stanza. sendPresence :: Presence -> Session -> IO (Either XmppFailure ())-sendPresence p session = sendStanza (PresenceS p) session+sendPresence p session = sendStanza (PresenceS checkedP) session+  where+    -- | RFC 6121 §3.1.1: When a user sends a presence subscription request to a+    -- potential instant messaging and presence contact, the value of the 'to'+    -- attribute MUST be a bare JID rather than a full JID+    checkedP = case presenceType p of+        Subscribe -> p & to . _Just %~ toBare+        _ -> p
source/Network/Xmpp/Concurrent/Threads.hs view
@@ -26,8 +26,6 @@ readWorker onStanza onCClosed stateRef = forever . Ex.mask_ $ do      s' <- Ex.catches ( do-                   -- we don't know whether pull will-                   -- necessarily be interruptible                         atomically $ do                             s@(Stream con) <- readTMVar stateRef                             scs <- streamConnectionState <$> readTMVar con@@ -44,6 +42,8 @@         Nothing -> return ()         Just s -> do             res <- Ex.catches (do+                   -- we don't know whether pull will+                   -- necessarily be interruptible                              allowInterrupt                              res <- pullStanza s                              case res of@@ -70,9 +70,7 @@     allowInterrupt = unsafeUnmask $ return ()     -- While waiting for the first semaphore(s) to flip we might receive another     -- interrupt. When that happens we add it's semaphore to the list and retry-    -- waiting. We do this because we might receive another-    -- interrupt while we're waiting for a mutex to unlock; if that happens, the-    -- new interrupt is added to the list and is waited for as well.+    -- waiting.     handleInterrupts :: [TMVar ()] -> IO [()]     handleInterrupts ts =         Ex.catch (atomically $ forM ts takeTMVar)@@ -81,9 +79,6 @@     stateIsClosed Finished = True     stateIsClosed _        = False ---- Two streams: input and output. Threads read from input stream and write to--- output stream. -- | Runs thread in XmppState monad. Returns channel of incoming and outgoing -- stances, respectively, and an Action to stop the Threads and close the -- connection.
source/Network/Xmpp/Concurrent/Types.hs view
@@ -17,6 +17,7 @@ import           Data.XML.Types (Element) import           Network import           Network.Xmpp.IM.Roster.Types+import           Network.Xmpp.IM.PresenceTracker.Types import           Network.Xmpp.Sasl.Types import           Network.Xmpp.Types @@ -84,6 +85,17 @@       -- | Enable roster handling according to rfc 6121. See 'getRoster' to       -- acquire the current roster     , enableRoster               :: Bool+      -- | Track incomming presence stancas.+    , enablePresenceTracking     :: Bool+      -- | Callback that is invoked when the presence status of a peer changes,+      -- i.e. it comes online, goes offline or its IM presence changes. The+      -- arguments are the (full) JID of the peer, the old state and the new+      -- state. The function is called in a new thread to avoid blocking+      -- handling stanzas+    , onPresenceChange           :: Maybe ( Jid+                                          -> PeerStatus+                                          -> PeerStatus+                                          -> IO ())     }  instance Default SessionConfiguration where@@ -97,6 +109,8 @@                                          return . Text.pack . show $ curId                                , plugins = []                                , enableRoster = True+                               , enablePresenceTracking = True+                               , onPresenceChange = Nothing                                }  -- | Handlers to be run when the Xmpp session ends and when the Xmpp connection is@@ -130,6 +144,7 @@     , eventHandlers :: TMVar EventHandlers     , stopThreads :: IO ()     , rosterRef :: TVar Roster+    , presenceRef :: TVar Peers     , conf :: SessionConfiguration     , sendStanza' :: Stanza -> IO (Either XmppFailure ())     , sRealm :: HostName@@ -151,6 +166,7 @@     {   -- | Send an answer to an IQ request once. Subsequent calls will do         -- nothing and return Nothing       answerTicket :: Either StanzaError (Maybe Element)+                      -> [ExtendedAttribute]                       -> IO (Maybe (Either XmppFailure ()))       -- | The actual IQ request that created this ticket.     , iqRequestBody :: IQRequest@@ -162,4 +178,6 @@ data IQSendError = IQSendError XmppFailure -- There was an error sending the IQ                                            -- stanza                  | IQTimeOut -- No answer was received during the allotted time-                   deriving (Show, Eq)+                   deriving (Show, Eq, Typeable)++instance Ex.Exception IQSendError
source/Network/Xmpp/IM.hs view
@@ -22,11 +22,20 @@   , Roster(..)   , Item(..)   , getRoster+  , getRosterSTM   , rosterAdd   , rosterRemove+  -- * presenceTracker+  , PeerStatus(..)+  , isPeerAvailable+  , getEntityStatus+  , getAvailablePeers+  , getPeerEntities   ) where  import Network.Xmpp.IM.Message import Network.Xmpp.IM.Presence import Network.Xmpp.IM.Roster import Network.Xmpp.IM.Roster.Types+import Network.Xmpp.IM.PresenceTracker+import Network.Xmpp.IM.PresenceTracker.Types
source/Network/Xmpp/IM/Presence.hs view
@@ -4,21 +4,21 @@  module Network.Xmpp.IM.Presence where -import Data.Default-import Data.Text (Text)-import Data.XML.Pickle-import Data.XML.Types-import Network.Xmpp.Types+import           Data.Default+import           Data.Text (Text)+import           Data.XML.Pickle+import           Data.XML.Types+import           Network.Xmpp.Types  data ShowStatus = StatusAway                 | StatusChat                 | StatusDnd-                | StatusXa deriving (Read, Show)+                | StatusXa deriving (Read, Show, Eq)  data IMPresence = IMP { showStatus :: Maybe ShowStatus                       , status     :: Maybe Text                       , priority   :: Maybe Int-                      } deriving Show+                      } deriving (Show, Eq)  imPresence :: IMPresence imPresence = IMP { showStatus = Nothing@@ -53,6 +53,7 @@                xp3Tuple                   (xpOption $ xpElemNodes "{jabber:client}show"                      (xpContent xpShow))+                  -- TODO: Multiple status elements with different lang tags                   (xpOption $ xpElemNodes "{jabber:client}status"                      (xpContent xpText))                   (xpOption $ xpElemNodes "{jabber:client}priority"
+ source/Network/Xmpp/IM/PresenceTracker.hs view
@@ -0,0 +1,110 @@+{-# LANGUAGE RankNTypes #-}+module Network.Xmpp.IM.PresenceTracker where++import           Control.Applicative+import           Control.Concurrent+import           Control.Concurrent.STM+import           Control.Monad+import qualified Data.Foldable as Foldable+import           Data.Map.Strict (Map)+import qualified Data.Map.Strict as Map+import           Data.Maybe+import           Lens.Family2+import           Lens.Family2.Stock+import           Network.Xmpp.Concurrent.Types+import           Network.Xmpp.IM.Presence+import           Network.Xmpp.Lens hiding (Lens, Traversal)+import           Network.Xmpp.Types+import           Prelude hiding (mapM)++import           Network.Xmpp.IM.PresenceTracker.Types++_peers :: Iso Peers (Map Jid (Map Jid (Maybe IMPresence)))+_peers = mkIso unPeers Peers++_PeerAvailable :: Prism PeerStatus (Maybe IMPresence)+_PeerAvailable = prism' PeerAvailable fromPeerAvailable+  where+    fromPeerAvailable (PeerAvailable pa) = Just pa+    fromPeerAvailable _  = Nothing++_PeerUnavailable :: Prism PeerStatus ()+_PeerUnavailable = prism' (const PeerUnavailable) fromPeerUnavailable+  where+    fromPeerUnavailable PeerUnavailable = Just ()+    fromPeerUnavailable _ = Nothing++_PeerStatus :: Iso (Maybe (Maybe IMPresence)) PeerStatus+_PeerStatus = mkIso toPeerStatus fromPeerStatus+  where+    toPeerStatus (Nothing) = PeerUnavailable+    toPeerStatus (Just imp) = PeerAvailable imp+    fromPeerStatus PeerUnavailable = Nothing+    fromPeerStatus (PeerAvailable imp) = Just imp++maybeMap :: Iso (Maybe (Map a b)) (Map a b)+maybeMap = mkIso maybeToMap mapToMaybe+  where+    maybeToMap Nothing = Map.empty+    maybeToMap (Just m) = m+    mapToMaybe m | Map.null m = Nothing+                 | otherwise = Just m+++-- | Status of give full JID+peerStatusL :: Jid -> Lens' Peers PeerStatus+peerStatusL j = _peers . at (toBare j)  . maybeMap . at j . _PeerStatus++peerMapPeerAvailable :: Jid -> Peers -> Bool+peerMapPeerAvailable j | isFull j = not . nullOf (peerStatusL j . _PeerAvailable)+                       | otherwise = not . nullOf (_peers . at j . _Just)++handlePresence :: Maybe (Jid -> PeerStatus -> PeerStatus -> IO ())+               -> TVar Peers+               -> StanzaHandler+handlePresence onChange peers _ st _  = do+        let mbPr = do+                pr <- st ^? _Presence -- Only act on presence stanzas+                fr <- pr ^? from . _Just . _isFull -- Only act on full JIDs+                return (pr, fr)+        Foldable.forM_ mbPr $ \(pr, fr) ->+            case presenceType pr of+                Available -> setStatus fr   (PeerAvailable (getIMPresence pr))+                Unavailable -> setStatus fr PeerUnavailable+                _ -> return ()+        return [(st, [])]+  where+    setStatus fr newStatus = do+        os <- atomically $ do+            ps <- readTVar peers+            let oldStatus = ps ^. peerStatusL fr+            writeTVar peers $ ps & set (peerStatusL fr) newStatus+            return oldStatus+        unless (os == newStatus) $ case onChange of+            Nothing -> return ()+            Just oc -> void . forkIO $ oc fr os newStatus+        return ()++-- | Check whether a given jid is available+isPeerAvailable :: Jid -> Session -> STM Bool+isPeerAvailable j sess = peerMapPeerAvailable j <$> readTVar (presenceRef sess)++-- | Get status of given full JID+getEntityStatus :: Jid -> Session -> STM PeerStatus+getEntityStatus j sess = do+    peers <- readTVar (presenceRef sess)+    return $ peers ^. peerStatusL j++-- | Get list of (bare) Jids with available entities+getAvailablePeers :: Session -> STM [Jid]+getAvailablePeers sess = do+    Peers peers <- readTVar (presenceRef sess)+    return $ Map.keys peers++-- | Get all available full JIDs to the given JID+getPeerEntities :: Jid -> Session -> STM (Map Jid (Maybe IMPresence))+getPeerEntities j sess = do+    Peers peers <- readTVar (presenceRef sess)+    case Map.lookup (toBare j) peers of+        Nothing -> return Map.empty+        Just js -> return js
+ source/Network/Xmpp/IM/PresenceTracker/Types.hs view
@@ -0,0 +1,20 @@+module Network.Xmpp.IM.PresenceTracker.Types where++import           Data.Map (Map)++import           Network.Xmpp.Types+import           Network.Xmpp.IM.Presence++-- Map from bare JIDs to a map of full JIDs to show maybe status.+--+-- Invariants:+-- * The outer map should not have entries for bare JIDs that have no+--   available resource, i.e. the inner map should never be empty+--+-- * The inner map keys' local and domain part coincide with the outer keys'+newtype Peers = Peers { unPeers :: Map Jid (Map Jid (Maybe IMPresence))}+                deriving (Show)++data PeerStatus = PeerAvailable (Maybe IMPresence)+                | PeerUnavailable+                  deriving (Show, Eq)
source/Network/Xmpp/IM/Roster.hs view
@@ -31,22 +31,15 @@ timeout :: Maybe Integer timeout = Just 3000000 -- 3 seconds --- | Push a roster item to the server. The values for approved and ask are--- ignored and all values for subsciption except "remove" are ignored.-rosterPush :: Item -> Session -> IO (Either IQSendError (Annotated IQResponse))-rosterPush item session = do-    let el = pickleElem xpQuery (Query Nothing [fromItem item])-    sendIQA' timeout Nothing Set Nothing el session- -- | Add or update an item to the roster. -- -- To update the item just send the complete set of new data.-rosterAdd :: Jid -- ^ JID of the item+rosterSet :: Jid -- ^ JID of the item           -> Maybe Text -- ^ Name alias           -> [Text] -- ^ Groups (duplicates will be removed)           -> Session           -> IO (Either IQSendError (Annotated IQResponse))-rosterAdd j n gs session = do+rosterSet j n gs session = do     let el = pickleElem xpQuery (Query Nothing                                  [QueryItem { qiApproved = Nothing                                             , qiAsk = False@@ -55,8 +48,16 @@                                             , qiSubscription = Nothing                                             , qiGroups = nub gs                                             }])-    sendIQA' timeout Nothing Set Nothing el session+    sendIQA' timeout Nothing Set Nothing el [] session +-- | Synonym to rosterSet+rosterAdd :: Jid+          -> Maybe Text+          -> [Text]+          -> Session+          -> IO (Either IQSendError (Annotated IQResponse))+rosterAdd = rosterSet+ -- | Remove an item from the roster. Return 'True' when the item is sucessfully -- removed or if it wasn't in the roster to begin with. rosterRemove :: Jid -> Session -> IO Bool@@ -69,10 +70,21 @@             case res of                 Right (IQResponseResult IQResult{}, _) -> return True                 _ -> return False+  where+    rosterPush :: Item+               -> Session+               -> IO (Either IQSendError (Annotated IQResponse))+    rosterPush item session = do+        let el = pickleElem xpQuery (Query Nothing [fromItem item])+        sendIQA' timeout Nothing Set Nothing el [] session +-- | Retrieve the current Roster state (STM version)+getRosterSTM :: Session -> STM Roster+getRosterSTM session = readTVar (rosterRef session)+ -- | Retrieve the current Roster state getRoster :: Session -> IO Roster-getRoster session = atomically $ readTVar (rosterRef session)+getRoster session = atomically $ getRosterSTM session  -- | Get the initial roster or refresh the roster. You don't need to call this -- on your own.@@ -86,37 +98,48 @@                           "Server did not return a roster: "         Just roster -> atomically $ writeTVar (rosterRef session) roster -handleRoster :: TVar Roster -> StanzaHandler-handleRoster ref out sta _ = case sta of-    IQRequestS (iqr@IQRequest{iqRequestPayload =-                                   iqb@Element{elementName = en}})-        | nameNamespace en == Just "jabber:iq:roster" -> do-            case iqRequestFrom iqr of-                Just _from -> return [(sta, [])] -- Don't handle roster pushes-                                                 -- from unauthorized sources-                Nothing -> case unpickleElem xpQuery iqb of-                    Right Query{ queryVer = v-                               , queryItems = [update]-                               } -> do-                        handleUpdate v update-                        _ <- out $ result iqr-                        return []-                    _ -> do-                        errorM "Pontarius.Xmpp" "Invalid roster query"-                        _ <- out $ badRequest iqr-                        return []-    _ -> return [(sta, [])]+handleRoster :: Maybe Jid -> TVar Roster -> StanzaHandler+handleRoster mbBoundJid ref out sta _ = do+    case sta of+        IQRequestS (iqr@IQRequest{iqRequestPayload =+                                       iqb@Element{elementName = en}})+            | nameNamespace en == Just "jabber:iq:roster" -> do+                let doHandle = case (iqRequestFrom iqr, mbBoundJid) of+                        -- We don't need to check our own JID when the IQ+                        -- request was sent without a from address+                        (Nothing, _) -> True+                        -- We don't have a Jid bound, so we can't verify that+                        -- the from address matches our bare jid+                        (Just _fr, Nothing) -> False+                        -- Check that the from address matches our bare jid+                        (Just fr, Just boundJid) | fr == toBare boundJid -> True+                                                 | otherwise -> False+                if doHandle+                    then case unpickleElem xpQuery iqb of+                        Right Query{ queryVer = v+                                   , queryItems = [update]+                                   } -> do+                            handleUpdate v update+                            _ <- out $ result iqr+                            return []+                        _ -> do+                            errorM "Pontarius.Xmpp" "Invalid roster query"+                            _ <- out $ badRequest iqr+                            return []+                    -- Don't handle roster pushes from unauthorized sources+                    else return [(sta, [])]+        _ -> return [(sta, [])]   where     handleUpdate v' update = atomically $ modifyTVar ref $ \(Roster v is) ->         Roster (v' `mplus` v) $ case qiSubscription update of             Just Remove -> Map.delete (qiJid update) is             _ -> Map.insert (qiJid update) (toItem update) is -    badRequest (IQRequest iqid from _to lang _tp bd) =-        IQErrorS $ IQError iqid Nothing from lang errBR (Just bd)+    badRequest (IQRequest iqid from _to lang _tp bd _attrs) =+        IQErrorS $ IQError iqid Nothing from lang errBR (Just bd) []     errBR = StanzaError Cancel BadRequest Nothing Nothing-    result (IQRequest iqid from _to lang _tp _bd) =-        IQResultS $ IQResult iqid Nothing from lang Nothing+    result (IQRequest iqid from _to lang _tp _bd _attrs) =+        IQResultS $ IQResult iqid Nothing from lang Nothing []  retrieveRoster :: Maybe Roster -> Session -> IO (Maybe Roster) retrieveRoster mbOldRoster sess = do@@ -128,6 +151,7 @@                 else Nothing     res <- sendIQ' timeout Nothing Get Nothing                    (pickleElem xpQuery (Query version []))+                   []                    sess     case res of         Left e -> do@@ -156,9 +180,13 @@                  , riAsk = qiAsk qi                  , riJid = qiJid qi                  , riName = qiName qi-                 , riSubscription = fromMaybe None (qiSubscription qi)+                 , riSubscription = fromSubscription (qiSubscription qi)                  , riGroups = nub $ qiGroups qi                  }+  where+    fromSubscription Nothing = None+    fromSubscription (Just s) | s `elem` [None, To, From, Both] = s+                              | otherwise = None  fromItem :: Item -> QueryItem fromItem i = QueryItem { qiApproved = Nothing@@ -197,17 +225,15 @@  xpSubscription :: PU Text Subscription xpSubscription = ("xpSubscription", "") <?>-        xpPartial ( \input -> case subscriptionFromText input of-                                   Nothing -> Left "Could not parse subscription."-                                   Just j -> Right j)-                  subscriptionToText+        xpIso subscriptionFromText+              subscriptionToText   where-    subscriptionFromText "none" = Just None-    subscriptionFromText "to" = Just To-    subscriptionFromText "from" = Just From-    subscriptionFromText "both" = Just Both-    subscriptionFromText "remove" = Just Remove-    subscriptionFromText _ = Nothing+    subscriptionFromText "none" = None+    subscriptionFromText "to" = To+    subscriptionFromText "from" = From+    subscriptionFromText "both" = Both+    subscriptionFromText "remove" = Remove+    subscriptionFromText _ = None     subscriptionToText None = "none"     subscriptionToText To = "to"     subscriptionToText From = "from"
source/Network/Xmpp/Internal.hs view
@@ -17,43 +17,58 @@ -- top of this API.  module Network.Xmpp.Internal-  ( -- * Stream-    Stream(..)-  , StreamConfiguration(..)-  , StreamState(..)-  , StreamHandle(..)-  , StreamFeatures(..)-  , openStream-  , withStream-    -- * TLS-  , tls-  , TlsBehaviour(..)-    -- * Auth-  , SaslHandler-  , auth-    -- * Stanzas-  , Stanza(..)-  , pushStanza-  , pullStanza-  , writeStanza-    -- ** IQ-  , pushIQ-  , iqError-  , iqResult-  , associatedErrorType-    -- * Plugins-  , Plugin-  , Plugin'(..)-  , Annotation(..)-  , connectTls- )-       where+  ( module Network.Xmpp.Concurrent+  , module Network.Xmpp.Concurrent.Basic+  , module Network.Xmpp.Concurrent.IQ+  , module Network.Xmpp.Concurrent.Message+  , module Network.Xmpp.Concurrent.Monad+  , module Network.Xmpp.Concurrent.Presence+  , module Network.Xmpp.Concurrent.Threads+  , module Network.Xmpp.Concurrent.Types+  , module Network.Xmpp.IM.Message+  , module Network.Xmpp.IM.Presence+  , module Network.Xmpp.IM.Roster+  , module Network.Xmpp.IM.Roster.Types+  , module Network.Xmpp.Marshal+  , module Network.Xmpp.Sasl+  , module Network.Xmpp.Sasl.Common+  , module Network.Xmpp.Sasl.Mechanisms+  , module Network.Xmpp.Sasl.Mechanisms.DigestMd5+  , module Network.Xmpp.Sasl.Mechanisms.Plain+  , module Network.Xmpp.Sasl.Mechanisms.Scram+  , module Network.Xmpp.Sasl.StringPrep+  , module Network.Xmpp.Sasl.Types+  , module Network.Xmpp.Stanza+  , module Network.Xmpp.Stream+  , module Network.Xmpp.Tls+  , module Network.Xmpp.Types+  , module Network.Xmpp.Utilities+  ) where ++import Network.Xmpp.Concurrent import Network.Xmpp.Concurrent.Basic+import Network.Xmpp.Concurrent.IQ+import Network.Xmpp.Concurrent.Message+import Network.Xmpp.Concurrent.Monad+import Network.Xmpp.Concurrent.Presence+import Network.Xmpp.Concurrent.Threads import Network.Xmpp.Concurrent.Types+import Network.Xmpp.IM.Message+import Network.Xmpp.IM.Presence+import Network.Xmpp.IM.Roster+import Network.Xmpp.IM.Roster.Types+import Network.Xmpp.Marshal import Network.Xmpp.Sasl+import Network.Xmpp.Sasl.Common+import Network.Xmpp.Sasl.Mechanisms+import Network.Xmpp.Sasl.Mechanisms.DigestMd5+import Network.Xmpp.Sasl.Mechanisms.Plain+import Network.Xmpp.Sasl.Mechanisms.Scram+import Network.Xmpp.Sasl.StringPrep import Network.Xmpp.Sasl.Types import Network.Xmpp.Stanza-import Network.Xmpp.Stream+import Network.Xmpp.Stream hiding (mbl, lmb) import Network.Xmpp.Tls import Network.Xmpp.Types+import Network.Xmpp.Utilities
source/Network/Xmpp/Lens.hs view
@@ -5,30 +5,60 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FunctionalDependencies #-} --- | Van Laarhoven lenses for XMPP types. The lenses are designed to work with--- the lens library. This module also provides a few simple accessors ('view',--- 'modify', 'set' and 'getAll') so you don't need to pull in the--- lens library to get some use out of them.+-- | (More than just) Van Laarhoven lenses for XMPP types. The accessors in here+-- are designed to work with an optics library like lens or lens-family. This+-- module also provides a few simple functions ('view', 'modify', 'set' and+-- 'getAll') so you don't need to pull in another library to get some use out+-- of them. ----- The name of the lenses corresponds to the field name of the data types with+-- * The name of the lenses corresponds to the field name of the data types with -- an upper-case L appended. For documentation of the fields refer to the documentation of the data types (linked in the section header)+--+-- * Same goes for Traversals, except they are suffixed with a \'T\'+--+-- * Prism generally start with an underscore+--+-- /NB/ you do not need to import this module to get access to the optics+-- defined herein. They are also exported from Network.Xmpp. You only need to+-- import this module if you want to use the complementary accessor functions+-- without using an optics library like lens or lens-family  module Network.Xmpp.Lens        ( Lens        , Traversal+       , Prism+       , Iso          -- * Accessors          -- | Reimplementation of the basic lens functions so you don't have to-         -- bring in all of lens library in to use the lenses+         -- bring in a lens library to use the optics           -- ** Lenses-       , view+       , LF.view        , modify-       , set+       , LF.set          -- * Traversals        , getAll+         -- * Prisms++         -- ** Construction+       , prism'+       , mkLens+       , mkIso          -- * Lenses +         -- ** JID+       , _JidText+       , _isFull+       , _isBare+          -- ** Stanzas+       , _IQRequest+       , _IQResult+       , _IQError+       , _Message+       , _MessageError+       , _Presence+       , _PresenceError        , IsStanza(..)        , HasStanzaPayload(..)        , IsErrorStanza(..)@@ -48,12 +78,23 @@        , establishSessionL        , tlsBehaviourL        , tlsParamsL+         -- **** TLS parameters+       , clientServerIdentificationL+       , tlsServerIdentificationL+       , clientSupportedL+       , supportedCiphersL+       , supportedVersionsL+       , tlsSupportedCiphersL+       , tlsSupportedVersionsL+       , clientUseServerNameIndicationL+       , tlsUseNameIndicationL          -- *** 'SessionConfiguration'        , streamConfigurationL        , onConnectionClosedL        , sessionStanzaIDsL        , ensableRosterL        , pluginsL+       , onPresenceChangeL          -- ** IM          -- *** Roster          -- **** 'Roster'@@ -99,40 +140,43 @@        where  import           Control.Applicative-import           Data.Functor.Identity(Identity(..))+import qualified Data.ByteString as BS+import           Data.Functor.Identity (Identity(..)) import qualified Data.Map as Map+import           Data.Profunctor+import           Data.Text (Text) import qualified Data.Text as Text-import           Data.Text(Text)-import           Data.XML.Types(Element)-import           Network.DNS(ResolvConf)-import           Network.TLS (ClientParams)+import           Data.XML.Types (Element)+import qualified Lens.Family2 as LF+import           Network.DNS (ResolvConf)+import           Network.TLS as TLS import           Network.Xmpp.Concurrent.Types-import           Network.Xmpp.IM.Roster.Types import           Network.Xmpp.IM.Message import           Network.Xmpp.IM.Presence+import           Network.Xmpp.IM.PresenceTracker.Types+import           Network.Xmpp.IM.Roster.Types import           Network.Xmpp.Types  -- | Van-Laarhoven lenses.+{-# DEPRECATED Lens "Use Lens' from lens-family or lens" #-} type Lens a b = Functor f => (b -> f b) -> a -> f a +{-# DEPRECATED Traversal "Use Traversal' from lens-family or lens" #-} type Traversal a b = Applicative f => (b -> f b) -> a -> f a ---- Accessors----------------+type Prism a b = forall p f. (Choice p, Applicative f) => p b (f b) -> p a (f a) +type Iso a b = forall p f. (Profunctor p, Functor f) => p b (f b) -> p a (f a) --- | Read the value the lens is pointing to-view :: Lens a b -> a -> b-view l x = getConst $ l Const x+prism' :: (b -> s) -> (s -> Maybe b) -> Prism s b+prism' bs sma = dimap (\s -> maybe (Left s) Right (sma s))+                      (either pure (fmap bs)) . right' --- | Replace the value the lens is pointing to-set :: Lens a b -> b -> a -> a-set l b x = modify l (const b) x+mkLens :: (a -> b) -> (b -> a ->  a) -> Lens a b+mkLens get set = \inj x -> fmap (flip set x) (inj $ get x) --- | modify the Value(s) a Lens or Traversal is pointing to-modify :: Traversal a b -> (b -> b) -> a -> a-modify t f = runIdentity . t (Identity . f)+mkIso :: (a -> b) -> (b -> a) -> Iso a b+mkIso t f = dimap t (fmap f)  newtype Collect a b = Collect {getCollection :: [a]} deriving Functor @@ -140,14 +184,27 @@     pure _ = Collect []     Collect xs <*> Collect ys = Collect $ xs ++ ys +{-# DEPRECATED getAll "use toListOf (lens-family), partsOf (lens) or similar" #-} -- | Return all the values a Traversal is pointing to in a list getAll :: Traversal a b -> a -> [b] getAll t = getCollection . t (Collect . pure) +{-# DEPRECATED modify "use over (lens-family, lens)" #-}+modify :: Traversal a b -> (b -> b) -> a -> a+modify t f = runIdentity . t (Identity . f)  -- Xmpp Lenses -------------------- +_JidText :: Prism Text Jid+_JidText = prism' jidToText jidFromText++_isFull :: Prism Jid Jid+_isFull = prism' id (\j -> if isFull j then Just j else Nothing)++_isBare :: Prism Jid Jid+_isBare = prism' toBare (\j -> if isBare j then Just j else Nothing)+ class IsStanza s where     -- | From-attribute of the stanza     from :: Lens s (Maybe Jid)@@ -278,6 +335,48 @@                       <$> inj (if Text.null x then Nothing else Just x)  +_IQRequest :: Prism Stanza IQRequest+_IQRequest = prism' IQRequestS fromIQRequestS+  where+    fromIQRequestS (IQRequestS s) = Just s+    fromIQRequestS _ = Nothing++_IQResult :: Prism Stanza IQResult+_IQResult = prism' IQResultS fromIQResultS+  where+    fromIQResultS (IQResultS s) = Just s+    fromIQResultS _ = Nothing++_IQError :: Prism Stanza IQError+_IQError = prism' IQErrorS fromIQErrorS+  where+    fromIQErrorS (IQErrorS s) = Just s+    fromIQErrorS _ = Nothing++_Message :: Prism Stanza Message+_Message = prism' MessageS fromMessageS+  where+    fromMessageS (MessageS s) = Just s+    fromMessageS _ = Nothing++_MessageError :: Prism Stanza MessageError+_MessageError = prism' MessageErrorS fromMessageErrorS+  where+    fromMessageErrorS (MessageErrorS s) = Just s+    fromMessageErrorS _ = Nothing++_Presence :: Prism Stanza Presence+_Presence = prism' PresenceS fromPresenceS+  where+    fromPresenceS (PresenceS s) = Just s+    fromPresenceS _ = Nothing++_PresenceError :: Prism Stanza PresenceError+_PresenceError = prism' PresenceErrorS fromPresenceErrorS+  where+    fromPresenceErrorS (PresenceErrorS s) = Just s+    fromPresenceErrorS _ = Nothing+ class IsErrorStanza s where     -- | Error element of the stanza     stanzaError :: Lens s StanzaError@@ -390,11 +489,36 @@ tlsBehaviourL inj sc@StreamConfiguration{tlsBehaviour = x}     = (\x' -> sc{tlsBehaviour = x'}) <$> inj x + tlsParamsL :: Lens StreamConfiguration ClientParams tlsParamsL inj sc@StreamConfiguration{tlsParams = x}     = (\x' -> sc{tlsParams = x'}) <$> inj x --- SessioConfiguration+-- TLS parameters+-----------------++clientServerIdentificationL  :: Lens ClientParams (String, BS.ByteString)+clientServerIdentificationL inj cp@ClientParams{clientServerIdentification = x}+    = (\x' -> cp{clientServerIdentification = x'}) <$> inj x++clientSupportedL  :: Lens ClientParams Supported+clientSupportedL inj cp@ClientParams{clientSupported = x}+    = (\x' -> cp{clientSupported = x'}) <$> inj x++clientUseServerNameIndicationL  :: Lens ClientParams Bool+clientUseServerNameIndicationL inj+    cp@ClientParams{clientUseServerNameIndication = x}+    = (\x' -> cp{clientUseServerNameIndication = x'}) <$> inj x++supportedCiphersL :: Lens Supported [Cipher]+supportedCiphersL inj s@Supported{supportedCiphers = x}+    = (\x' -> s{supportedCiphers = x'}) <$> inj x++supportedVersionsL :: Lens Supported [TLS.Version]+supportedVersionsL inj s@Supported{supportedVersions = x}+    = (\x' -> s{supportedVersions = x'}) <$> inj x++-- SessionConfiguration ----------------------- streamConfigurationL :: Lens SessionConfiguration StreamConfiguration streamConfigurationL inj sc@SessionConfiguration{sessionStreamConfiguration = x}@@ -415,6 +539,34 @@ pluginsL :: Lens SessionConfiguration [Plugin] pluginsL inj sc@SessionConfiguration{plugins = x}     = (\x' -> sc{plugins = x'}) <$> inj x++onPresenceChangeL :: Lens SessionConfiguration (Maybe ( Jid -> PeerStatus+                                                        -> PeerStatus -> IO ()))+onPresenceChangeL inj sc@SessionConfiguration{onPresenceChange = x}+    = (\x' -> sc{onPresenceChange = x'}) <$> inj x++-- | Access clientServerIdentification inside tlsParams inside streamConfiguration+tlsServerIdentificationL  :: Lens SessionConfiguration (String, BS.ByteString)+tlsServerIdentificationL = streamConfigurationL+                         . tlsParamsL+                         . clientServerIdentificationL++-- | Access clientUseServerNameIndication inside tlsParams+tlsUseNameIndicationL :: Lens SessionConfiguration Bool+tlsUseNameIndicationL = streamConfigurationL+                      . tlsParamsL+                      . clientUseServerNameIndicationL++-- | Access supportedCiphers inside clientSupported inside tlsParams+tlsSupportedCiphersL :: Lens SessionConfiguration [Cipher]+tlsSupportedCiphersL =  streamConfigurationL+                     .  tlsParamsL . clientSupportedL . supportedCiphersL++-- | Access supportedVersions inside clientSupported inside tlsParams+tlsSupportedVersionsL :: Lens SessionConfiguration [TLS.Version]+tlsSupportedVersionsL = streamConfigurationL+                      . tlsParamsL . clientSupportedL . supportedVersionsL+  -- Roster ------------------
source/Network/Xmpp/Marshal.hs view
@@ -10,12 +10,14 @@  module Network.Xmpp.Marshal where -import Data.XML.Pickle-import Data.XML.Types+import           Data.XML.Pickle+import           Data.XML.Types -import Data.Text+import qualified Control.Exception as Ex+import           Data.Text (Text)+import qualified Data.Text as Text -import Network.Xmpp.Types+import           Network.Xmpp.Types  xpNonemptyText :: PU Text NonemptyText xpNonemptyText = ("xpNonemptyText" , "") <?+> xpWrap Nonempty fromNonempty xpText@@ -23,6 +25,16 @@ xpStreamStanza :: PU [Node] (Either StreamErrorInfo Stanza) xpStreamStanza = xpEither xpStreamError xpStanza +xpExtendedAttrs :: PU [Attribute] [ExtendedAttribute]+xpExtendedAttrs = ("xpAttrVerbatim" , "") <?+>+                    xpIso (map (\(name, cs) -> (name, flattenContents cs)))+                          (map (\(name, c) -> (name, [ContentText c])))+  where+    flattenContents = Text.concat . filterContentText+    filterContentText = map (\c -> case c of+        ContentText t -> t+        ContentEntity{} -> Ex.throw UnresolvedEntityException )+ xpStanza :: PU [Node] Stanza xpStanza = ("xpStanza" , "") <?+> xpAlt stanzaSel     [ xpWrap IQRequestS     (\(IQRequestS     x) -> x) xpIQRequest@@ -46,15 +58,16 @@  xpMessage :: PU [Node] (Message) xpMessage = ("xpMessage" , "") <?+> xpWrap-    (\((tp, qid, from, to, lang), ext) -> Message qid from to lang tp ext)-    (\(Message qid from to lang tp ext) -> ((tp, qid, from, to, lang), ext))+    (\((tp, qid, from, to, lang, attrs), ext) -> Message qid from to lang tp ext attrs)+    (\(Message qid from to lang tp ext attrs) -> ((tp, qid, from, to, lang, attrs), ext))     (xpElem "{jabber:client}message"-         (xp5Tuple+         (xp6Tuple              (xpDefault Normal $ xpAttr "type" xpMessageType)              (xpAttrImplied "id"   xpId)              (xpAttrImplied "from" xpJid)              (xpAttrImplied "to"   xpJid)              xpLangTag+             xpExtendedAttrs              -- TODO: NS?          )          (xpAll xpElemVerbatim)@@ -62,45 +75,54 @@  xpPresence :: PU [Node] Presence xpPresence = ("xpPresence" , "") <?+> xpWrap-    (\((qid, from, to, lang, tp), ext) -> Presence qid from to lang tp ext)-    (\(Presence qid from to lang tp ext) -> ((qid, from, to, lang, tp), ext))+    (\((qid, from, to, lang, tp, attr), ext)+        -> Presence qid from to lang tp ext attr)+    (\(Presence qid from to lang tp ext attr)+       -> ((qid, from, to, lang, tp, attr), ext))     (xpElem "{jabber:client}presence"-         (xp5Tuple+         (xp6Tuple               (xpAttrImplied "id"   xpId)               (xpAttrImplied "from" xpJid)               (xpAttrImplied "to"   xpJid)               xpLangTag               (xpDefault Available $ xpAttr "type" xpPresenceType)+              xpExtendedAttrs          )          (xpAll xpElemVerbatim)     )  xpIQRequest :: PU [Node] IQRequest xpIQRequest = ("xpIQRequest" , "") <?+> xpWrap-    (\((qid, from, to, lang, tp),body) -> IQRequest qid from to lang tp body)-    (\(IQRequest qid from to lang tp body) -> ((qid, from, to, lang, tp), body))+    (\((qid, from, to, lang, tp, attr),body)+       -> IQRequest qid from to lang tp body attr)+    (\(IQRequest qid from to lang tp body attr)+        -> ((qid, from, to, lang, tp, attr), body))     (xpElem "{jabber:client}iq"-         (xp5Tuple+         (xp6Tuple              (xpAttr        "id"   xpId)              (xpAttrImplied "from" xpJid)              (xpAttrImplied "to"   xpJid)              xpLangTag              ((xpAttr        "type" xpIQRequestType))+             xpExtendedAttrs          )          xpElemVerbatim     )  xpIQResult :: PU [Node] IQResult xpIQResult = ("xpIQResult" , "") <?+> xpWrap-    (\((qid, from, to, lang, _tp),body) -> IQResult qid from to lang body)-    (\(IQResult qid from to lang body) -> ((qid, from, to, lang, ()), body))+    (\((qid, from, to, lang, _tp, attr),body)+        -> IQResult qid from to lang body attr)+    (\(IQResult qid from to lang body attr)+        -> ((qid, from, to, lang, (), attr ), body))     (xpElem "{jabber:client}iq"-         (xp5Tuple+         (xp6Tuple              (xpAttr        "id"   xpId)              (xpAttrImplied "from" xpJid)              (xpAttrImplied "to"   xpJid)              xpLangTag              ((xpAttrFixed "type" "result"))+             xpExtendedAttrs          )          (xpOption xpElemVerbatim)     )@@ -134,10 +156,8 @@     -- the optional field is left empty and must be filled in by the caller     xpStanzaErrorConditionShape :: PU Text StanzaErrorCondition     xpStanzaErrorConditionShape = ("xpStanzaErrorCondition", "") <?>-            xpPartial ( \input -> case stanzaErrorConditionFromText input of-                                       Nothing -> Left "Could not parse stanza error condition."-                                       Just j -> Right j)-                      stanzaErrorConditionToText+            xpIso stanzaErrorConditionFromText+                  stanzaErrorConditionToText     stanzaErrorConditionToText BadRequest = "bad-request"     stanzaErrorConditionToText Conflict = "conflict"     stanzaErrorConditionToText FeatureNotImplemented = "feature-not-implemented"@@ -160,41 +180,43 @@     stanzaErrorConditionToText SubscriptionRequired = "subscription-required"     stanzaErrorConditionToText UndefinedCondition = "undefined-condition"     stanzaErrorConditionToText UnexpectedRequest = "unexpected-request"-    stanzaErrorConditionFromText "bad-request" = Just BadRequest-    stanzaErrorConditionFromText "conflict" = Just Conflict-    stanzaErrorConditionFromText "feature-not-implemented" = Just FeatureNotImplemented-    stanzaErrorConditionFromText "forbidden" = Just Forbidden-    stanzaErrorConditionFromText "gone" = Just $ Gone Nothing-    stanzaErrorConditionFromText "internal-server-error" = Just InternalServerError-    stanzaErrorConditionFromText "item-not-found" = Just ItemNotFound-    stanzaErrorConditionFromText "jid-malformed" = Just JidMalformed-    stanzaErrorConditionFromText "not-acceptable" = Just NotAcceptable-    stanzaErrorConditionFromText "not-allowed" = Just NotAllowed-    stanzaErrorConditionFromText "not-authorized" = Just NotAuthorized-    stanzaErrorConditionFromText "policy-violation" = Just PolicyViolation-    stanzaErrorConditionFromText "recipient-unavailable" = Just RecipientUnavailable-    stanzaErrorConditionFromText "redirect" = Just $ Redirect Nothing-    stanzaErrorConditionFromText "registration-required" = Just RegistrationRequired-    stanzaErrorConditionFromText "remote-server-not-found" = Just RemoteServerNotFound-    stanzaErrorConditionFromText "remote-server-timeout" = Just RemoteServerTimeout-    stanzaErrorConditionFromText "resource-constraint" = Just ResourceConstraint-    stanzaErrorConditionFromText "service-unavailable" = Just ServiceUnavailable-    stanzaErrorConditionFromText "subscription-required" = Just SubscriptionRequired-    stanzaErrorConditionFromText "undefined-condition" = Just UndefinedCondition-    stanzaErrorConditionFromText "unexpected-request" = Just UnexpectedRequest-    stanzaErrorConditionFromText _ = Nothing+    stanzaErrorConditionFromText "bad-request" = BadRequest+    stanzaErrorConditionFromText "conflict" = Conflict+    stanzaErrorConditionFromText "feature-not-implemented" = FeatureNotImplemented+    stanzaErrorConditionFromText "forbidden" = Forbidden+    stanzaErrorConditionFromText "gone" = Gone Nothing+    stanzaErrorConditionFromText "internal-server-error" = InternalServerError+    stanzaErrorConditionFromText "item-not-found" = ItemNotFound+    stanzaErrorConditionFromText "jid-malformed" = JidMalformed+    stanzaErrorConditionFromText "not-acceptable" = NotAcceptable+    stanzaErrorConditionFromText "not-allowed" = NotAllowed+    stanzaErrorConditionFromText "not-authorized" = NotAuthorized+    stanzaErrorConditionFromText "policy-violation" = PolicyViolation+    stanzaErrorConditionFromText "recipient-unavailable" = RecipientUnavailable+    stanzaErrorConditionFromText "redirect" = Redirect Nothing+    stanzaErrorConditionFromText "registration-required" = RegistrationRequired+    stanzaErrorConditionFromText "remote-server-not-found" = RemoteServerNotFound+    stanzaErrorConditionFromText "remote-server-timeout" = RemoteServerTimeout+    stanzaErrorConditionFromText "resource-constraint" = ResourceConstraint+    stanzaErrorConditionFromText "service-unavailable" = ServiceUnavailable+    stanzaErrorConditionFromText "subscription-required" = SubscriptionRequired+    stanzaErrorConditionFromText "undefined-condition" = UndefinedCondition+    stanzaErrorConditionFromText "unexpected-request" = UnexpectedRequest+    stanzaErrorConditionFromText _ = UndefinedCondition    xpStanzaError :: PU [Node] StanzaError xpStanzaError = ("xpStanzaError" , "") <?+> xpWrap-    (\(tp, (cond, txt, ext)) -> StanzaError tp cond txt ext)-    (\(StanzaError tp cond txt ext) -> (tp, (cond, txt, ext)))+    (\((tp, _code), (cond, txt, ext)) -> StanzaError tp cond txt ext)+    (\(StanzaError tp cond txt ext) -> ((tp, Nothing), (cond, txt, ext)))     (xpElem "{jabber:client}error"-         (xpAttr "type" xpStanzaErrorType)+         (xp2Tuple+             (xpAttr "type" xpStanzaErrorType)+             (xpAttribute' "code" xpId))          (xp3Tuple               xpStanzaErrorCondition-              (xpOption $ xpElem "{jabber:client}text"+              (xpOption $ xpElem "{urn:ietf:params:xml:ns:xmpp-stanzas}text"                    (xpAttrImplied xmlLang xpLang)                    (xpContent xpNonemptyText)               )@@ -204,52 +226,54 @@  xpMessageError :: PU [Node] (MessageError) xpMessageError = ("xpMessageError" , "") <?+> xpWrap-    (\((_, qid, from, to, lang), (err, ext)) ->-        MessageError qid from to lang err ext)-    (\(MessageError qid from to lang err ext) ->-        (((), qid, from, to, lang), (err, ext)))+    (\((_, qid, from, to, lang, attr), (err, ext)) ->+        MessageError qid from to lang err ext attr)+    (\(MessageError qid from to lang err ext attr) ->+        (((), qid, from, to, lang, attr), (err, ext)))     (xpElem "{jabber:client}message"-         (xp5Tuple+         (xp6Tuple               (xpAttrFixed   "type" "error")               (xpAttrImplied "id"   xpId)               (xpAttrImplied "from" xpJid)               (xpAttrImplied "to"   xpJid)               (xpAttrImplied xmlLang xpLang)-              -- TODO: NS?+              xpExtendedAttrs          )          (xp2Tuple xpStanzaError (xpAll xpElemVerbatim))     )  xpPresenceError :: PU [Node] PresenceError xpPresenceError = ("xpPresenceError" , "") <?+> xpWrap-    (\((qid, from, to, lang, _),(err, ext)) ->-        PresenceError qid from to lang err ext)-    (\(PresenceError qid from to lang err ext) ->-        ((qid, from, to, lang, ()), (err, ext)))+    (\((qid, from, to, lang, _, attr),(err, ext)) ->+        PresenceError qid from to lang err ext attr)+    (\(PresenceError qid from to lang err ext attr) ->+        ((qid, from, to, lang, (), attr), (err, ext)))     (xpElem "{jabber:client}presence"-         (xp5Tuple+         (xp6Tuple               (xpAttrImplied "id"   xpId)               (xpAttrImplied "from" xpJid)               (xpAttrImplied "to"   xpJid)               xpLangTag               (xpAttrFixed "type" "error")+              xpExtendedAttrs          )          (xp2Tuple xpStanzaError (xpAll xpElemVerbatim))     )  xpIQError :: PU [Node] IQError xpIQError = ("xpIQError" , "") <?+> xpWrap-    (\((qid, from, to, lang, _tp),(err, body)) ->-        IQError qid from to lang err body)-    (\(IQError qid from to lang err body) ->-        ((qid, from, to, lang, ()), (err, body)))+    (\((qid, from, to, lang, _tp, attr),(err, body)) ->+        IQError qid from to lang err body attr)+    (\(IQError qid from to lang err body attr) ->+        ((qid, from, to, lang, (), attr), (err, body)))     (xpElem "{jabber:client}iq"-         (xp5Tuple+         (xp6Tuple               (xpAttr        "id"   xpId)               (xpAttrImplied "from" xpJid)               (xpAttrImplied "to"   xpJid)               xpLangTag               ((xpAttrFixed "type" "error"))+              xpExtendedAttrs          )          (xp2Tuple xpStanzaError (xpOption xpElemVerbatim))     )@@ -376,16 +400,14 @@  xpMessageType :: PU Text MessageType xpMessageType = ("xpMessageType", "") <?>-        xpPartial ( \input -> case messageTypeFromText input of-                                   Nothing -> Left "Could not parse message type."-                                   Just j -> Right j)-                  messageTypeToText+        xpIso messageTypeFromText+              messageTypeToText   where-    messageTypeFromText "chat" = Just Chat-    messageTypeFromText "groupchat" = Just GroupChat-    messageTypeFromText "headline" = Just Headline-    messageTypeFromText "normal" = Just Normal-    messageTypeFromText _ = Just Normal+    messageTypeFromText "chat" = Chat+    messageTypeFromText "groupchat" = GroupChat+    messageTypeFromText "headline" = Headline+    messageTypeFromText "normal" = Normal+    messageTypeFromText _ = Normal     messageTypeToText Chat = "chat"     messageTypeToText GroupChat = "groupchat"     messageTypeToText Headline = "headline"@@ -437,10 +459,8 @@  xpStreamErrorCondition :: PU Text StreamErrorCondition xpStreamErrorCondition = ("xpStreamErrorCondition", "") <?>-        xpPartial ( \input -> case streamErrorConditionFromText input of-                                   Nothing -> Left "Could not parse stream error condition."-                                   Just j -> Right j)-                  streamErrorConditionToText+        xpIso streamErrorConditionFromText+              streamErrorConditionToText   where     streamErrorConditionToText StreamBadFormat              = "bad-format"     streamErrorConditionToText StreamBadNamespacePrefix     = "bad-namespace-prefix"@@ -467,29 +487,29 @@     streamErrorConditionToText StreamUnsupportedFeature     = "unsupported-feature"     streamErrorConditionToText StreamUnsupportedStanzaType  = "unsupported-stanza-type"     streamErrorConditionToText StreamUnsupportedVersion     = "unsupported-version"-    streamErrorConditionFromText "bad-format" = Just StreamBadFormat-    streamErrorConditionFromText "bad-namespace-prefix" = Just StreamBadNamespacePrefix-    streamErrorConditionFromText "conflict" = Just StreamConflict-    streamErrorConditionFromText "connection-timeout" = Just StreamConnectionTimeout-    streamErrorConditionFromText "host-gone" = Just StreamHostGone-    streamErrorConditionFromText "host-unknown" = Just StreamHostUnknown-    streamErrorConditionFromText "improper-addressing" = Just StreamImproperAddressing-    streamErrorConditionFromText "internal-server-error" = Just StreamInternalServerError-    streamErrorConditionFromText "invalid-from" = Just StreamInvalidFrom-    streamErrorConditionFromText "invalid-namespace" = Just StreamInvalidNamespace-    streamErrorConditionFromText "invalid-xml" = Just StreamInvalidXml-    streamErrorConditionFromText "not-authorized" = Just StreamNotAuthorized-    streamErrorConditionFromText "not-well-formed" = Just StreamNotWellFormed-    streamErrorConditionFromText "policy-violation" = Just StreamPolicyViolation-    streamErrorConditionFromText "remote-connection-failed" = Just StreamRemoteConnectionFailed-    streamErrorConditionFromText "reset" = Just StreamReset-    streamErrorConditionFromText "resource-constraint" = Just StreamResourceConstraint-    streamErrorConditionFromText "restricted-xml" = Just StreamRestrictedXml-    streamErrorConditionFromText "see-other-host" = Just StreamSeeOtherHost-    streamErrorConditionFromText "system-shutdown" = Just StreamSystemShutdown-    streamErrorConditionFromText "undefined-condition" = Just StreamUndefinedCondition-    streamErrorConditionFromText "unsupported-encoding" = Just StreamUnsupportedEncoding-    streamErrorConditionFromText "unsupported-feature" = Just StreamUnsupportedFeature-    streamErrorConditionFromText "unsupported-stanza-type" = Just StreamUnsupportedStanzaType-    streamErrorConditionFromText "unsupported-version" = Just StreamUnsupportedVersion-    streamErrorConditionFromText _ = Nothing+    streamErrorConditionFromText "bad-format" = StreamBadFormat+    streamErrorConditionFromText "bad-namespace-prefix" = StreamBadNamespacePrefix+    streamErrorConditionFromText "conflict" = StreamConflict+    streamErrorConditionFromText "connection-timeout" = StreamConnectionTimeout+    streamErrorConditionFromText "host-gone" = StreamHostGone+    streamErrorConditionFromText "host-unknown" = StreamHostUnknown+    streamErrorConditionFromText "improper-addressing" = StreamImproperAddressing+    streamErrorConditionFromText "internal-server-error" = StreamInternalServerError+    streamErrorConditionFromText "invalid-from" = StreamInvalidFrom+    streamErrorConditionFromText "invalid-namespace" = StreamInvalidNamespace+    streamErrorConditionFromText "invalid-xml" = StreamInvalidXml+    streamErrorConditionFromText "not-authorized" = StreamNotAuthorized+    streamErrorConditionFromText "not-well-formed" = StreamNotWellFormed+    streamErrorConditionFromText "policy-violation" = StreamPolicyViolation+    streamErrorConditionFromText "remote-connection-failed" = StreamRemoteConnectionFailed+    streamErrorConditionFromText "reset" = StreamReset+    streamErrorConditionFromText "resource-constraint" = StreamResourceConstraint+    streamErrorConditionFromText "restricted-xml" = StreamRestrictedXml+    streamErrorConditionFromText "see-other-host" = StreamSeeOtherHost+    streamErrorConditionFromText "system-shutdown" = StreamSystemShutdown+    streamErrorConditionFromText "undefined-condition" = StreamUndefinedCondition+    streamErrorConditionFromText "unsupported-encoding" = StreamUnsupportedEncoding+    streamErrorConditionFromText "unsupported-feature" = StreamUnsupportedFeature+    streamErrorConditionFromText "unsupported-stanza-type" = StreamUnsupportedStanzaType+    streamErrorConditionFromText "unsupported-version" = StreamUnsupportedVersion+    streamErrorConditionFromText _ = StreamUndefinedCondition -- §4.9.2
source/Network/Xmpp/Sasl/Common.hs view
@@ -1,6 +1,7 @@ {-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE PatternGuards #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleContexts #-}  module Network.Xmpp.Sasl.Common where @@ -86,10 +87,7 @@  xpSaslError :: PU Text.Text SaslError xpSaslError = ("xpSaslError", "") <?>-        xpPartial ( \input -> case saslErrorFromText input of-                                   Nothing -> Left "Could not parse SASL error."-                                   Just j -> Right j)-                  saslErrorToText+        xpIso saslErrorFromText saslErrorToText   where     saslErrorToText SaslAborted              = "aborted"     saslErrorToText SaslAccountDisabled      = "account-disabled"@@ -102,18 +100,18 @@     saslErrorToText SaslMechanismTooWeak     = "mechanism-too-weak"     saslErrorToText SaslNotAuthorized        = "not-authorized"     saslErrorToText SaslTemporaryAuthFailure = "temporary-auth-failure"-    saslErrorFromText "aborted" = Just SaslAborted-    saslErrorFromText "account-disabled" = Just SaslAccountDisabled-    saslErrorFromText "credentials-expired" = Just SaslCredentialsExpired-    saslErrorFromText "encryption-required" = Just SaslEncryptionRequired-    saslErrorFromText "incorrect-encoding" = Just SaslIncorrectEncoding-    saslErrorFromText "invalid-authzid" = Just SaslInvalidAuthzid-    saslErrorFromText "invalid-mechanism" = Just SaslInvalidMechanism-    saslErrorFromText "malformed-request" = Just SaslMalformedRequest-    saslErrorFromText "mechanism-too-weak" = Just SaslMechanismTooWeak-    saslErrorFromText "not-authorized" = Just SaslNotAuthorized-    saslErrorFromText "temporary-auth-failure" = Just SaslTemporaryAuthFailure-    saslErrorFromText _ = Nothing+    saslErrorFromText "aborted" = SaslAborted+    saslErrorFromText "account-disabled" = SaslAccountDisabled+    saslErrorFromText "credentials-expired" = SaslCredentialsExpired+    saslErrorFromText "encryption-required" = SaslEncryptionRequired+    saslErrorFromText "incorrect-encoding" = SaslIncorrectEncoding+    saslErrorFromText "invalid-authzid" = SaslInvalidAuthzid+    saslErrorFromText "invalid-mechanism" = SaslInvalidMechanism+    saslErrorFromText "malformed-request" = SaslMalformedRequest+    saslErrorFromText "mechanism-too-weak" = SaslMechanismTooWeak+    saslErrorFromText "not-authorized" = SaslNotAuthorized+    saslErrorFromText "temporary-auth-failure" = SaslTemporaryAuthFailure+    saslErrorFromText _ = SaslNotAuthorized  -- Challenge element pickler. xpChallenge :: PU [Node] (Maybe Text.Text)@@ -137,10 +135,14 @@ saslInit :: Text.Text -> Maybe BS.ByteString -> ErrorT AuthFailure (StateT StreamState IO) () saslInit mechanism payload = do     r <- lift . pushElement . saslInitE mechanism $-        Text.decodeUtf8 . B64.encode <$> payload+        Text.decodeUtf8 . encodeEmpty . B64.encode <$> payload     case r of         Right () -> return ()         Left e  -> throwError $ AuthStreamFailure e+  where+    -- §6.4.2+    encodeEmpty "" = "="+    encodeEmpty x = x  -- | Pull the next element. pullSaslElement :: ErrorT AuthFailure (StateT StreamState IO) SaslElement
source/Network/Xmpp/Stanza.hs view
@@ -74,8 +74,8 @@ -- error type is derived from the condition using 'associatedErrorType' and -- both text and the application specific condition are left empty iqError :: StanzaErrorCondition -> IQRequest -> IQError-iqError condition (IQRequest iqid from' _to lang' _tp _bd) =-    IQError iqid Nothing from' lang' (mkStanzaError condition) Nothing+iqError condition (IQRequest iqid from' _to lang' _tp _bd _attr) =+    IQError iqid Nothing from' lang' (mkStanzaError condition) Nothing []   -- | Create an IQ Result matching an IQ request@@ -86,6 +86,7 @@               , iqResultTo   = view from iqr               , iqResultLangTag = view lang iqr               , iqResultPayload = pl+              , iqResultAttributes = []               }  -- | The RECOMMENDED error type associated with an error condition. The
source/Network/Xmpp/Stream.hs view
@@ -44,8 +44,10 @@ import           System.Log.Logger import           System.Random (randomRIO) import           Text.XML.Stream.Parse as XP+import           Lens.Family2 (over)  import           Network.Xmpp.Utilities+import qualified Network.Xmpp.Lens as L  -- "readMaybe" definition, as readMaybe is not introduced in the `base' package -- until version 4.6.@@ -133,10 +135,13 @@     response <- ErrorT $ runEventsSink $ streamS expectedTo     case response of       Right (ver, from, to, sid, lt, features)-        | (Text.unpack ver) /= "1.0" ->+        | versionFromText ver == Nothing -> closeStreamWithError+                                            StreamUnsupportedVersion Nothing+                                            "Unspecified version"+        | let v = versionFromText ver+          in isJust v && majorVersion (fromJust v) >= 2 ->             closeStreamWithError StreamUnsupportedVersion Nothing-                "Unknown version"-+              "Non-1.x version"     -- HACK: We ignore MUST-strength requirement (section 4.7.4. of RFC     -- 6120) for the sake of compatibility with jabber.org         --  | lt == Nothing ->@@ -464,7 +469,7 @@         Right (Right r) -> return $ Right r  -- Performs the given IO operation, catches any errors and re-throws everything--- except 'ResourceVanished' and IllegalOperation, in which case it will return False instead+-- except 'ResourceVanished' and IllegalOperation, which it will return. catchPush :: IO () -> IO (Either XmppFailure ()) catchPush p = ExL.catch     (p >> return (Right ()))@@ -533,7 +538,7 @@                   , streamId = Nothing                   , streamLang = Nothing                   , streamJid = Nothing-                  , streamConfiguration = config+                  , streamConfiguration = maybeSetTlsHost realm config                   }             stream' <- mkStream stream             return $ Right stream'@@ -546,12 +551,12 @@         liftIO . debugM "Pontarius.Xmpp" $ "In: " ++ (BSC8.unpack d) ++             "."         return d+    tlsIdentL = L.tlsParamsL . L.clientServerIdentificationL+    updateHost host ("", _) = (host, "")+    updateHost _ hst = hst+    maybeSetTlsHost host = over tlsIdentL (updateHost host) --- Connects to the provided hostname or IP address. If a hostname is provided, a--- DNS-SRV lookup is performed (unless `sockAddr' has been specified, in which--- case that address is used instead). If an A(AAA) record results are--- encountered, all IP addresses will be tried until a successful connection--- attempt has been made. Will return the Handle acquired, if any.+-- Connects using the specified method. Returns the Handle acquired, if any. connect :: HostName -> StreamConfiguration -> ErrorT XmppFailure IO            (Maybe StreamHandle) connect realm config = do@@ -593,6 +598,10 @@                         "No SRV records, using fallback process."                     lift $ resolvAndConnectTcp resolvSeed (BSC8.pack $ host)                                                5222+                Just [(".", _)] -> do+                    liftIO $ infoM "Pontarius.Xmpp"+                                "SRV lookup returned \".\"; service not available"+                    throwError TcpConnectionFailure                 Just srvRecords' -> do                     lift $ debugM "Pontarius.Xmpp"                         "SRV records found, performing A/AAAA lookups."@@ -624,10 +633,11 @@         connectTo address port) :: IO (Either Ex.IOException Handle)     case result of         Right handle -> do-            debugM "Pontarius.Xmpp" "Successfully connected to HostName."+            debugM "Pontarius.Xmpp" $ "Successfully connected to " ++ show address             return $ Just handle         Left _ -> do-            debugM "Pontarius.Xmpp" "Connection to HostName could not be established."+            debugM "Pontarius.Xmpp" $+                "Connection to " ++ show address ++ " could not be established."             connectTcp remainder  #if MIN_VERSION_dns(1, 0, 0)@@ -775,7 +785,7 @@        -> IO (Either XmppFailure (Either IQError IQResult)) pushIQ iqID to tp lang body stream = runErrorT $ do     ErrorT $ pushStanza-        (IQRequestS $ IQRequest iqID Nothing to lang tp body) stream+        (IQRequestS $ IQRequest iqID Nothing to lang tp body []) stream     res <- lift $ pullStanza stream     case res of         Left e -> throwError e
source/Network/Xmpp/Tls.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PackageImports #-}+{-# LANGUAGE FlexibleContexts #-}  module Network.Xmpp.Tls where @@ -16,12 +17,14 @@ import qualified       Data.ByteString.Lazy as BL import                 Data.Conduit import                 Data.IORef+import                 Data.Monoid import                 Data.XML.Types import                 Network.DNS.Resolver (ResolvConf) import                 Network.TLS import                 Network.Xmpp.Stream import                 Network.Xmpp.Types import                 System.Log.Logger (debugM, errorM, infoM)+import                 System.X509  mkBackend :: StreamHandle -> Backend mkBackend con = Backend { backendSend = \bs -> void (streamSend con bs)@@ -54,7 +57,7 @@           . wrapExceptions           . flip withStream con           . runErrorT $ do-    conf <- gets $ streamConfiguration+    conf <- gets streamConfiguration     sState <- gets streamConnectionState     case sState of         Plain -> return ()@@ -123,7 +126,11 @@ tlsinit params backend = do     liftIO $ debugM "Pontarius.Xmpp.Tls" "TLS with debug mode enabled."     gen <- liftIO (cprgCreate <$> createEntropyPool :: IO SystemRNG)-    con <- client params gen backend+    sysCStore <- liftIO getSystemCertificateStore+    let params' = params{clientShared =+                      (clientShared params){ sharedCAStore =+                          sysCStore <> sharedCAStore (clientShared params)}}+    con <- client params' gen backend     handshake con     let src = forever $ do             dt <- liftIO $ recvData con@@ -173,20 +180,23 @@         Nothing -> throwError TcpConnectionFailure         Just h'' -> return h''     let hand = handleToStreamHandle h-    (_raw, _snk, psh, recv, ctx) <- tlsinit params $ mkBackend hand-    return $ StreamHandle { streamSend = catchPush . psh-                          , streamReceive = wrapExceptions . recv-                          , streamFlush = contextFlush ctx-                          , streamClose = bye ctx >> streamClose hand-                          }+    let params' = params{clientServerIdentification+                   = case clientServerIdentification params of+                       ("", _) -> (host, "")+                       csi -> csi+                       }+    (_raw, _snk, psh, recv, ctx) <- tlsinit params' $ mkBackend hand+    return StreamHandle{ streamSend = catchPush . psh+                       , streamReceive = wrapExceptions . recv+                       , streamFlush = contextFlush ctx+                       , streamClose = bye ctx >> streamClose hand+                       }  wrapExceptions :: IO a -> IO (Either XmppFailure a) wrapExceptions f = Ex.catches (liftM Right $ f)                  [ Ex.Handler $ return . Left . XmppIOException                  , Ex.Handler $ wrap . XmppTlsError-                 , Ex.Handler $ wrap . XmppTlsConnectionNotEstablished-                 , Ex.Handler $ wrap . XmppTlsTerminated-                 , Ex.Handler $ wrap . XmppTlsHandshakeFailed+                 , Ex.Handler $ wrap . XmppTlsException                  , Ex.Handler $ return . Left                  ]   where
source/Network/Xmpp/Types.hs view
@@ -22,12 +22,15 @@     , IQResponse(..)     , IQResult(..)     , LangTag (..)+    , langTagQ     , langTagFromText     , langTagToText     , parseLangTag+    , ExtendedAttribute     , Message(..)     , message     , MessageError(..)+    , messageError     , MessageType(..)     , Presence(..)     , presence@@ -37,6 +40,9 @@     , SaslFailure(..)     , StreamFeatures(..)     , Stanza(..)+    , messageS+    , messageErrorS+    , presenceS     , StanzaError(..)     , StanzaErrorCondition(..)     , StanzaErrorType(..)@@ -44,6 +50,7 @@     , XmppTlsError(..)     , StreamErrorCondition(..)     , Version(..)+    , versionFromText     , StreamHandle(..)     , Stream(..)     , StreamState(..)@@ -52,6 +59,7 @@     , ConnectionDetails(..)     , StreamConfiguration(..)     , xmppDefaultParams+    , xmppDefaultParamsStrong     , Jid(..) #if WITH_TEMPLATE_HASKELL     , jidQ@@ -89,7 +97,8 @@ import           Data.Text (Text) import qualified Data.Text as Text import           Data.Typeable(Typeable)-import           Data.XML.Types+import           Data.XML.Types as XML+import qualified Data.Text.Encoding as Text #if WITH_TEMPLATE_HASKELL import           Language.Haskell.TH import           Language.Haskell.TH.Quote@@ -138,6 +147,8 @@             | PresenceErrorS !PresenceError               deriving (Eq, Show) +type ExtendedAttribute = (XML.Name, Text)+ -- | A "request" Info/Query (IQ) stanza is one with either "get" or "set" as -- type. It always contains an xml payload. data IQRequest = IQRequest { iqRequestID      :: !Text@@ -146,6 +157,7 @@                            , iqRequestLangTag :: !(Maybe LangTag)                            , iqRequestType    :: !IQRequestType                            , iqRequestPayload :: !Element+                           , iqRequestAttributes :: ![ExtendedAttribute]                            } deriving (Eq, Show)  -- | The type of IQ request that is made.@@ -163,6 +175,7 @@                          , iqResultTo      :: !(Maybe Jid)                          , iqResultLangTag :: !(Maybe LangTag)                          , iqResultPayload :: !(Maybe Element)+                         , iqResultAttributes :: ![ExtendedAttribute]                          } deriving (Eq, Show)  -- | The answer to an IQ request that generated an error.@@ -172,6 +185,7 @@                        , iqErrorLangTag     :: !(Maybe LangTag)                        , iqErrorStanzaError :: !StanzaError                        , iqErrorPayload     :: !(Maybe Element) -- should this be []?+                       , iqErrorAttributes  :: ![ExtendedAttribute]                        } deriving (Eq, Show)  -- | The message stanza. Used for /push/ type communication.@@ -181,6 +195,7 @@                        , messageLangTag :: !(Maybe LangTag)                        , messageType    :: !MessageType                        , messagePayload :: ![Element]+                       , messageAttributes :: ![ExtendedAttribute]                        } deriving (Eq, Show)  -- | An empty message@@ -201,6 +216,7 @@                   , messageLangTag = Nothing                   , messageType    = Normal                   , messagePayload = []+                  , messageAttributes = []                   }  -- | Empty message stanza@@ -219,9 +235,31 @@                                  , messageErrorLangTag     :: !(Maybe LangTag)                                  , messageErrorStanzaError :: !StanzaError                                  , messageErrorPayload     :: ![Element]+                                 , messageErrorAttributes  :: ![ExtendedAttribute]                                  } deriving (Eq, Show) +messageError :: MessageError+messageError = MessageError { messageErrorID          = Nothing+                            , messageErrorFrom        = Nothing+                            , messageErrorTo          = Nothing+                            , messageErrorLangTag     = Nothing+                            , messageErrorStanzaError =+                                StanzaError { stanzaErrorType = Cancel+                                            , stanzaErrorCondition =+                                                  ServiceUnavailable+                                            , stanzaErrorText = Nothing+                                            , stanzaErrorApplicationSpecificCondition = Nothing+                                            }+                            , messageErrorPayload     = []+                            , messageErrorAttributes  = []+                            } +instance Default MessageError where+    def = messageError++messageErrorS :: Stanza+messageErrorS = MessageErrorS def+ -- | The type of a Message being sent -- (<http://xmpp.org/rfcs/rfc6121.html#message-syntax-type>) data MessageType = -- | The message is sent in the context of a one-to-one chat@@ -266,6 +304,7 @@                          , presenceLangTag :: !(Maybe LangTag)                          , presenceType    :: !PresenceType                          , presencePayload :: ![Element]+                         , presenceAttributes :: ![ExtendedAttribute]                          } deriving (Eq, Show)  -- | An empty presence.@@ -276,6 +315,7 @@                     , presenceLangTag  = Nothing                     , presenceType     = Available                     , presencePayload  = []+                    , presenceAttributes = []                     }  -- | Empty presence stanza@@ -292,6 +332,7 @@                                    , presenceErrorLangTag     :: !(Maybe LangTag)                                    , presenceErrorStanzaError :: !StanzaError                                    , presenceErrorPayload     :: ![Element]+                                   , presenceErrorAttributes  :: ![ExtendedAttribute]                                    } deriving (Eq, Show)  -- | @PresenceType@ holds Xmpp presence types. The "error" message type is left@@ -532,9 +573,7 @@     } deriving (Show, Eq)  data XmppTlsError = XmppTlsError TLSError-                  | XmppTlsConnectionNotEstablished TLSException-                  | XmppTlsTerminated TLSException-                  | XmppTlsHandshakeFailed TLSException+                  | XmppTlsException TLSException                     deriving (Show, Eq, Typeable)  -- | Signals an XMPP stream error or another unpredicted stream-related@@ -692,10 +731,10 @@  -- | Signals the state of the stream connection. data ConnectionState-    = Closed  -- ^ No stream has been established+    = Closed  -- ^ Stream has not been established yet     | Plain   -- ^ Stream established, but not secured via TLS     | Secured -- ^ Stream established and secured via TLS-    | Finished -- ^ Stream is closed+    | Finished -- ^ Stream was closed       deriving (Show, Eq, Typeable)  -- | Defines operations for sending, receiving, flushing, and closing on a@@ -1009,8 +1048,9 @@             guard $ Text.all (`Set.notMember` prohibMap) l''             l''' <- nonEmpty l''             return $ Just l'''-    domainPart' <- SP.runStringPrep (SP.namePrepProfile False) d+    domainPart' <- SP.runStringPrep (SP.namePrepProfile False) (stripSuffix d)     guard $ validDomainPart domainPart'+    guard $ validPartLength domainPart'     domainPart <- nonEmpty domainPart'     resourcePart <- case r of         Nothing -> return Nothing@@ -1026,7 +1066,10 @@                                           -- checks      validPartLength :: Text -> Bool-    validPartLength p = Text.length p > 0 && Text.length p < 1024+    validPartLength p = Text.length p > 0+                        && BS.length (Text.encodeUtf8 p) < 1024+    -- RFC6122 §2.2+    stripSuffix t = if Text.last t == '.' then Text.init t else t  -- | Returns 'True' if the JID is /bare/, that is, it doesn't have a resource -- part, and 'False' otherwise.@@ -1149,11 +1192,14 @@                        | UseSrv HostName -- ^ Use this hostname for a SRV lookup                        | UseHost HostName PortID -- ^ Use specified host                        | UseConnection (ErrorT XmppFailure IO StreamHandle)-                         -- ^ Use custom method to create a StreamHandle. This+                         -- ^ Use a custom method to create a StreamHandle. This                          -- will also be used by reconnect. For example, to                          -- establish TLS before starting the stream as done by                          -- GCM, see 'connectTls'. You can also return an-                         -- already established connection.+                         -- already established connection. This method should+                         -- also return a hostname that is used for TLS+                         -- signature verification. If startTLS is not used it+                         -- can be left empty  -- | Configuration settings related to the stream. data StreamConfiguration =@@ -1182,9 +1228,9 @@                         , tlsParams :: ClientParams                         } --- | Default parameters for TLS. Those are the default client parameters from the tls package with the ciphers set to ciphersuite_strong-xmppDefaultParams :: ClientParams-xmppDefaultParams = (defaultParamsClient "" BS.empty)+-- | Default parameters for TLS restricted to strong ciphers+xmppDefaultParamsStrong :: ClientParams+xmppDefaultParamsStrong = (defaultParamsClient "" BS.empty)                         { clientSupported = def                             { supportedCiphers = ciphersuite_strong                                                  ++ [ cipher_AES256_SHA1@@ -1192,6 +1238,15 @@                                                     ]                             }                         }++-- | Default parameters for TLS+xmppDefaultParams :: ClientParams+xmppDefaultParams = (defaultParamsClient "" BS.empty)+                        { clientSupported = def+                            { supportedCiphers = ciphersuite_all+                            }+                        }+  instance Default StreamConfiguration where     def = StreamConfiguration { preferredLang     = Nothing
+ tests/Run.hs view
@@ -0,0 +1,14 @@+module Main where++import Test.Tasty.HUnit+import Test.Tasty++import qualified Run.SendReceive as SendReceive+import qualified Run.Google as Google++sendReceiveTest = testCase "send and receive" SendReceive.run+googleTest = testCase "connect to google service" Google.connectGoogle++main = defaultMain $ testGroup "connection tests" [ sendReceiveTest+                                                  , googleTest+                                                  ]
+ tests/Run/Payload.hs view
@@ -0,0 +1,117 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE LambdaCase #-}+++module Run.Payload where++import           Control.Monad+import           Control.Monad.STM+import qualified Data.Text as Text+import           Data.XML.Pickle+import           Data.XML.Types+import           Network.Xmpp+import           Network.Xmpp.Internal+import           System.Log.Logger+import           Test.HUnit hiding (Node)+import           Test.Hspec.Expectations++data Payload = Payload+               { payloadCounter :: !Int+               , ignoreFlag     :: !Bool+               , errorFlag      :: !Bool+               , payloadText    :: !Text.Text+               } deriving (Eq, Show)++testNS :: Text.Text+testNS = "xmpp:library:test"++payloadP :: PU [Node] Payload+payloadP = xpWrap (\((counter,iFlag, eFlag) , message)+                      -> Payload counter iFlag eFlag message)+                  (\(Payload counter iFlag eFlag message)+                      ->((counter,iFlag, eFlag) , message)) $+                   xpElem (Name "request" (Just testNS) Nothing)+                      (xp3Tuple+                        (xpAttr "counter" xpPrim)+                        (xpAttr "ignoreFlag" xpPrim)+                        (xpAttr "errorFlag" xpPrim)+                      )+                      (xpElemNodes (Name "message" (Just testNS) Nothing)+                          (xpContent xpId))++invertPayload :: Payload -> Payload+invertPayload (Payload count _iFlag _eFlag message) =+    Payload (count + 1) False False (Text.reverse message)++iqResponder :: Session -> IO ()+iqResponder context = do+    chan' <- listenIQ Set testNS context+    chan <- case chan' of+        Left _ -> do+            assertFailure "Channel was already taken"+            undefined+        Right c -> return c+    forever $ do+        next <- atomically $ chan+        let Right payload = unpickleElem payloadP . iqRequestPayload $+                              iqRequestBody next+        let answerPayload = invertPayload payload+        let answerBody = pickleElem payloadP answerPayload+        unless (ignoreFlag payload) . void $+            case errorFlag payload of+                False -> answerIQ next (Right $ Just answerBody) []+                True -> answerIQ next (Left $ mkStanzaError NotAcceptable) []++testString :: Text.Text+testString = "abc ÄÖ>"++testPayload :: Jid -> Session -> IO ()+testPayload them session = do+    infoM "Pontarius.Xmpp" "Testing IQ send/receive"+    let pl1 = Payload 1 False False testString+        body1 = pickleElem payloadP pl1+    resp <- sendIQ' (Just 3000000) (Just them) Set Nothing body1 [] session++    case resp of+        Left e -> assertFailure $ "Could not send pl1" ++ show e+        Right (IQResponseError e) ->+            assertFailure $ "Unexpected IQ error" ++ show e+        Right (IQResponseResult IQResult{iqResultPayload = Just pl}) -> do+            case unpickleElem payloadP pl of+                Left e -> assertFailure $ "Error unpickling response p1"+                                           ++ ppUnpickleError e+                Right r -> do+                    payloadCounter r `shouldBe` 2+                    payloadText r `shouldBe` Text.reverse testString+        Right (IQResponseResult _) ->+            assertFailure "IQ result didn't contain payload"+    infoM "Pontarius.Xmpp" "Done testing IQ send/receive"+    ----------------------+    -- Timeout test+    ----------------------+    let pl2 = Payload 2 True False testString+        body2 = pickleElem payloadP pl2+    infoM "Pontarius.Xmpp" "Testing timeout"+    resp <- sendIQ' (Just 1000000) (Just them) Set Nothing body2 [] session+    case resp of+        Left IQTimeOut -> return ()+        Left e -> assertFailure $ "Unexpected send error" ++ show e+        Right r -> assertFailure $ "Unexpected IQ answer" ++ show r+    infoM "Pontarius.Xmpp" "IQ timed out (as expected)"+    ----------------------+    -- Error test+    ----------------------+    infoM "Pontarius.Xmpp" "Testing IQ error"+    let pl3 = Payload 3 False True testString+        body3 = pickleElem payloadP pl3+    resp <- sendIQ' (Just 3000000) (Just them) Set Nothing body3 [] session+    case resp of+        Left e -> assertFailure $ "Unexpected send error" ++ show e+        Right (IQResponseError e) ->+             stanzaErrorCondition (iqErrorStanzaError e) `shouldBe` NotAcceptable++        Right r -> assertFailure $ "Received unexpected IQ response" ++ show r+    infoM "Pontarius.Xmpp" "Received expected error"
tests/Tests/Arbitrary/Xmpp.hs view
@@ -5,7 +5,7 @@ import           Data.Char import           Data.Maybe import qualified Data.Text as Text-import           Network.Xmpp.Types+import           Network.Xmpp.Internal hiding (elements) import           Test.QuickCheck import           Test.QuickCheck.Instances() import qualified Text.CharRanges as Ranges