:# Copyright (C) 2009-2010 John Millikin :# :# This program is free software: you can redistribute it and/or modify :# it under the terms of the GNU General Public License as published by :# the Free Software Foundation, either version 3 of the License, or :# any later version. :# :# This program is distributed in the hope that it will be useful, :# but WITHOUT ANY WARRANTY; without even the implied warranty of :# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the :# GNU General Public License for more details. :# :# You should have received a copy of the GNU General Public License :# along with this program. If not, see . \section{Messages} :d DBus.Message class Message a where messageTypeCode :: a -> Word8 messageHeaderFields :: a -> [HeaderField] messageFlags :: a -> Set Flag messageBody :: a -> [Variant] : :d DBus.Message maybe' :: (a -> b) -> Maybe a -> [b] maybe' f = maybe [] (\x' -> [f x']) : \subsection{Unknown messages} Unknown messages are used for storing information about messages without a recognised type code. They are not instances of {\tt Message}, because if they were, then clients could accidentally send invalid messages over the bus. :d DBus.Message data Unknown = Unknown { unknownType :: Word8 , unknownFlags :: Set Flag , unknownBody :: [Variant] } deriving (Show, Eq) : \clearpage \subsection{Header fields} \begin{multicols}{2} TODO \vfill \columnbreak :d DBus.Message data HeaderField = HeaderPath ObjectPath | HeaderInterface InterfaceName | HeaderMember MemberName | HeaderErrorName ErrorName | HeaderReplySerial Serial | HeaderDestination BusName | HeaderSender BusName | HeaderSignature Signature deriving (Show, Eq) : \end{multicols} \subsubsection{Flags} \begin{multicols}{2} The instance of {\tt Ord} only exists for storing flags in a set. Flags have no inherent ordering. \vfill \columnbreak :d DBus.Message data Flag = NoReplyExpected | NoAutoStart deriving (Show, Eq, Ord) : \end{multicols} \subsubsection{Serials} \begin{multicols}{2} {\tt Serial} is just a wrapper around {\tt Word32}, to provide a bit of added type-safety. \vfill \columnbreak :d DBus.Message |apidoc DBus.Message.Serial| newtype Serial = Serial Word32 deriving (Eq, Ord, Show) instance IsVariant Serial where toVariant (Serial x) = toVariant x fromVariant = fmap Serial . fromVariant : \end{multicols} \begin{multicols}{2} Additionally, some useful functions exist for incrementing serials. \vfill \columnbreak :d DBus.Message serialValue :: Serial -> Word32 serialValue (Serial x) = x : \end{multicols} \begin{multicols}{2} The {\tt Serial} constructor isn't useful to clients, because building arbitrary serials doesn't make any sense. \vfill \columnbreak \end{multicols} \clearpage \subsection{Message types} \subsubsection{Method calls} :d DBus.Message data MethodCall = MethodCall { methodCallPath :: ObjectPath , methodCallMember :: MemberName , methodCallInterface :: Maybe InterfaceName , methodCallDestination :: Maybe BusName , methodCallFlags :: Set Flag , methodCallBody :: [Variant] } deriving (Show, Eq) instance Message MethodCall where messageTypeCode _ = 1 messageFlags = methodCallFlags messageBody = methodCallBody messageHeaderFields m = concat [ [ HeaderPath (methodCallPath m) , HeaderMember (methodCallMember m) ] , maybe' HeaderInterface (methodCallInterface m) , maybe' HeaderDestination (methodCallDestination m) ] : \clearpage \subsubsection{Method returns} :d DBus.Message data MethodReturn = MethodReturn { methodReturnSerial :: Serial , methodReturnDestination :: Maybe BusName , methodReturnBody :: [Variant] } deriving (Show, Eq) instance Message MethodReturn where messageTypeCode _ = 2 messageFlags _ = Data.Set.fromList [NoReplyExpected, NoAutoStart] messageBody = methodReturnBody messageHeaderFields m = concat [ [ HeaderReplySerial (methodReturnSerial m) ] , maybe' HeaderDestination (methodReturnDestination m) ] : \clearpage \subsubsection{Errors} :d DBus.Message data Error = Error { errorName :: ErrorName , errorSerial :: Serial , errorDestination :: Maybe BusName , errorBody :: [Variant] } deriving (Show, Eq) instance Message Error where messageTypeCode _ = 3 messageFlags _ = Data.Set.fromList [NoReplyExpected, NoAutoStart] messageBody = errorBody messageHeaderFields m = concat [ [ HeaderErrorName (errorName m) , HeaderReplySerial (errorSerial m) ] , maybe' HeaderDestination (errorDestination m) ] : Errors usually contain a human-readable message in their first body field. This function lets it be retrieved easily, with a fallback if no valid message was found. :d DBus.Message errorMessage :: Error -> Text errorMessage msg = fromMaybe "(no error message)" $ do field <- maybeIndex (errorBody msg) 0 text <- fromVariant field if Data.Text.null text then Nothing else return text : \clearpage \subsubsection{Signals} :d DBus.Message data Signal = Signal { signalDestination :: Maybe BusName , signalPath :: ObjectPath , signalInterface :: InterfaceName , signalMember :: MemberName , signalBody :: [Variant] } deriving (Show, Eq) instance Message Signal where messageTypeCode _ = 4 messageFlags _ = Data.Set.fromList [NoReplyExpected, NoAutoStart] messageBody = signalBody messageHeaderFields m = concat [ [ HeaderPath (signalPath m) , HeaderMember (signalMember m) , HeaderInterface (signalInterface m) ] , maybe' HeaderDestination (signalDestination m) ] : \clearpage \subsection{Received messages} Messages received from a bus have additional fields which do not make sense when sending. If a message has an unknown type, its serial and origin are still useful for sending an error reply. :d DBus.Message |apidoc DBus.Message.ReceivedMessage| data ReceivedMessage = ReceivedMethodCall Serial (Maybe BusName) MethodCall | ReceivedMethodReturn Serial (Maybe BusName) MethodReturn | ReceivedError Serial (Maybe BusName) Error | ReceivedSignal Serial (Maybe BusName) Signal | ReceivedUnknown Serial (Maybe BusName) Unknown deriving (Show, Eq) : :d DBus.Message receivedSerial :: ReceivedMessage -> Serial receivedSerial (ReceivedMethodCall s _ _) = s receivedSerial (ReceivedMethodReturn s _ _) = s receivedSerial (ReceivedError s _ _) = s receivedSerial (ReceivedSignal s _ _) = s receivedSerial (ReceivedUnknown s _ _) = s : :d DBus.Message receivedSender :: ReceivedMessage -> Maybe BusName receivedSender (ReceivedMethodCall _ s _) = s receivedSender (ReceivedMethodReturn _ s _) = s receivedSender (ReceivedError _ s _) = s receivedSender (ReceivedSignal _ s _) = s receivedSender (ReceivedUnknown _ s _) = s : :d DBus.Message receivedBody :: ReceivedMessage -> [Variant] receivedBody (ReceivedMethodCall _ _ x) = messageBody x receivedBody (ReceivedMethodReturn _ _ x) = messageBody x receivedBody (ReceivedError _ _ x) = messageBody x receivedBody (ReceivedSignal _ _ x) = messageBody x receivedBody (ReceivedUnknown _ _ x) = unknownBody x :