go-tg-screenshot-bot
390 строк · 9.7 Кб
1package dbus
2
3import (
4"bytes"
5"encoding/binary"
6"errors"
7"io"
8"reflect"
9"strconv"
10)
11
12const protoVersion byte = 1
13
14// Flags represents the possible flags of a D-Bus message.
15type Flags byte
16
17const (
18// FlagNoReplyExpected signals that the message is not expected to generate
19// a reply. If this flag is set on outgoing messages, any possible reply
20// will be discarded.
21FlagNoReplyExpected Flags = 1 << iota
22// FlagNoAutoStart signals that the message bus should not automatically
23// start an application when handling this message.
24FlagNoAutoStart
25// FlagAllowInteractiveAuthorization may be set on a method call
26// message to inform the receiving side that the caller is prepared
27// to wait for interactive authorization, which might take a
28// considerable time to complete. For instance, if this flag is set,
29// it would be appropriate to query the user for passwords or
30// confirmation via Polkit or a similar framework.
31FlagAllowInteractiveAuthorization
32)
33
34// Type represents the possible types of a D-Bus message.
35type Type byte
36
37const (
38TypeMethodCall Type = 1 + iota
39TypeMethodReply
40TypeError
41TypeSignal
42typeMax
43)
44
45func (t Type) String() string {
46switch t {
47case TypeMethodCall:
48return "method call"
49case TypeMethodReply:
50return "reply"
51case TypeError:
52return "error"
53case TypeSignal:
54return "signal"
55}
56return "invalid"
57}
58
59// HeaderField represents the possible byte codes for the headers
60// of a D-Bus message.
61type HeaderField byte
62
63const (
64FieldPath HeaderField = 1 + iota
65FieldInterface
66FieldMember
67FieldErrorName
68FieldReplySerial
69FieldDestination
70FieldSender
71FieldSignature
72FieldUnixFDs
73fieldMax
74)
75
76// An InvalidMessageError describes the reason why a D-Bus message is regarded as
77// invalid.
78type InvalidMessageError string
79
80func (e InvalidMessageError) Error() string {
81return "dbus: invalid message: " + string(e)
82}
83
84// fieldType are the types of the various header fields.
85var fieldTypes = [fieldMax]reflect.Type{
86FieldPath: objectPathType,
87FieldInterface: stringType,
88FieldMember: stringType,
89FieldErrorName: stringType,
90FieldReplySerial: uint32Type,
91FieldDestination: stringType,
92FieldSender: stringType,
93FieldSignature: signatureType,
94FieldUnixFDs: uint32Type,
95}
96
97// requiredFields lists the header fields that are required by the different
98// message types.
99var requiredFields = [typeMax][]HeaderField{
100TypeMethodCall: {FieldPath, FieldMember},
101TypeMethodReply: {FieldReplySerial},
102TypeError: {FieldErrorName, FieldReplySerial},
103TypeSignal: {FieldPath, FieldInterface, FieldMember},
104}
105
106// Message represents a single D-Bus message.
107type Message struct {
108Type
109Flags
110Headers map[HeaderField]Variant
111Body []interface{}
112
113serial uint32
114}
115
116type header struct {
117Field byte
118Variant
119}
120
121func DecodeMessageWithFDs(rd io.Reader, fds []int) (msg *Message, err error) {
122var order binary.ByteOrder
123var hlength, length uint32
124var typ, flags, proto byte
125var headers []header
126
127b := make([]byte, 1)
128_, err = rd.Read(b)
129if err != nil {
130return
131}
132switch b[0] {
133case 'l':
134order = binary.LittleEndian
135case 'B':
136order = binary.BigEndian
137default:
138return nil, InvalidMessageError("invalid byte order")
139}
140
141dec := newDecoder(rd, order, fds)
142dec.pos = 1
143
144msg = new(Message)
145vs, err := dec.Decode(Signature{"yyyuu"})
146if err != nil {
147return nil, err
148}
149if err = Store(vs, &typ, &flags, &proto, &length, &msg.serial); err != nil {
150return nil, err
151}
152msg.Type = Type(typ)
153msg.Flags = Flags(flags)
154
155// get the header length separately because we need it later
156b = make([]byte, 4)
157_, err = io.ReadFull(rd, b)
158if err != nil {
159return nil, err
160}
161binary.Read(bytes.NewBuffer(b), order, &hlength)
162if hlength+length+16 > 1<<27 {
163return nil, InvalidMessageError("message is too long")
164}
165dec = newDecoder(io.MultiReader(bytes.NewBuffer(b), rd), order, fds)
166dec.pos = 12
167vs, err = dec.Decode(Signature{"a(yv)"})
168if err != nil {
169return nil, err
170}
171if err = Store(vs, &headers); err != nil {
172return nil, err
173}
174
175msg.Headers = make(map[HeaderField]Variant)
176for _, v := range headers {
177msg.Headers[HeaderField(v.Field)] = v.Variant
178}
179
180dec.align(8)
181body := make([]byte, int(length))
182if length != 0 {
183_, err := io.ReadFull(rd, body)
184if err != nil {
185return nil, err
186}
187}
188
189if err = msg.IsValid(); err != nil {
190return nil, err
191}
192sig, _ := msg.Headers[FieldSignature].value.(Signature)
193if sig.str != "" {
194buf := bytes.NewBuffer(body)
195dec = newDecoder(buf, order, fds)
196vs, err := dec.Decode(sig)
197if err != nil {
198return nil, err
199}
200msg.Body = vs
201}
202
203return
204}
205
206// DecodeMessage tries to decode a single message in the D-Bus wire format
207// from the given reader. The byte order is figured out from the first byte.
208// The possibly returned error can be an error of the underlying reader, an
209// InvalidMessageError or a FormatError.
210func DecodeMessage(rd io.Reader) (msg *Message, err error) {
211return DecodeMessageWithFDs(rd, make([]int, 0))
212}
213
214type nullwriter struct{}
215
216func (nullwriter) Write(p []byte) (cnt int, err error) {
217return len(p), nil
218}
219
220func (msg *Message) CountFds() (int, error) {
221if len(msg.Body) == 0 {
222return 0, nil
223}
224enc := newEncoder(nullwriter{}, nativeEndian, make([]int, 0))
225err := enc.Encode(msg.Body...)
226return len(enc.fds), err
227}
228
229func (msg *Message) EncodeToWithFDs(out io.Writer, order binary.ByteOrder) (fds []int, err error) {
230if err := msg.validateHeader(); err != nil {
231return nil, err
232}
233var vs [7]interface{}
234switch order {
235case binary.LittleEndian:
236vs[0] = byte('l')
237case binary.BigEndian:
238vs[0] = byte('B')
239default:
240return nil, errors.New("dbus: invalid byte order")
241}
242body := new(bytes.Buffer)
243fds = make([]int, 0)
244enc := newEncoder(body, order, fds)
245if len(msg.Body) != 0 {
246err = enc.Encode(msg.Body...)
247if err != nil {
248return
249}
250}
251vs[1] = msg.Type
252vs[2] = msg.Flags
253vs[3] = protoVersion
254vs[4] = uint32(len(body.Bytes()))
255vs[5] = msg.serial
256headers := make([]header, 0, len(msg.Headers))
257for k, v := range msg.Headers {
258headers = append(headers, header{byte(k), v})
259}
260vs[6] = headers
261var buf bytes.Buffer
262enc = newEncoder(&buf, order, enc.fds)
263err = enc.Encode(vs[:]...)
264if err != nil {
265return
266}
267enc.align(8)
268body.WriteTo(&buf)
269if buf.Len() > 1<<27 {
270return make([]int, 0), InvalidMessageError("message is too long")
271}
272if _, err := buf.WriteTo(out); err != nil {
273return make([]int, 0), err
274}
275return enc.fds, nil
276}
277
278// EncodeTo encodes and sends a message to the given writer. The byte order must
279// be either binary.LittleEndian or binary.BigEndian. If the message is not
280// valid or an error occurs when writing, an error is returned.
281func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) (err error) {
282_, err = msg.EncodeToWithFDs(out, order)
283return err
284}
285
286// IsValid checks whether msg is a valid message and returns an
287// InvalidMessageError or FormatError if it is not.
288func (msg *Message) IsValid() error {
289var b bytes.Buffer
290return msg.EncodeTo(&b, nativeEndian)
291}
292
293func (msg *Message) validateHeader() error {
294if msg.Flags & ^(FlagNoAutoStart|FlagNoReplyExpected|FlagAllowInteractiveAuthorization) != 0 {
295return InvalidMessageError("invalid flags")
296}
297if msg.Type == 0 || msg.Type >= typeMax {
298return InvalidMessageError("invalid message type")
299}
300for k, v := range msg.Headers {
301if k == 0 || k >= fieldMax {
302return InvalidMessageError("invalid header")
303}
304if reflect.TypeOf(v.value) != fieldTypes[k] {
305return InvalidMessageError("invalid type of header field")
306}
307}
308for _, v := range requiredFields[msg.Type] {
309if _, ok := msg.Headers[v]; !ok {
310return InvalidMessageError("missing required header")
311}
312}
313if path, ok := msg.Headers[FieldPath]; ok {
314if !path.value.(ObjectPath).IsValid() {
315return InvalidMessageError("invalid path name")
316}
317}
318if iface, ok := msg.Headers[FieldInterface]; ok {
319if !isValidInterface(iface.value.(string)) {
320return InvalidMessageError("invalid interface name")
321}
322}
323if member, ok := msg.Headers[FieldMember]; ok {
324if !isValidMember(member.value.(string)) {
325return InvalidMessageError("invalid member name")
326}
327}
328if errname, ok := msg.Headers[FieldErrorName]; ok {
329if !isValidInterface(errname.value.(string)) {
330return InvalidMessageError("invalid error name")
331}
332}
333if len(msg.Body) != 0 {
334if _, ok := msg.Headers[FieldSignature]; !ok {
335return InvalidMessageError("missing signature")
336}
337}
338
339return nil
340}
341
342// Serial returns the message's serial number. The returned value is only valid
343// for messages received by eavesdropping.
344func (msg *Message) Serial() uint32 {
345return msg.serial
346}
347
348// String returns a string representation of a message similar to the format of
349// dbus-monitor.
350func (msg *Message) String() string {
351if err := msg.IsValid(); err != nil {
352return "<invalid>"
353}
354s := msg.Type.String()
355if v, ok := msg.Headers[FieldSender]; ok {
356s += " from " + v.value.(string)
357}
358if v, ok := msg.Headers[FieldDestination]; ok {
359s += " to " + v.value.(string)
360}
361s += " serial " + strconv.FormatUint(uint64(msg.serial), 10)
362if v, ok := msg.Headers[FieldReplySerial]; ok {
363s += " reply_serial " + strconv.FormatUint(uint64(v.value.(uint32)), 10)
364}
365if v, ok := msg.Headers[FieldUnixFDs]; ok {
366s += " unixfds " + strconv.FormatUint(uint64(v.value.(uint32)), 10)
367}
368if v, ok := msg.Headers[FieldPath]; ok {
369s += " path " + string(v.value.(ObjectPath))
370}
371if v, ok := msg.Headers[FieldInterface]; ok {
372s += " interface " + v.value.(string)
373}
374if v, ok := msg.Headers[FieldErrorName]; ok {
375s += " error " + v.value.(string)
376}
377if v, ok := msg.Headers[FieldMember]; ok {
378s += " member " + v.value.(string)
379}
380if len(msg.Body) != 0 {
381s += "\n"
382}
383for i, v := range msg.Body {
384s += " " + MakeVariant(v).String()
385if i != len(msg.Body)-1 {
386s += "\n"
387}
388}
389return s
390}
391