1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
|
-- Copyright (C) 2009-2012 John Millikin <john@john-millikin.com>
--
-- 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 <http://www.gnu.org/licenses/>.
module DBus.Internal.Message
( Message(..)
, UnknownMessage(..)
, MethodCall(..)
, MethodReturn(..)
, MethodError(..)
, methodErrorMessage
, Signal(..)
, ReceivedMessage(..)
-- for use in Wire
, HeaderField(..)
, setMethodCallFlags
) where
import Data.Bits ((.|.), (.&.))
import Data.Maybe (fromMaybe, listToMaybe)
import Data.Word (Word8, Word32)
import DBus.Internal.Types
class Message a where
messageTypeCode :: a -> Word8
messageHeaderFields :: a -> [HeaderField]
messageBody :: a -> [Variant]
messageFlags :: a -> Word8
messageFlags _ = 0
maybe' :: (a -> b) -> Maybe a -> [b]
maybe' f = maybe [] (\x' -> [f x'])
data UnknownMessage = UnknownMessage
{ unknownMessageType :: Word8
, unknownMessageSender :: Maybe BusName
, unknownMessageBody :: [Variant]
}
deriving (Show, Eq)
data HeaderField
= HeaderPath ObjectPath
| HeaderInterface InterfaceName
| HeaderMember MemberName
| HeaderErrorName ErrorName
| HeaderReplySerial Serial
| HeaderDestination BusName
| HeaderSender BusName
| HeaderSignature Signature
| HeaderUnixFds Word32
deriving (Show, Eq)
-- | A method call is a request to run some procedure exported by the
-- remote process. Procedures are identified by an (object_path,
-- interface_name, method_name) tuple.
data MethodCall = MethodCall
{
-- | The object path of the method call. Conceptually, object paths
-- act like a procedural language's pointers. Each object referenced
-- by a path is a collection of procedures.
methodCallPath :: ObjectPath
-- | The interface of the method call. Each object may implement any
-- number of interfaces. Each method is part of at least one
-- interface.
--
-- In certain cases, this may be @Nothing@, but most users should set
-- it to a value.
, methodCallInterface :: Maybe InterfaceName
-- | The method name of the method call. Method names are unique within
-- an interface, but might not be unique within an object.
, methodCallMember :: MemberName
-- | The name of the application that sent this call.
--
-- Most users will just leave this empty, because the bus overwrites
-- the sender for security reasons. Setting the sender manually is
-- used for peer-peer connections.
--
-- Defaults to @Nothing@.
, methodCallSender :: Maybe BusName
-- | The name of the application to send the call to.
--
-- Most users should set this. If a message with no destination is
-- sent to the bus, the bus will behave as if the destination was
-- set to @org.freedesktop.DBus@. For peer-peer connections, the
-- destination can be empty because there is only one peer.
--
-- Defaults to @Nothing@.
, methodCallDestination :: Maybe BusName
-- | Set whether a reply is expected. This can save network and cpu
-- resources by inhibiting unnecessary replies.
--
-- Defaults to @True@.
, methodCallReplyExpected :: Bool
-- | Set whether the bus should auto-start the remote
--
-- Defaults to @True@.
, methodCallAutoStart :: Bool
-- | The arguments to the method call. See 'toVariant'.
--
-- Defaults to @[]@.
, methodCallBody :: [Variant]
}
deriving (Eq, Show)
setMethodCallFlags :: MethodCall -> Word8 -> MethodCall
setMethodCallFlags c w = c
{ methodCallReplyExpected = w .&. 0x1 == 0
, methodCallAutoStart = w .&. 0x2 == 0
}
instance Message MethodCall where
messageTypeCode _ = 1
messageFlags c = foldr (.|.) 0
[ if methodCallReplyExpected c then 0 else 0x1
, if methodCallAutoStart c then 0 else 0x2
]
messageBody = methodCallBody
messageHeaderFields m = concat
[ [ HeaderPath (methodCallPath m)
, HeaderMember (methodCallMember m)
]
, maybe' HeaderInterface (methodCallInterface m)
, maybe' HeaderSender (methodCallSender m)
, maybe' HeaderDestination (methodCallDestination m)
]
-- | A method return is a reply to a method call, indicating that the call
-- succeeded.
data MethodReturn = MethodReturn
{
-- | The serial of the original method call. This lets the original
-- caller match up this reply to the pending call.
methodReturnSerial :: Serial
-- | The name of the application that is returning from a call.
--
-- Most users will just leave this empty, because the bus overwrites
-- the sender for security reasons. Setting the sender manually is
-- used for peer-peer connections.
--
-- Defaults to @Nothing@.
, methodReturnSender :: Maybe BusName
-- | The name of the application that initiated the call.
--
-- Most users should set this. If a message with no destination is
-- sent to the bus, the bus will behave as if the destination was
-- set to @org.freedesktop.DBus@. For peer-peer connections, the
-- destination can be empty because there is only one peer.
--
-- Defaults to @Nothing@.
, methodReturnDestination :: Maybe BusName
-- | Values returned from the method call. See 'toVariant'.
--
-- Defaults to @[]@.
, methodReturnBody :: [Variant]
}
deriving (Show, Eq)
instance Message MethodReturn where
messageTypeCode _ = 2
messageBody = methodReturnBody
messageHeaderFields m = concat
[ [ HeaderReplySerial (methodReturnSerial m)
]
, maybe' HeaderSender (methodReturnSender m)
, maybe' HeaderDestination (methodReturnDestination m)
]
-- | A method error is a reply to a method call, indicating that the call
-- received an error and did not succeed.
data MethodError = MethodError
{
-- | The name of the error type. Names are used so clients can
-- handle certain classes of error differently from others.
methodErrorName :: ErrorName
-- | The serial of the original method call. This lets the original
-- caller match up this reply to the pending call.
, methodErrorSerial :: Serial
-- | The name of the application that is returning from a call.
--
-- Most users will just leave this empty, because the bus overwrites
-- the sender for security reasons. Setting the sender manually is
-- used for peer-peer connections.
--
-- Defaults to @Nothing@.
, methodErrorSender :: Maybe BusName
-- | The name of the application that initiated the call.
--
-- Most users should set this. If a message with no destination is
-- sent to the bus, the bus will behave as if the destination was
-- set to @org.freedesktop.DBus@. For peer-peer connections, the
-- destination can be empty because there is only one peer.
--
-- Defaults to @Nothing@.
, methodErrorDestination :: Maybe BusName
-- | Additional information about the error. By convention, if
-- the error body contains any items, the first item should be a
-- string describing the error.
, methodErrorBody :: [Variant]
}
deriving (Show, Eq)
instance Message MethodError where
messageTypeCode _ = 3
messageBody = methodErrorBody
messageHeaderFields m = concat
[ [ HeaderErrorName (methodErrorName m)
, HeaderReplySerial (methodErrorSerial m)
]
, maybe' HeaderSender (methodErrorSender m)
, maybe' HeaderDestination (methodErrorDestination m)
]
-- | Get a human-readable description of the error, by returning the first
-- item in the error body if it's a string.
methodErrorMessage :: MethodError -> String
methodErrorMessage err = fromMaybe "(no error message)" $ do
field <- listToMaybe (methodErrorBody err)
msg <- fromVariant field
if null msg
then Nothing
else return msg
-- | Signals are broadcast by applications to notify other clients of some
-- event.
data Signal = Signal
{
-- | The path of the object that emitted this signal.
signalPath :: ObjectPath
-- | The interface that this signal belongs to.
, signalInterface :: InterfaceName
-- | The name of this signal.
, signalMember :: MemberName
-- | The name of the application that emitted this signal.
--
-- Most users will just leave this empty, because the bus overwrites
-- the sender for security reasons. Setting the sender manually is
-- used for peer-peer connections.
--
-- Defaults to @Nothing@.
, signalSender :: Maybe BusName
-- | The name of the application to emit the signal to. If @Nothing@,
-- the signal is sent to any application that has registered an
-- appropriate match rule.
--
-- Defaults to @Nothing@.
, signalDestination :: Maybe BusName
-- | Additional information about the signal, such as the new value
-- or the time.
--
-- Defaults to @[]@.
, signalBody :: [Variant]
}
deriving (Show, Eq)
instance Message Signal where
messageTypeCode _ = 4
messageBody = signalBody
messageHeaderFields m = concat
[ [ HeaderPath (signalPath m)
, HeaderMember (signalMember m)
, HeaderInterface (signalInterface m)
]
, maybe' HeaderSender (signalSender m)
, maybe' HeaderDestination (signalDestination m)
]
-- | Not an actual message type, but a wrapper around messages received from
-- the bus. Each value contains the message's 'Serial'.
--
-- If casing against these constructors, always include a default case to
-- handle messages of an unknown type. New message types may be added to the
-- D-Bus specification, and applications should handle them gracefully by
-- either ignoring or logging them.
data ReceivedMessage
= ReceivedMethodCall Serial MethodCall
| ReceivedMethodReturn Serial MethodReturn
| ReceivedMethodError Serial MethodError
| ReceivedSignal Serial Signal
| ReceivedUnknown Serial UnknownMessage
deriving (Show, Eq)
|