1 /++
2 	A module mostly copied from https://github.com/trishume/ddbus to help access the C dbus library on Linux.
3 +/
4 module arsd.dbus;
5 
6 pragma(lib, "dbus-1");
7 
8 import core.time : Duration;
9 import std.meta;
10 import std..string;
11 import std.typecons;
12 import std.exception;
13 import std.traits;
14 import std.conv;
15 import std.range;
16 import std.algorithm;
17 
18 import core.memory;
19 import std.array;
20 import std.format;
21 
22 import std.meta : AliasSeq, staticIndexOf;
23 import std.range;
24 import std.traits;
25 import std.variant : VariantN;
26 
27 
28 /++
29   Flags for use with dbusMarshaling UDA
30 
31   Default is to include public fields only
32 +/
33 enum MarshalingFlag : ubyte {
34   includePrivateFields = 1 << 0,  /// Automatically include private fields
35   manualOnly           = 1 << 7   /// Only include fields with explicit
36                                   ///   `@Yes.DBusMarshal`. This overrides any
37                                   ///   `include` flags.
38 }
39 
40 /++
41   UDA for specifying DBus marshaling options on structs
42 +/
43 auto dbusMarshaling(Args)(Args args ...)
44   if (allSatisfy!(isMarshalingFlag, Args)) {
45   return BitFlags!MarshalingFlag(args);
46 }
47 
48 private template isAllowedField(alias field) {
49   private enum flags = marshalingFlags!(__traits(parent, field));
50   private alias getUDAs!(field, Flag!"DBusMarshal") UDAs;
51 
52   static if (UDAs.length != 0) {
53     static assert (UDAs.length == 1,
54       "Only one UDA of type Flag!\"DBusMarshal\" allowed on struct field.");
55     static assert (is(typeof(UDAs[0]) == Flag!"DBusMarshal"),
56       "Did you intend to add UDA Yes.DBusMarshal or No.DBusMarshal?");
57     enum isAllowedField = cast(bool) UDAs[0];
58   } else static if (!(flags & MarshalingFlag.manualOnly)) {
59     static if (__traits(getProtection, field) == "public")
60       enum isAllowedField = true;
61     else static if (cast(bool) (flags & MarshalingFlag.includePrivateFields))
62       enum isAllowedField = true;
63     else
64       enum isAllowedField = false;
65   } else
66     enum isAllowedField = false;
67 }
68 
69 private template isMarshalingFlag(T) {
70   enum isMarshalingFlag = is(T == MarshalingFlag);
71 }
72 
73 private template marshalingFlags(S) if (is(S == struct)) {
74   private alias getUDAs!(S, BitFlags!MarshalingFlag) UDAs;
75 
76   static if (UDAs.length == 0)
77     enum marshalingFlags = BitFlags!MarshalingFlag.init;
78   else {
79     static assert (UDAs.length == 1,
80       "Only one @dbusMarshaling UDA allowed on type.");
81     static assert (is(typeof(UDAs[0]) == BitFlags!MarshalingFlag),
82       "Huh? Did you intend to use @dbusMarshaling UDA?");
83     enum marshalingFlags = UDAs[0];
84   }
85 }
86 
87 struct DictionaryEntry(K, V) {
88   K key;
89   V value;
90 }
91 
92 auto byDictionaryEntries(K, V)(V[K] aa) {
93   return aa.byKeyValue.map!(pair => DictionaryEntry!(K, V)(pair.key, pair.value));
94 }
95 
96 template VariantType(T) {
97   alias VariantType = TemplateArgsOf!(T)[0];
98 }
99 
100 template allCanDBus(TS...) {
101   static if (TS.length == 0) {
102     enum allCanDBus = true; 
103   } else static if(!canDBus!(TS[0])) {
104     enum allCanDBus = false;
105   } else {
106     enum allCanDBus = allCanDBus!(TS[1..$]);
107   }
108 }
109 
110 /++
111   AliasSeq of all basic types in terms of the DBus typesystem
112  +/
113 private // Don't add to the API yet, 'cause I intend to move it later
114 alias BasicTypes = AliasSeq!(
115   bool,
116   byte,
117   short,
118   ushort,
119   int,
120   uint,
121   long,
122   ulong,
123   double,
124   string,
125   ObjectPath
126 );
127 
128 template basicDBus(T) {
129   static if(staticIndexOf!(T, BasicTypes) >= 0) {
130     enum basicDBus = true;
131   } else static if(is(T B == enum)) {
132     enum basicDBus = basicDBus!B;
133   } else static if(isInstanceOf!(BitFlags, T)) {
134     alias TemplateArgsOf!T[0] E;
135     enum basicDBus = basicDBus!E;
136   } else {
137     enum basicDBus = false;
138   }
139 }
140 
141 template canDBus(T) {
142   static if(basicDBus!T || is(T == DBusAny)) {
143     enum canDBus = true;
144   } else static if(isInstanceOf!(Variant, T)) {
145     enum canDBus = canDBus!(VariantType!T);
146   } else static if(isInstanceOf!(VariantN, T)) {
147     // Phobos-style variants are supported if limited to DBus compatible types.
148     enum canDBus = (T.AllowedTypes.length > 0) && allCanDBus!(T.AllowedTypes);
149   } else static if(isTuple!T) {
150     enum canDBus = allCanDBus!(T.Types);
151   } else static if(isInputRange!T) {
152     static if(is(ElementType!T == DictionaryEntry!(K, V), K, V)) {
153       enum canDBus = basicDBus!K && canDBus!V;
154     } else {
155       enum canDBus = canDBus!(ElementType!T);
156     }
157   } else static if(isAssociativeArray!T) {
158     enum canDBus = basicDBus!(KeyType!T) && canDBus!(ValueType!T);
159   } else static if(is(T == struct) && !isInstanceOf!(DictionaryEntry, T)) {
160     enum canDBus = allCanDBus!(AllowedFieldTypes!T);
161   } else {
162     enum canDBus = false;
163   }
164 }
165 
166 string typeSig(T)() if(canDBus!T) {
167   static if(is(T == byte)) {
168     return "y";
169   } else static if(is(T == bool)) {
170     return "b";
171   } else static if(is(T == short)) {
172     return "n";
173   } else static if(is(T == ushort)) {
174     return "q";
175   } else static if(is(T == int)) {
176     return "i";
177   } else static if(is(T == uint)) {
178     return "u";
179   } else static if(is(T == long)) {
180     return "x";
181   } else static if(is(T == ulong)) {
182     return "t";
183   } else static if(is(T == double)) {
184     return "d";
185   } else static if(is(T == string)) {
186     return "s";
187   } else static if(is(T == ObjectPath)) {
188     return "o";
189   } else static if(isInstanceOf!(Variant, T) || isInstanceOf!(VariantN, T)) {
190     return "v";
191   } else static if(is(T B == enum)) {
192     return typeSig!B;
193   } else static if(isInstanceOf!(BitFlags, T)) {
194     alias TemplateArgsOf!T[0] E;
195     return typeSig!E;
196   } else static if(is(T == DBusAny)) {
197     static assert(false, "Cannot determine type signature of DBusAny. Change to Variant!DBusAny if a variant was desired.");
198   } else static if(isTuple!T) {
199     string sig = "(";
200     foreach(i, S; T.Types) {
201       sig ~= typeSig!S();
202     } 
203     sig ~= ")";
204     return sig;
205   } else static if(isInputRange!T) {
206     return "a" ~ typeSig!(ElementType!T)();
207   } else static if(isAssociativeArray!T) {
208     return "a{" ~ typeSig!(KeyType!T) ~ typeSig!(ValueType!T) ~ "}";
209   } else static if(is(T == struct)) {
210     string sig = "(";
211     foreach(i, S; AllowedFieldTypes!T) {
212       sig ~= typeSig!S();
213     }
214     sig ~= ")";
215     return sig;
216   }
217 }
218 
219 string typeSig(T)() if(isInstanceOf!(DictionaryEntry, T)) {
220   alias typeof(T.key) K;
221   alias typeof(T.value) V;
222   return "{" ~ typeSig!K ~ typeSig!V ~ '}';
223 }
224 
225 string[] typeSigReturn(T)() if(canDBus!T) {
226   static if(is(T == Tuple!TS, TS...))
227     return typeSigArr!TS;
228   else
229     return [typeSig!T];
230 }
231 
232 string typeSigAll(TS...)() if(allCanDBus!TS) {
233   string sig = "";
234   foreach(i,T; TS) {
235     sig ~= typeSig!T();
236   }
237   return sig;
238 }
239 
240 string[] typeSigArr(TS...)() if(allCanDBus!TS) {
241   string[] sig = [];
242   foreach(i,T; TS) {
243     sig ~= typeSig!T();
244   }
245   return sig;
246 }
247 
248 int typeCode(T)() if(canDBus!T) {
249   int code = typeSig!T()[0];
250   return (code != '(') ? code : 'r';
251 }
252 
253 int typeCode(T)() if(isInstanceOf!(DictionaryEntry, T) && canDBus!(T[])) {
254   return 'e';
255 }
256 
257 private template AllowedFieldTypes(S) if (is(S == struct)) {
258   static alias TypeOf(alias sym) = typeof(sym);
259 
260   alias AllowedFieldTypes =
261     staticMap!(TypeOf, Filter!(isAllowedField, S.tupleof));
262 }
263 
264 struct ObjectPath {
265   private string _value;
266 
267   this(string objPath) pure @safe {
268     enforce(isValid(objPath));
269     _value = objPath;
270   }
271 
272   string toString() const {
273     return _value;
274   }
275 
276   /++
277     Returns the string representation of this ObjectPath.
278    +/
279   string value() const pure @nogc nothrow @safe {
280     return _value;
281   }
282 
283   size_t toHash() const pure @nogc nothrow @trusted {
284     return hashOf(_value);
285   }
286 
287   bool opEquals(ref const typeof(this) b) const pure @nogc nothrow @safe {
288     return _value == b._value;
289   }
290 
291   ObjectPath opBinary(string op : "~")(string rhs) const pure @safe {
292     if (!rhs.startsWith("/"))
293       return opBinary!"~"(ObjectPath("/" ~ rhs));
294     else
295       return opBinary!"~"(ObjectPath(rhs));
296   }
297 
298   ObjectPath opBinary(string op : "~")(ObjectPath rhs) const pure @safe
299   in {
300     assert(ObjectPath.isValid(_value) && ObjectPath.isValid(rhs._value));
301   } out (v) {
302     assert(ObjectPath.isValid(v._value));
303   } body {
304     ObjectPath ret;
305 
306     if (_value == "/")
307       ret._value = rhs._value;
308     else
309       ret._value = _value ~ rhs._value;
310 
311     return ret;
312   }
313 
314   void opOpAssign(string op : "~")(string rhs) pure @safe {
315     _value = opBinary!"~"(rhs)._value;
316   }
317 
318   void opOpAssign(string op : "~")(ObjectPath rhs) pure @safe {
319     _value = opBinary!"~"(rhs)._value;
320   }
321 
322   /++
323     Returns: `false` for empty strings or strings that don't match the
324     pattern `(/[0-9A-Za-z_]+)+|/`.
325    +/
326   static bool isValid(string objPath) pure @nogc nothrow @safe {
327     import std.ascii : isAlphaNum;
328 
329     if (!objPath.length)
330       return false;
331     if (objPath == "/")
332       return true;
333     if (objPath[0] != '/' || objPath[$ - 1] == '/')
334       return false;
335     // .representation to avoid unicode exceptions -> @nogc & nothrow
336     return objPath.representation.splitter('/').drop(1)
337       .all!(a =>
338         a.length &&
339         a.all!(c =>
340           c.isAlphaNum || c == '_'
341         )
342       );
343   }
344 }
345 
346 /// Structure allowing typeless parameters
347 struct DBusAny {
348   /// DBus type of the value (never 'v'), see typeSig!T
349   int type;
350   /// Child signature for Arrays & Tuples
351   string signature;
352   /// If true, this value will get serialized as variant value, otherwise it is serialized like it wasn't in a DBusAny wrapper.
353   /// Same functionality as Variant!T but with dynamic types if true.
354   bool explicitVariant;
355 
356   union
357   {
358     ///
359     byte int8;
360     ///
361     short int16;
362     ///
363     ushort uint16;
364     ///
365     int int32;
366     ///
367     uint uint32;
368     ///
369     long int64;
370     ///
371     ulong uint64;
372     ///
373     double float64;
374     ///
375     string str;
376     ///
377     bool boolean;
378     ///
379     ObjectPath obj;
380     ///
381     DBusAny[] array;
382     ///
383     alias tuple = array;
384     ///
385     DictionaryEntry!(DBusAny, DBusAny)* entry;
386     ///
387     ubyte[] binaryData;
388   }
389 
390   /// Manually creates a DBusAny object using a type, signature and implicit specifier.
391   this(int type, string signature, bool explicit) {
392     this.type = type;
393     this.signature = signature;
394     this.explicitVariant = explicit;
395   }
396 
397   /// Automatically creates a DBusAny object with fitting parameters from a D type or Variant!T.
398   /// Pass a `Variant!T` to make this an explicit variant.
399   this(T)(T value) {
400     static if(is(T == byte) || is(T == ubyte)) {
401       this(typeCode!byte, null, false);
402       int8 = cast(byte) value;
403     } else static if(is(T == short)) {
404       this(typeCode!short, null, false);
405       int16 = cast(short) value;
406     } else static if(is(T == ushort)) {
407       this(typeCode!ushort, null, false);
408       uint16 = cast(ushort) value;
409     } else static if(is(T == int)) {
410       this(typeCode!int, null, false);
411       int32 = cast(int) value;
412     } else static if(is(T == uint)) {
413       this(typeCode!uint, null, false);
414       uint32 = cast(uint) value;
415     } else static if(is(T == long)) {
416       this(typeCode!long, null, false);
417       int64 = cast(long) value;
418     } else static if(is(T == ulong)) {
419       this(typeCode!ulong, null, false);
420       uint64 = cast(ulong) value;
421     } else static if(is(T == double)) {
422       this(typeCode!double, null, false);
423       float64 = cast(double) value;
424     } else static if(isSomeString!T) {
425       this(typeCode!string, null, false);
426       str = value.to!string;
427     } else static if(is(T == bool)) {
428       this(typeCode!bool, null, false);
429       boolean = cast(bool) value;
430     } else static if(is(T == ObjectPath)) {
431       this(typeCode!ObjectPath, null, false);
432       obj = value;
433     } else static if(is(T == Variant!R, R)) {
434       static if(is(R == DBusAny)) {
435         type = value.data.type;
436         signature = value.data.signature;
437         explicitVariant = true;
438         if(type == 'a' || type == 'r') {
439           if(signature == ['y'])
440             binaryData = value.data.binaryData;
441           else
442             array = value.data.array;
443         } else if(type == 's')
444           str = value.data.str;
445         else if(type == 'e')
446           entry = value.data.entry;
447         else
448           uint64 = value.data.uint64;
449       } else {
450         this(value.data);
451         explicitVariant = true;
452       }
453     } else static if(is(T : DictionaryEntry!(K, V), K, V)) {
454       this('e', null, false);
455       entry = new DictionaryEntry!(DBusAny, DBusAny)();
456       static if(is(K == DBusAny))
457         entry.key = value.key;
458       else
459         entry.key = DBusAny(value.key);
460       static if(is(V == DBusAny))
461         entry.value = value.value;
462       else
463         entry.value = DBusAny(value.value);
464     } else static if(is(T == ubyte[]) || is(T == byte[])) {
465       this('a', ['y'], false);
466       binaryData = cast(ubyte[]) value;
467     } else static if(isInputRange!T) {
468       this.type = 'a';
469       static assert(!is(ElementType!T == DBusAny), "Array must consist of the same type, use Variant!DBusAny or DBusAny(tuple(...)) instead");
470       static assert(.typeSig!(ElementType!T) != "y");
471       this.signature = .typeSig!(ElementType!T);
472       this.explicitVariant = false;
473       foreach(elem; value)
474         array ~= DBusAny(elem);
475     } else static if(isTuple!T) {
476       this.type = 'r';
477       this.signature = ['('];
478       this.explicitVariant = false;
479       foreach(index, R; value.Types) {
480         auto var = DBusAny(value[index]);
481         tuple ~= var;
482         if(var.explicitVariant)
483           this.signature ~= 'v';
484         else {
485           if (var.type != 'r')
486             this.signature ~= cast(char) var.type;
487           if(var.type == 'a' || var.type == 'r')
488             this.signature ~= var.signature;
489         }
490       }
491       this.signature ~= ')';
492     } else static if(isAssociativeArray!T) {
493       this(value.byDictionaryEntries);
494     } else static assert(false, T.stringof ~ " not convertible to a Variant");
495   }
496 
497   ///
498   string toString() const {
499     string valueStr;
500     switch(type) {
501     case typeCode!byte:
502       valueStr = int8.to!string;
503       break;
504     case typeCode!short:
505       valueStr = int16.to!string;
506       break;
507     case typeCode!ushort:
508       valueStr = uint16.to!string;
509       break;
510     case typeCode!int:
511       valueStr = int32.to!string;
512       break;
513     case typeCode!uint:
514       valueStr = uint32.to!string;
515       break;
516     case typeCode!long:
517       valueStr = int64.to!string;
518       break;
519     case typeCode!ulong:
520       valueStr = uint64.to!string;
521       break;
522     case typeCode!double:
523       valueStr = float64.to!string;
524       break;
525     case typeCode!string:
526       valueStr = '"' ~ str ~ '"';
527       break;
528     case typeCode!ObjectPath:
529       valueStr = '"' ~ obj.to!string ~ '"';
530       break;
531     case typeCode!bool:
532       valueStr = boolean ? "true" : "false";
533       break;
534     case 'a':
535       import std.digest : toHexString;
536 
537       if(signature == ['y'])
538         valueStr = "binary(" ~ binaryData.toHexString ~ ')';
539       else
540         valueStr = '[' ~ array.map!(a => a.toString).join(", ") ~ ']';
541       break;
542     case 'r':
543       valueStr = '(' ~ tuple.map!(a => a.toString).join(", ") ~ ')';
544       break;
545     case 'e':
546       valueStr = entry.key.toString ~ ": " ~ entry.value.toString;
547       break;
548     default:
549       valueStr = "unknown";
550       break;
551     }
552     return "DBusAny(" ~ cast(char) type
553       ~ ", \"" ~ signature.idup
554       ~ "\", " ~ (explicitVariant ? "explicit" : "implicit")
555       ~ ", " ~ valueStr ~ ")";
556   }
557 
558   /++
559     Get the value stored in the DBusAny object.
560 
561     Parameters:
562       T = The requested type. The currently stored value must match the
563         requested type exactly.
564 
565     Returns:
566       The current value of the DBusAny object.
567 
568     Throws:
569       TypeMismatchException if the DBus type of the current value of the
570       DBusAny object is not the same as the DBus type used to represent T.
571   +/
572   T get(T)() @property const
573     if(staticIndexOf!(T, BasicTypes) >= 0)
574   {
575     enforce(type == typeCode!T,
576       new TypeMismatchException(
577         "Cannot get a " ~ T.stringof ~ " from a DBusAny with"
578           ~ " a value of DBus type '" ~ typeSig ~ "'.", typeCode!T, type));
579 
580     static if(isIntegral!T) {
581       enum memberName =
582         (isUnsigned!T ? "uint" : "int") ~ (T.sizeof * 8).to!string;
583       return __traits(getMember, this, memberName);
584     } else static if(is(T == double)) {
585       return float64;
586     } else static if(is(T == string)) {
587       return str;
588     } else static if(is(T == ObjectPath)) {
589       return obj;
590     } else static if(is(T == bool)) {
591       return boolean;
592     } else {
593       static assert(false);
594     }
595   }
596 
597   /// ditto
598   T get(T)() @property const
599     if(is(T == const(DBusAny)[]))
600   {
601     enforce((type == 'a' && signature != "y") || type == 'r',
602       new TypeMismatchException(
603         "Cannot get a " ~ T.stringof ~ " from a DBusAny with"
604           ~ " a value of DBus type '" ~ this.typeSig ~ "'.",
605         typeCode!T, type));
606 
607     return array;
608   }
609 
610   /// ditto
611   T get(T)() @property const
612     if (is(T == const(ubyte)[]))
613   {
614     enforce(type == 'a' && signature == "y",
615       new TypeMismatchException(
616         "Cannot get a " ~ T.stringof ~ " from a DBusAny with"
617           ~ " a value of DBus type '" ~ this.typeSig ~ "'.",
618         typeCode!T, type));
619 
620     return binaryData;
621   }
622 
623   /// If the value is an array of DictionaryEntries this will return a HashMap
624   DBusAny[DBusAny] toAA() {
625     enforce(type == 'a' && signature && signature[0] == '{');
626     DBusAny[DBusAny] aa;
627     foreach(val; array) {
628       enforce(val.type == 'e');
629       aa[val.entry.key] = val.entry.value;
630     }
631     return aa;
632   }
633 
634   /++
635     Get the DBus type signature of the value stored in the DBusAny object.
636 
637     Returns:
638       The type signature of the value stored in this DBusAny object.
639    +/
640   string typeSig() @property const pure nothrow @safe
641   {
642     if(type == 'a') {
643       return "a" ~ signature;
644     } else if(type == 'r') {
645       return signature;
646     } else if(type == 'e') {
647       return () @trusted {
648         return "{" ~ entry.key.signature ~ entry.value.signature ~ "}";
649       } ();
650     } else {
651       return [ cast(char) type ];
652     }
653   }
654 
655   /// Converts a basic type, a tuple or an array to the D type with type checking. Tuples can get converted to an array too.
656   T to(T)() {
657     static if(is(T == Variant!R, R)) {
658       static if(is(R == DBusAny)) {
659         auto v = to!R;
660         v.explicitVariant = false;
661         return Variant!R(v);
662       } else
663         return Variant!R(to!R);
664     } else static if(is(T == DBusAny)) {
665       return this;
666     } else static if(isIntegral!T || isFloatingPoint!T) {
667       switch(type) {
668       case typeCode!byte:
669         return cast(T) int8;
670       case typeCode!short:
671         return cast(T) int16;
672       case typeCode!ushort:
673         return cast(T) uint16;
674       case typeCode!int:
675         return cast(T) int32;
676       case typeCode!uint:
677         return cast(T) uint32;
678       case typeCode!long:
679         return cast(T) int64;
680       case typeCode!ulong:
681         return cast(T) uint64;
682       case typeCode!double:
683         return cast(T) float64;
684       default:
685         throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
686       }
687     } else static if(is(T == bool)) {
688       if(type == 'b')
689         return boolean;
690       else
691         throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
692     } else static if(isSomeString!T) {
693       if(type == 's')
694         return str.to!T;
695       else if(type == 'o')
696         return obj.toString();
697       else
698         throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
699     } else static if(is(T == ObjectPath)) {
700       if(type == 'o')
701         return obj;
702       else
703         throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
704     } else static if(isDynamicArray!T) {
705       if(type != 'a' && type != 'r')
706         throw new Exception("Can't convert type " ~ cast(char) type ~ " to an array");
707       T ret;
708       if(signature == ['y']) {
709         static if(isIntegral!(ElementType!T))
710           foreach(elem; binaryData)
711             ret ~= elem.to!(ElementType!T);
712       } else
713         foreach(elem; array)
714           ret ~= elem.to!(ElementType!T);
715       return ret;
716     } else static if(isTuple!T) {
717       if(type != 'r')
718         throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
719       T ret;
720       enforce(ret.Types.length == tuple.length, "Tuple length mismatch");
721       foreach(index, T; ret.Types)
722         ret[index] = tuple[index].to!T;
723       return ret;
724     } else static if(isAssociativeArray!T) {
725       if(type != 'a' || !signature || signature[0] != '{')
726         throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
727       T ret;
728       foreach(pair; array) {
729         enforce(pair.type == 'e');
730         ret[pair.entry.key.to!(KeyType!T)] = pair.entry.value.to!(ValueType!T);
731       }
732       return ret;
733     } else static assert(false, "Can't convert variant to " ~ T.stringof);
734   }
735 
736   bool opEquals(ref in DBusAny b) const {
737     if(b.type != type || b.explicitVariant != explicitVariant)
738       return false;
739     if((type == 'a' || type == 'r') && b.signature != signature)
740       return false;
741     if(type == 'a' && signature == ['y'])
742       return binaryData == b.binaryData;
743     if(type == 'a')
744       return array == b.array;
745     else if(type == 'r')
746       return tuple == b.tuple;
747     else if(type == 's')
748       return str == b.str;
749     else if(type == 'o')
750       return obj == b.obj;
751     else if(type == 'e')
752       return entry == b.entry || (entry && b.entry && *entry == *b.entry);
753     else
754       return uint64 == b.uint64;
755   }
756 }
757 
758 /// Marks the data as variant on serialization
759 struct Variant(T) {
760   ///
761   T data;
762 }
763 
764 Variant!T variant(T)(T data) {
765   return Variant!T(data);
766 }
767 
768 enum MessageType {
769   Invalid = 0,
770   Call, Return, Error, Signal
771 }
772 
773 void emitSignal(Args...)(Connection conn, string path, string iface, string name, Args args) {
774 	Message msg = Message(null, path, iface, name, true);
775 	msg.build(args);
776 	conn.send(msg);
777 }
778 
779 struct Message {
780   DBusMessage *msg;
781 
782   this(string dest, string path, string iface, string method, bool signal = false) {
783     if(signal)
784         msg = dbus_message_new_signal(path.toStringz(), iface.toStringz(), method.toStringz());
785     else
786         msg = dbus_message_new_method_call(dest.toStringz(), path.toStringz(), iface.toStringz(), method.toStringz());
787   }
788 
789   this(DBusMessage *m) {
790     msg = m;
791   }
792 
793   this(this) {
794     dbus_message_ref(msg);
795   }
796 
797   ~this() {
798     dbus_message_unref(msg);
799   }
800 
801   void build(TS...)(TS args) if(allCanDBus!TS) {
802     DBusMessageIter iter;
803     dbus_message_iter_init_append(msg, &iter);
804     buildIter(&iter, args);
805   }
806 
807   /**
808      Reads the first argument of the message.
809      Note that this creates a new iterator every time so calling it multiple times will always
810      read the first argument. This is suitable for single item returns.
811      To read multiple arguments use readTuple.
812   */
813   T read(T)() if(canDBus!T) {
814     DBusMessageIter iter;
815     dbus_message_iter_init(msg, &iter);
816     return readIter!T(&iter);
817   }
818   alias read to;
819 
820   Tup readTuple(Tup)() if(isTuple!Tup && allCanDBus!(Tup.Types)) {
821     DBusMessageIter iter;
822     dbus_message_iter_init(msg, &iter);
823     Tup ret;
824     readIterTuple(&iter, ret);
825     return ret;
826   }
827 
828   Message createReturn() {
829     return Message(dbus_message_new_method_return(msg));
830   }
831 
832   MessageType type() {
833     return cast(MessageType)dbus_message_get_type(msg);
834   }
835 
836   bool isCall() {
837     return type() == MessageType.Call;
838   }
839 
840   // Various string members
841   // TODO: make a mixin to avoid this copy-paste
842   string signature() {
843     const(char)* cStr = dbus_message_get_signature(msg);
844     assert(cStr != null);
845     return cStr.fromStringz().idup;
846   }
847   string path() {
848     const(char)* cStr = dbus_message_get_path(msg);
849     assert(cStr != null);
850     return cStr.fromStringz().idup;
851   }
852   string iface() {
853     const(char)* cStr = dbus_message_get_interface(msg);
854     assert(cStr != null);
855     return cStr.fromStringz().idup;
856   }
857   string member() {
858     const(char)* cStr = dbus_message_get_member(msg);
859     assert(cStr != null);
860     return cStr.fromStringz().idup;
861   }
862   string sender() {
863     const(char)* cStr = dbus_message_get_sender(msg);
864     assert(cStr != null);
865     return cStr.fromStringz().idup;
866   }
867 }
868 
869 struct Connection {
870   DBusConnection *conn;
871   this(DBusConnection *connection) {
872     conn = connection;
873   }
874 
875   this(this) {
876     dbus_connection_ref(conn);
877   }
878 
879   ~this() {
880     dbus_connection_unref(conn);
881   }
882 
883   void close() {
884     dbus_connection_close(conn);
885   }
886 
887   void send(Message msg) {
888     dbus_connection_send(conn,msg.msg, null);
889   }
890 
891   void sendBlocking(Message msg) {
892     send(msg);
893     dbus_connection_flush(conn);
894   }
895 
896   Message sendWithReplyBlocking(Message msg, int timeout = -1) {
897     DBusMessage *dbusMsg = msg.msg;
898     dbus_message_ref(dbusMsg);
899     DBusMessage *reply = wrapErrors((err) {
900         auto ret = dbus_connection_send_with_reply_and_block(conn,dbusMsg,timeout,err);
901         dbus_message_unref(dbusMsg);
902         return ret;
903       });
904     return Message(reply);
905   }
906 
907   Message sendWithReplyBlocking(Message msg, Duration timeout) {
908     return sendWithReplyBlocking(msg, timeout.total!"msecs"().to!int);
909   }
910 }
911 
912 Connection connectToBus(DBusBusType bus = DBusBusType.DBUS_BUS_SESSION) {
913   DBusConnection *conn = wrapErrors((err) { return dbus_bus_get(bus,err); });
914   return Connection(conn);
915 }
916 
917 class PathIface {
918   this(Connection conn, string dest, ObjectPath path, string iface) {
919     this(conn, dest, path.value, iface);
920   }
921 
922   this(Connection conn, string dest, string path, string iface) {
923     this.conn = conn;
924     this.dest = dest.toStringz();
925     this.path = path.toStringz();
926     this.iface = iface.toStringz();
927   }
928 
929   Ret call(Ret, Args...)(string meth, Args args) if(allCanDBus!Args && canDBus!Ret) {
930     Message msg = Message(dbus_message_new_method_call(dest,path,iface,meth.toStringz()));
931     msg.build(args);
932     Message ret = conn.sendWithReplyBlocking(msg);
933     return ret.read!Ret();
934   }
935 
936   Message opDispatch(string meth, Args...)(Args args) {
937     Message msg = Message(dbus_message_new_method_call(dest,path,iface,meth.toStringz()));
938     msg.build(args);
939     return conn.sendWithReplyBlocking(msg);
940   }
941 
942   Connection conn;
943   const(char)* dest;
944   const(char)* path;
945   const(char)* iface;
946 }
947 
948 enum SignalMethod;
949 
950 /**
951    Registers all *possible* methods of an object in a router.
952    It will not register methods that use types that ddbus can't handle.
953 
954    The implementation is rather hacky and uses the compiles trait to check for things
955    working so if some methods randomly don't seem to be added, you should probably use
956    setHandler on the router directly. It is also not efficient and creates a closure for every method.
957 
958    TODO: replace this with something that generates a wrapper class who's methods take and return messages
959    and basically do what MessageRouter.setHandler does but avoiding duplication. Then this DBusWrapper!Class
960    could be instantiated with any object efficiently and placed in the router table with minimal duplication.
961  */
962 void registerMethods(T : Object)(MessageRouter router, string path, string iface, T obj) {
963   MessagePattern patt = MessagePattern(path,iface,"",false);
964   foreach(member; __traits(allMembers, T)) {
965     static if (__traits(compiles, __traits(getOverloads, obj, member))
966                && __traits(getOverloads, obj, member).length > 0
967                && __traits(compiles, router.setHandler(patt, &__traits(getOverloads,obj,member)[0]))) {
968       patt.method = member;
969       patt.signal = hasUDA!(__traits(getOverloads,obj,member)[0], SignalMethod);
970       router.setHandler(patt, &__traits(getOverloads,obj,member)[0]);
971     }
972   }
973 }
974 
975 struct MessagePattern {
976   string path;
977   string iface;
978   string method;
979   bool signal;
980 
981   this(Message msg) {
982     path = msg.path();
983     iface = msg.iface();
984     method = msg.member();
985     signal = (msg.type() == MessageType.Signal);
986   }
987 
988   this(string path, string iface, string method, bool signal = false) {
989     this.path = path;
990     this.iface = iface;
991     this.method = method;
992     this.signal = signal;
993   }
994 
995   size_t toHash() const @safe nothrow {
996     size_t hash = 0;
997     auto stringHash = &(typeid(path).getHash);
998     hash += stringHash(&path);
999     hash += stringHash(&iface);
1000     hash += stringHash(&method);
1001     hash += (signal?1:0);
1002     return hash;
1003   }
1004 
1005   bool opEquals(ref const typeof(this) s) const @safe pure nothrow {
1006     return (path == s.path) && (iface == s.iface) && (method == s.method) && (signal == s.signal);
1007   }
1008 }
1009 
1010 struct MessageHandler {
1011   alias HandlerFunc = void delegate(Message call, Connection conn);
1012   HandlerFunc func;
1013   string[] argSig;
1014   string[] retSig;
1015 }
1016 
1017 class MessageRouter {
1018   MessageHandler[MessagePattern] callTable;
1019 
1020   bool handle(Message msg, Connection conn) {
1021     MessageType type = msg.type();
1022     if(type != MessageType.Call && type != MessageType.Signal)
1023       return false;
1024     auto pattern = MessagePattern(msg);
1025     // import std.stdio; debug writeln("Handling ", pattern);
1026 
1027     if(pattern.iface == "org.freedesktop.DBus.Introspectable" &&
1028       pattern.method == "Introspect" && !pattern.signal) {
1029       handleIntrospect(pattern.path, msg, conn);
1030       return true;
1031     }
1032 
1033     MessageHandler* handler = (pattern in callTable);
1034     if(handler is null) return false;
1035 
1036     // Check for matching argument types
1037     version(DDBusNoChecking) {
1038 
1039     } else {
1040       if(!equal(join(handler.argSig), msg.signature())) {
1041         return false;
1042       }
1043     }
1044 
1045     handler.func(msg,conn);
1046     return true;
1047   }
1048 
1049   void setHandler(Ret, Args...)(MessagePattern patt, Ret delegate(Args) handler) {
1050     void handlerWrapper(Message call, Connection conn) {
1051       Tuple!Args args = call.readTuple!(Tuple!Args)();
1052       auto retMsg = call.createReturn();
1053       static if(!is(Ret == void)) {
1054         Ret ret = handler(args.expand);
1055         static if (is(Ret == Tuple!T, T...))
1056           retMsg.build!T(ret.expand);
1057         else
1058           retMsg.build(ret);
1059       } else {
1060         handler(args.expand);
1061       }
1062       if(!patt.signal)
1063         conn.send(retMsg);
1064     }
1065     static string[] args = typeSigArr!Args;
1066     static if(is(Ret==void)) {
1067       static string[] ret = [];
1068     } else {
1069       static string[] ret = typeSigReturn!Ret;
1070     }
1071     MessageHandler handleStruct = {func: &handlerWrapper, argSig: args, retSig: ret};
1072     callTable[patt] = handleStruct;
1073   }
1074 
1075   static string introspectHeader = `<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
1076 <node name="%s">`;
1077 
1078   string introspectXML(string path) {
1079     auto methods = callTable.byKey().filter!(a => (a.path == path) && !a.signal)().array()
1080       // .schwartzSort!((a) => a.iface, "a<b")();
1081       .sort!((a,b) => a.iface < b.iface)();
1082     auto ifaces = methods.groupBy();
1083     auto app = appender!string;
1084     formattedWrite(app,introspectHeader,path);
1085     foreach(iface; ifaces) {
1086       formattedWrite(app,`<interface name="%s">`,iface.front.iface);
1087       foreach(methodPatt; iface.array()) {
1088         formattedWrite(app,`<method name="%s">`,methodPatt.method);
1089         auto handler = callTable[methodPatt];
1090         foreach(arg; handler.argSig) {
1091           formattedWrite(app,`<arg type="%s" direction="in"/>`,arg);
1092         }
1093         foreach(arg; handler.retSig) {
1094           formattedWrite(app,`<arg type="%s" direction="out"/>`,arg);
1095         }
1096         app.put("</method>");
1097       }
1098       app.put("</interface>");
1099     }
1100 
1101     string childPath = path;
1102     if(!childPath.endsWith("/")) {
1103       childPath ~= "/";
1104     }
1105     auto children = callTable.byKey().filter!(a => (a.path.startsWith(childPath)) && !a.signal)()
1106       .map!((s) => s.path.chompPrefix(childPath))
1107       .map!((s) => s.splitter('/').front)
1108       .array().sort().uniq();
1109     foreach(child; children) {
1110       formattedWrite(app,`<node name="%s"/>`,child);
1111     }
1112 
1113     app.put("</node>");
1114     return app.data;
1115   }
1116 
1117   void handleIntrospect(string path, Message call, Connection conn) {
1118     auto retMsg = call.createReturn();
1119     retMsg.build(introspectXML(path));
1120     conn.sendBlocking(retMsg);
1121   }
1122 }
1123 
1124 extern(C) private DBusHandlerResult filterFunc(DBusConnection *dConn, DBusMessage *dMsg, void *routerP) {
1125   MessageRouter router = cast(MessageRouter)routerP;
1126   dbus_message_ref(dMsg);
1127   Message msg = Message(dMsg);
1128   dbus_connection_ref(dConn);
1129   Connection conn = Connection(dConn);
1130   bool handled = router.handle(msg, conn);
1131   if(handled) {
1132     return DBusHandlerResult.DBUS_HANDLER_RESULT_HANDLED;
1133   } else {
1134     return DBusHandlerResult.DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1135   }
1136 }
1137 
1138 extern(C) private void unrootUserData(void *userdata) {
1139   GC.removeRoot(userdata);
1140 }
1141 
1142 void registerRouter(Connection conn, MessageRouter router) {
1143   void *routerP = cast(void*)router;
1144   GC.addRoot(routerP);
1145   dbus_connection_add_filter(conn.conn, &filterFunc, routerP, &unrootUserData);
1146 }
1147 
1148 private T wrapErrors(T)(
1149   T delegate(DBusError *err) del,
1150   string file = __FILE__,
1151   size_t line = __LINE__,
1152   Throwable next = null
1153 ) {
1154   DBusError error;
1155   dbus_error_init(&error);
1156   T ret = del(&error);
1157   if(dbus_error_is_set(&error)) {
1158     auto ex = new DBusException(&error, file, line, next);
1159     dbus_error_free(&error);
1160     throw ex;
1161   }
1162   return ret;
1163 }
1164 
1165 /++
1166   Thrown when a DBus error code was returned by libdbus.
1167 +/
1168 class DBusException : Exception {
1169   private this(
1170     scope DBusError *err,
1171     string file = __FILE__,
1172     size_t line = __LINE__,
1173     Throwable next = null
1174   ) pure nothrow {
1175 
1176     super(err.message.fromStringz().idup, file, line, next);
1177   }
1178 }
1179 
1180 /++
1181   Thrown when the signature of a message does not match the requested types or
1182   when trying to get a value from a DBusAny object that does not match the type
1183   of its actual value.
1184 +/
1185 class TypeMismatchException : Exception {
1186   private this(
1187     int expectedType,
1188     int actualType,
1189     string file = __FILE__,
1190     size_t line = __LINE__,
1191     Throwable next = null
1192   ) pure nothrow @safe {
1193     string message;
1194 
1195     if (expectedType == 'v') {
1196       message = "The type of value at the current position in the message is"
1197         ~ " incompatible to the target variant type."
1198         ~ " Type code of the value: '" ~ cast(char) actualType ~ '\'';
1199     } else {
1200       message = "The type of value at the current position in the message does"
1201         ~ " not match the type of value to be read."
1202         ~ " Expected: '" ~ cast(char) expectedType ~ "',"
1203         ~ " Got: '" ~ cast(char) actualType ~ '\'';
1204     }
1205 
1206     this(message, expectedType, actualType, file, line, next);
1207   }
1208 
1209   this(
1210     string message,
1211     int expectedType,
1212     int actualType,
1213     string file = __FILE__,
1214     size_t line = __LINE__,
1215     Throwable next = null
1216   ) pure nothrow @safe {
1217     _expectedType = expectedType;
1218     _actualType = actualType;
1219     super(message, file, line, next);
1220   }
1221 
1222   int expectedType() @property pure const nothrow @safe @nogc {
1223     return _expectedType;
1224   }
1225 
1226   int actualType() @property pure const nothrow @safe @nogc {
1227     return _actualType;
1228   }
1229 
1230   private:
1231   int _expectedType;
1232   int _actualType;
1233 }
1234 
1235 /++
1236   Thrown during type conversion between DBus types and D types when a value is
1237   encountered that can not be represented in the target type.
1238 
1239   This exception should not normally be thrown except when dealing with D types
1240   that have a constrained value set, such as Enums.
1241 +/
1242 class InvalidValueException : Exception {
1243   private this(Source)(
1244     Source value,
1245     string targetType,
1246     string file = __FILE__,
1247     size_t line = __LINE__,
1248     Throwable next = null
1249   ) {
1250     import std.conv : to;
1251 
1252     static if(__traits(compiles, value.to!string))
1253       string valueString = value.to!string;
1254     else
1255       string valueString = "(unprintable)";
1256 
1257     super("Value " ~ valueString ~ " cannot be represented in type " ~ targetType);
1258   }
1259 }
1260 
1261 import std.exception : enforce;
1262 import std.meta: allSatisfy;
1263 import std.range;
1264 import std.traits;
1265 import std.variant : VariantN;
1266 
1267 void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) {
1268   foreach(index, arg; args) {
1269     alias TS[index] T;
1270     static if(is(T == string)) {
1271       immutable(char)* cStr = arg.toStringz();
1272       dbus_message_iter_append_basic(iter,typeCode!T,&cStr);
1273     } else static if(is(T == ObjectPath)) {
1274       immutable(char)* cStr = arg.toString().toStringz();
1275       dbus_message_iter_append_basic(iter,typeCode!T,&cStr);
1276     } else static if(is(T==bool)) {
1277       dbus_bool_t longerBool = arg; // dbus bools are ints
1278       dbus_message_iter_append_basic(iter,typeCode!T,&longerBool);
1279     } else static if(isTuple!T) {
1280       DBusMessageIter sub;
1281       dbus_message_iter_open_container(iter, 'r', null, &sub);
1282       buildIter(&sub, arg.expand);
1283       dbus_message_iter_close_container(iter, &sub);
1284     } else static if(isInputRange!T) {
1285       DBusMessageIter sub;
1286       const(char)* subSig = (typeSig!(ElementType!T)()).toStringz();
1287       dbus_message_iter_open_container(iter, 'a', subSig, &sub);
1288       foreach(x; arg) {
1289         static if(isInstanceOf!(DictionaryEntry, typeof(x))) {
1290           DBusMessageIter entry;
1291           dbus_message_iter_open_container(&sub, 'e', null, &entry);
1292           buildIter(&entry, x.key);
1293           buildIter(&entry, x.value);
1294           dbus_message_iter_close_container(&sub, &entry);
1295         } else {
1296           buildIter(&sub, x);
1297         }
1298       }
1299       dbus_message_iter_close_container(iter, &sub);
1300     } else static if(isAssociativeArray!T) {
1301       DBusMessageIter sub;
1302       const(char)* subSig = typeSig!T[1..$].toStringz();
1303       dbus_message_iter_open_container(iter, 'a', subSig, &sub);
1304       foreach(k, v; arg) {
1305         DBusMessageIter entry;
1306         dbus_message_iter_open_container(&sub, 'e', null, &entry);
1307         buildIter(&entry, k);
1308         buildIter(&entry, v);
1309         dbus_message_iter_close_container(&sub, &entry);
1310       }
1311       dbus_message_iter_close_container(iter, &sub);
1312     } else static if(isInstanceOf!(VariantN, T)) {
1313       enforce(arg.hasValue,
1314         new InvalidValueException(arg, "dbus:" ~ cast(char) typeCode!T));
1315 
1316       DBusMessageIter sub;
1317       foreach(AT; T.AllowedTypes) {
1318         if (arg.peek!AT) {
1319           dbus_message_iter_open_container(iter, 'v', typeSig!AT.ptr, &sub);
1320           buildIter(&sub, arg.get!AT);
1321           dbus_message_iter_close_container(iter, &sub);
1322           break;
1323         }
1324       }
1325     } else static if(is(T == DBusAny) || is(T == Variant!DBusAny)) {
1326       static if(is(T == Variant!DBusAny)) {
1327         auto val = arg.data;
1328         val.explicitVariant = true;
1329       } else {
1330         auto val = arg;
1331       }
1332       DBusMessageIter subStore;
1333       DBusMessageIter* sub = &subStore;
1334       const(char)[] sig = [ cast(char) val.type ];
1335       if(val.type == 'a')
1336         sig ~= val.signature;
1337       else if(val.type == 'r')
1338         sig = val.signature;
1339       sig ~= '\0';
1340       if (!val.explicitVariant)
1341         sub = iter;
1342       else
1343         dbus_message_iter_open_container(iter, 'v', sig.ptr, sub);
1344       if(val.type == 's') {
1345         buildIter(sub, val.str);
1346       } else if(val.type == 'o') {
1347         buildIter(sub, val.obj);
1348       } else if(val.type == 'b') {
1349         buildIter(sub,val.boolean);
1350       } else if(dbus_type_is_basic(val.type)) {
1351         dbus_message_iter_append_basic(sub,val.type,&val.int64);
1352       } else if(val.type == 'a') {
1353         DBusMessageIter arr;
1354         dbus_message_iter_open_container(sub, 'a', sig[1 .. $].ptr, &arr);
1355         if (val.signature == ['y'])
1356           foreach (item; val.binaryData)
1357             dbus_message_iter_append_basic(&arr, 'y', &item);
1358         else
1359           foreach(item; val.array)
1360             buildIter(&arr, item);
1361         dbus_message_iter_close_container(sub, &arr);
1362       } else if(val.type == 'r') {
1363         DBusMessageIter arr;
1364         dbus_message_iter_open_container(sub, 'r', null, &arr);
1365         foreach(item; val.tuple)
1366           buildIter(&arr, item);
1367         dbus_message_iter_close_container(sub, &arr);
1368       } else if(val.type == 'e') {
1369         DBusMessageIter entry;
1370         dbus_message_iter_open_container(sub, 'e', null, &entry);
1371         buildIter(&entry, val.entry.key);
1372         buildIter(&entry, val.entry.value);
1373         dbus_message_iter_close_container(sub, &entry);
1374       }
1375       if(val.explicitVariant)
1376         dbus_message_iter_close_container(iter, sub);
1377     } else static if(isInstanceOf!(Variant, T)) {
1378       DBusMessageIter sub;
1379       const(char)* subSig = typeSig!(VariantType!T).toStringz();
1380       dbus_message_iter_open_container(iter, 'v', subSig, &sub);
1381       buildIter(&sub, arg.data);
1382       dbus_message_iter_close_container(iter, &sub);
1383     } else static if(is(T == struct)) {
1384       DBusMessageIter sub;
1385       dbus_message_iter_open_container(iter, 'r', null, &sub);
1386 
1387       // Following failed because of missing 'this' for members of arg.
1388       // That sucks. It worked without Filter.
1389       // Reported: https://issues.dlang.org/show_bug.cgi?id=17692
1390 //    buildIter(&sub, Filter!(isAllowedField, arg.tupleof));
1391 
1392       // Using foreach to work around the issue
1393       foreach(i, member; arg.tupleof) {
1394         // Ugly, but we need to use tupleof again in the condition, because when
1395         // we use `member`, isAllowedField will fail because it'll find this
1396         // nice `buildIter` function instead of T when it looks up the parent
1397         // scope of its argument.
1398         static if (isAllowedField!(arg.tupleof[i]))
1399           buildIter(&sub, member);
1400       }
1401 
1402       dbus_message_iter_close_container(iter, &sub);
1403     } else static if(basicDBus!T) {
1404       dbus_message_iter_append_basic(iter,typeCode!T,&arg);
1405     }
1406   }
1407 }
1408 
1409 T readIter(T)(DBusMessageIter *iter) if (is(T == enum)) {
1410   import std.algorithm.searching : canFind;
1411 
1412   alias OriginalType!T B;
1413 
1414   B value = readIter!B(iter);
1415   enforce(
1416     only(EnumMembers!T).canFind(value),
1417     new InvalidValueException(value, T.stringof)
1418   );
1419   return cast(T) value;
1420 }
1421 
1422 T readIter(T)(DBusMessageIter *iter) if (isInstanceOf!(BitFlags, T)) {
1423   import std.algorithm.iteration : fold;
1424 
1425   alias TemplateArgsOf!T[0] E;
1426   alias OriginalType!E B;
1427 
1428   B mask = only(EnumMembers!E).fold!((a, b) => cast(B) (a | b));
1429 
1430   B value = readIter!B(iter);
1431   enforce(
1432     !(value & ~mask),
1433     new InvalidValueException(value, T.stringof)
1434   );
1435 
1436   return T(cast(E) value);
1437 }
1438 
1439 T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFlags, T) && canDBus!T) {
1440   auto argType = dbus_message_iter_get_arg_type(iter);
1441   T ret;
1442 
1443   static if(!isInstanceOf!(Variant, T) || is(T == Variant!DBusAny)) {
1444     if(argType == 'v') {
1445       DBusMessageIter sub;
1446       dbus_message_iter_recurse(iter, &sub);
1447       static if(is(T == Variant!DBusAny)) {
1448         ret = variant(readIter!DBusAny(&sub));
1449       } else {
1450         ret = readIter!T(&sub);
1451         static if(is(T == DBusAny))
1452           ret.explicitVariant = true;
1453       }
1454       dbus_message_iter_next(iter);
1455       return ret;
1456     }
1457   }
1458 
1459   static if(
1460     !is(T == DBusAny)
1461     && !is(T == Variant!DBusAny)
1462     && !isInstanceOf!(VariantN, T)
1463   ) {
1464     enforce(argType == typeCode!T(),
1465       new TypeMismatchException(typeCode!T(), argType));
1466   }
1467   static if(is(T==string) || is(T==ObjectPath)) {
1468     const(char)* cStr;
1469     dbus_message_iter_get_basic(iter, &cStr);
1470     string str = cStr.fromStringz().idup; // copy string
1471     static if(is(T==string))
1472       ret = str;
1473     else
1474       ret = ObjectPath(str);
1475   } else static if(is(T==bool)) {
1476     dbus_bool_t longerBool;
1477     dbus_message_iter_get_basic(iter, &longerBool);
1478     ret = cast(bool)longerBool;
1479   } else static if(isTuple!T) {
1480     DBusMessageIter sub;
1481     dbus_message_iter_recurse(iter, &sub);
1482     readIterTuple!T(&sub, ret);
1483   } else static if(is(T t : U[], U)) {
1484     assert(dbus_message_iter_get_element_type(iter) == typeCode!U);
1485     DBusMessageIter sub;
1486     dbus_message_iter_recurse(iter, &sub);
1487     while(dbus_message_iter_get_arg_type(&sub) != 0) {
1488       static if(is(U == DictionaryEntry!(K,V), K, V)) {
1489         DBusMessageIter entry;
1490         dbus_message_iter_recurse(&sub, &entry);
1491         ret ~= U(readIter!K(&entry), readIter!V(&entry));
1492         dbus_message_iter_next(&sub);
1493       } else {
1494         ret ~= readIter!U(&sub);
1495       }
1496     }
1497   } else static if(isInstanceOf!(Variant, T)) {
1498     DBusMessageIter sub;
1499     dbus_message_iter_recurse(iter, &sub);
1500     ret.data = readIter!(VariantType!T)(&sub);
1501   } else static if(isInstanceOf!(VariantN, T)) {
1502     scope const(char)[] argSig =
1503       dbus_message_iter_get_signature(iter).fromStringz();
1504     scope(exit)
1505       dbus_free(cast(void*) argSig.ptr);
1506 
1507     foreach(AT; T.AllowedTypes) {
1508       // We have to compare the full signature here, not just the typecode.
1509       // Otherwise, in case of container types, we might select the wrong one.
1510       // We would then be calling an incorrect instance of readIter, which would
1511       // probably throw a TypeMismatchException.
1512       if (typeSig!AT == argSig) {
1513         ret = readIter!AT(iter);
1514         break;
1515       }
1516     }
1517 
1518     // If no value is in ret, apparently none of the types matched.
1519     enforce(ret.hasValue, new TypeMismatchException(typeCode!T, argType));
1520   } else static if(isAssociativeArray!T) {
1521     DBusMessageIter sub;
1522     dbus_message_iter_recurse(iter, &sub);
1523     while(dbus_message_iter_get_arg_type(&sub) != 0) {
1524       DBusMessageIter entry;
1525       dbus_message_iter_recurse(&sub, &entry);
1526       auto k = readIter!(KeyType!T)(&entry);
1527       auto v = readIter!(ValueType!T)(&entry);
1528       ret[k] = v;
1529       dbus_message_iter_next(&sub);
1530     }
1531   } else static if(is(T == DBusAny)) {
1532     ret.type = argType;
1533     ret.explicitVariant = false;
1534     if(ret.type == 's') {
1535       ret.str = readIter!string(iter);
1536       return ret;
1537     } else if(ret.type == 'o') {
1538       ret.obj = readIter!ObjectPath(iter);
1539       return ret;
1540     } else if(ret.type == 'b') {
1541       ret.boolean = readIter!bool(iter);
1542       return ret;
1543     } else if(dbus_type_is_basic(ret.type)) {
1544       dbus_message_iter_get_basic(iter, &ret.int64);
1545     } else if(ret.type == 'a') {
1546       DBusMessageIter sub;
1547       dbus_message_iter_recurse(iter, &sub);
1548       auto sig = dbus_message_iter_get_signature(&sub);
1549       ret.signature = sig.fromStringz.dup;
1550       dbus_free(sig);
1551       if (ret.signature == ['y'])
1552         while(dbus_message_iter_get_arg_type(&sub) != 0) {
1553           ubyte b;
1554           assert(dbus_message_iter_get_arg_type(&sub) == 'y');
1555           dbus_message_iter_get_basic(&sub, &b);
1556           dbus_message_iter_next(&sub);
1557           ret.binaryData ~= b;
1558         }
1559       else
1560         while(dbus_message_iter_get_arg_type(&sub) != 0) {
1561           ret.array ~= readIter!DBusAny(&sub);
1562         }
1563     } else if(ret.type == 'r') {
1564       auto sig = dbus_message_iter_get_signature(iter);
1565       ret.signature = sig.fromStringz.dup;
1566       dbus_free(sig);
1567       DBusMessageIter sub;
1568       dbus_message_iter_recurse(iter, &sub);
1569       while(dbus_message_iter_get_arg_type(&sub) != 0) {
1570         ret.tuple ~= readIter!DBusAny(&sub);
1571       }
1572     } else if(ret.type == 'e') {
1573       DBusMessageIter sub;
1574       dbus_message_iter_recurse(iter, &sub);
1575       ret.entry = new DictionaryEntry!(DBusAny, DBusAny);
1576       ret.entry.key = readIter!DBusAny(&sub);
1577       ret.entry.value = readIter!DBusAny(&sub);
1578     }
1579   } else static if(is(T == struct)) {
1580     DBusMessageIter sub;
1581     dbus_message_iter_recurse(iter, &sub);
1582     readIterStruct!T(&sub, ret);
1583   } else static if(basicDBus!T) {
1584     dbus_message_iter_get_basic(iter, &ret);
1585   }
1586 
1587   dbus_message_iter_next(iter);
1588   return ret;
1589 }
1590 
1591 void readIterTuple(Tup)(DBusMessageIter *iter, ref Tup tuple) if(isTuple!Tup && allCanDBus!(Tup.Types)) {
1592   foreach(index, T; Tup.Types) {
1593     tuple[index] = readIter!T(iter);
1594   }
1595 }
1596 
1597 void readIterStruct(S)(DBusMessageIter *iter, ref S s) if(is(S == struct) && canDBus!S)
1598 {
1599   foreach(index, T; Fields!S) {
1600     static if (isAllowedField!(s.tupleof[index])) {
1601       s.tupleof[index] = readIter!T(iter);
1602     }
1603   }
1604 }
1605 
1606 import core.stdc.config;
1607 import core.stdc.stdarg;
1608 extern (C) {
1609 // START dbus/dbus-arch-deps.d
1610 alias c_long dbus_int64_t;
1611 alias c_ulong dbus_uint64_t;
1612 alias int dbus_int32_t;
1613 alias uint dbus_uint32_t;
1614 alias short dbus_int16_t;
1615 alias ushort dbus_uint16_t;
1616 // END dbus/dbus-arch-deps.d
1617 // START dbus/dbus-types.d
1618 alias uint dbus_unichar_t;
1619 alias uint dbus_bool_t;
1620 
1621 
1622 
1623 struct DBus8ByteStruct
1624 {
1625     dbus_uint32_t first32;
1626     dbus_uint32_t second32;
1627 }
1628 
1629 union DBusBasicValue
1630 {
1631     ubyte[8] bytes;
1632     dbus_int16_t i16;
1633     dbus_uint16_t u16;
1634     dbus_int32_t i32;
1635     dbus_uint32_t u32;
1636     dbus_bool_t bool_val;
1637     dbus_int64_t i64;
1638     dbus_uint64_t u64;
1639     DBus8ByteStruct eight;
1640     double dbl;
1641     ubyte byt;
1642     char* str;
1643     int fd;
1644 }
1645 // END dbus/dbus-types.d
1646 // START dbus/dbus-protocol.d
1647 
1648 // END dbus/dbus-protocol.d
1649 // START dbus/dbus-errors.d
1650 struct DBusError
1651 {
1652     const(char)* name;
1653     const(char)* message;
1654     uint dummy1;
1655     uint dummy2;
1656     uint dummy3;
1657     uint dummy4;
1658     uint dummy5;
1659     void* padding1;
1660 }
1661 
1662 void dbus_error_init (DBusError* error);
1663 void dbus_error_free (DBusError* error);
1664 void dbus_set_error (DBusError* error, const(char)* name, const(char)* message, ...);
1665 void dbus_set_error_const (DBusError* error, const(char)* name, const(char)* message);
1666 void dbus_move_error (DBusError* src, DBusError* dest);
1667 dbus_bool_t dbus_error_has_name (const(DBusError)* error, const(char)* name);
1668 dbus_bool_t dbus_error_is_set (const(DBusError)* error);
1669 // END dbus/dbus-errors.d
1670 // START dbus/dbus-macros.d
1671 
1672 // END dbus/dbus-macros.d
1673 // START dbus/dbus-memory.d
1674 alias void function (void*) DBusFreeFunction;
1675 
1676 void* dbus_malloc (size_t bytes);
1677 void* dbus_malloc0 (size_t bytes);
1678 void* dbus_realloc (void* memory, size_t bytes);
1679 void dbus_free (void* memory);
1680 void dbus_free_string_array (char** str_array);
1681 void dbus_shutdown ();
1682 // END dbus/dbus-memory.d
1683 // START dbus/dbus-shared.d
1684 enum DBusBusType
1685 {
1686     DBUS_BUS_SESSION = 0,
1687     DBUS_BUS_SYSTEM = 1,
1688     DBUS_BUS_STARTER = 2
1689 }
1690 
1691 enum DBusHandlerResult
1692 {
1693     DBUS_HANDLER_RESULT_HANDLED = 0,
1694     DBUS_HANDLER_RESULT_NOT_YET_HANDLED = 1,
1695     DBUS_HANDLER_RESULT_NEED_MEMORY = 2
1696 }
1697 // END dbus/dbus-shared.d
1698 // START dbus/dbus-address.d
1699 struct DBusAddressEntry;
1700 
1701 
1702 dbus_bool_t dbus_parse_address (const(char)* address, DBusAddressEntry*** entry, int* array_len, DBusError* error);
1703 const(char)* dbus_address_entry_get_value (DBusAddressEntry* entry, const(char)* key);
1704 const(char)* dbus_address_entry_get_method (DBusAddressEntry* entry);
1705 void dbus_address_entries_free (DBusAddressEntry** entries);
1706 char* dbus_address_escape_value (const(char)* value);
1707 char* dbus_address_unescape_value (const(char)* value, DBusError* error);
1708 // END dbus/dbus-address.d
1709 // START dbus/dbus-syntax.d
1710 dbus_bool_t dbus_validate_path (const(char)* path, DBusError* error);
1711 dbus_bool_t dbus_validate_interface (const(char)* name, DBusError* error);
1712 dbus_bool_t dbus_validate_member (const(char)* name, DBusError* error);
1713 dbus_bool_t dbus_validate_error_name (const(char)* name, DBusError* error);
1714 dbus_bool_t dbus_validate_bus_name (const(char)* name, DBusError* error);
1715 dbus_bool_t dbus_validate_utf8 (const(char)* alleged_utf8, DBusError* error);
1716 // END dbus/dbus-syntax.d
1717 // START dbus/dbus-signature.d
1718 struct DBusSignatureIter
1719 {
1720     void* dummy1;
1721     void* dummy2;
1722     dbus_uint32_t dummy8;
1723     int dummy12;
1724     int dummy17;
1725 }
1726 
1727 void dbus_signature_iter_init (DBusSignatureIter* iter, const(char)* signature);
1728 int dbus_signature_iter_get_current_type (const(DBusSignatureIter)* iter);
1729 char* dbus_signature_iter_get_signature (const(DBusSignatureIter)* iter);
1730 int dbus_signature_iter_get_element_type (const(DBusSignatureIter)* iter);
1731 dbus_bool_t dbus_signature_iter_next (DBusSignatureIter* iter);
1732 void dbus_signature_iter_recurse (const(DBusSignatureIter)* iter, DBusSignatureIter* subiter);
1733 dbus_bool_t dbus_signature_validate (const(char)* signature, DBusError* error);
1734 dbus_bool_t dbus_signature_validate_single (const(char)* signature, DBusError* error);
1735 dbus_bool_t dbus_type_is_valid (int typecode);
1736 dbus_bool_t dbus_type_is_basic (int typecode);
1737 dbus_bool_t dbus_type_is_container (int typecode);
1738 dbus_bool_t dbus_type_is_fixed (int typecode);
1739 // END dbus/dbus-signature.d
1740 // START dbus/dbus-misc.d
1741 char* dbus_get_local_machine_id ();
1742 void dbus_get_version (int* major_version_p, int* minor_version_p, int* micro_version_p);
1743 dbus_bool_t dbus_setenv (const(char)* variable, const(char)* value);
1744 // END dbus/dbus-misc.d
1745 // START dbus/dbus-threads.d
1746 alias DBusMutex* function () DBusMutexNewFunction;
1747 alias void function (DBusMutex*) DBusMutexFreeFunction;
1748 alias uint function (DBusMutex*) DBusMutexLockFunction;
1749 alias uint function (DBusMutex*) DBusMutexUnlockFunction;
1750 alias DBusMutex* function () DBusRecursiveMutexNewFunction;
1751 alias void function (DBusMutex*) DBusRecursiveMutexFreeFunction;
1752 alias void function (DBusMutex*) DBusRecursiveMutexLockFunction;
1753 alias void function (DBusMutex*) DBusRecursiveMutexUnlockFunction;
1754 alias DBusCondVar* function () DBusCondVarNewFunction;
1755 alias void function (DBusCondVar*) DBusCondVarFreeFunction;
1756 alias void function (DBusCondVar*, DBusMutex*) DBusCondVarWaitFunction;
1757 alias uint function (DBusCondVar*, DBusMutex*, int) DBusCondVarWaitTimeoutFunction;
1758 alias void function (DBusCondVar*) DBusCondVarWakeOneFunction;
1759 alias void function (DBusCondVar*) DBusCondVarWakeAllFunction;
1760 
1761 
1762 
1763 enum DBusThreadFunctionsMask
1764 {
1765     DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK = 1,
1766     DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK = 2,
1767     DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK = 4,
1768     DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK = 8,
1769     DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK = 16,
1770     DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK = 32,
1771     DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK = 64,
1772     DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK = 128,
1773     DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK = 256,
1774     DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK = 512,
1775     DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK = 1024,
1776     DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK = 2048,
1777     DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK = 4096,
1778     DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK = 8192,
1779     DBUS_THREAD_FUNCTIONS_ALL_MASK = 16383
1780 }
1781 
1782 struct DBusThreadFunctions
1783 {
1784     uint mask;
1785     DBusMutexNewFunction mutex_new;
1786     DBusMutexFreeFunction mutex_free;
1787     DBusMutexLockFunction mutex_lock;
1788     DBusMutexUnlockFunction mutex_unlock;
1789     DBusCondVarNewFunction condvar_new;
1790     DBusCondVarFreeFunction condvar_free;
1791     DBusCondVarWaitFunction condvar_wait;
1792     DBusCondVarWaitTimeoutFunction condvar_wait_timeout;
1793     DBusCondVarWakeOneFunction condvar_wake_one;
1794     DBusCondVarWakeAllFunction condvar_wake_all;
1795     DBusRecursiveMutexNewFunction recursive_mutex_new;
1796     DBusRecursiveMutexFreeFunction recursive_mutex_free;
1797     DBusRecursiveMutexLockFunction recursive_mutex_lock;
1798     DBusRecursiveMutexUnlockFunction recursive_mutex_unlock;
1799     void function () padding1;
1800     void function () padding2;
1801     void function () padding3;
1802     void function () padding4;
1803 }
1804 
1805 struct DBusCondVar;
1806 
1807 
1808 struct DBusMutex;
1809 
1810 
1811 dbus_bool_t dbus_threads_init (const(DBusThreadFunctions)* functions);
1812 dbus_bool_t dbus_threads_init_default ();
1813 // END dbus/dbus-threads.d
1814 // START dbus/dbus-message.d
1815 struct DBusMessageIter
1816 {
1817     void* dummy1;
1818     void* dummy2;
1819     dbus_uint32_t dummy3;
1820     int dummy4;
1821     int dummy5;
1822     int dummy6;
1823     int dummy7;
1824     int dummy8;
1825     int dummy9;
1826     int dummy10;
1827     int dummy11;
1828     int pad1;
1829     int pad2;
1830     void* pad3;
1831 }
1832 
1833 struct DBusMessage;
1834 
1835 
1836 DBusMessage* dbus_message_new (int message_type);
1837 DBusMessage* dbus_message_new_method_call (const(char)* bus_name, const(char)* path, const(char)* iface, const(char)* method);
1838 DBusMessage* dbus_message_new_method_return (DBusMessage* method_call);
1839 DBusMessage* dbus_message_new_signal (const(char)* path, const(char)* iface, const(char)* name);
1840 DBusMessage* dbus_message_new_error (DBusMessage* reply_to, const(char)* error_name, const(char)* error_message);
1841 DBusMessage* dbus_message_new_error_printf (DBusMessage* reply_to, const(char)* error_name, const(char)* error_format, ...);
1842 DBusMessage* dbus_message_copy (const(DBusMessage)* message);
1843 DBusMessage* dbus_message_ref (DBusMessage* message);
1844 void dbus_message_unref (DBusMessage* message);
1845 int dbus_message_get_type (DBusMessage* message);
1846 dbus_bool_t dbus_message_set_path (DBusMessage* message, const(char)* object_path);
1847 const(char)* dbus_message_get_path (DBusMessage* message);
1848 dbus_bool_t dbus_message_has_path (DBusMessage* message, const(char)* object_path);
1849 dbus_bool_t dbus_message_set_interface (DBusMessage* message, const(char)* iface);
1850 const(char)* dbus_message_get_interface (DBusMessage* message);
1851 dbus_bool_t dbus_message_has_interface (DBusMessage* message, const(char)* iface);
1852 dbus_bool_t dbus_message_set_member (DBusMessage* message, const(char)* member);
1853 const(char)* dbus_message_get_member (DBusMessage* message);
1854 dbus_bool_t dbus_message_has_member (DBusMessage* message, const(char)* member);
1855 dbus_bool_t dbus_message_set_error_name (DBusMessage* message, const(char)* name);
1856 const(char)* dbus_message_get_error_name (DBusMessage* message);
1857 dbus_bool_t dbus_message_set_destination (DBusMessage* message, const(char)* destination);
1858 const(char)* dbus_message_get_destination (DBusMessage* message);
1859 dbus_bool_t dbus_message_set_sender (DBusMessage* message, const(char)* sender);
1860 const(char)* dbus_message_get_sender (DBusMessage* message);
1861 const(char)* dbus_message_get_signature (DBusMessage* message);
1862 void dbus_message_set_no_reply (DBusMessage* message, dbus_bool_t no_reply);
1863 dbus_bool_t dbus_message_get_no_reply (DBusMessage* message);
1864 dbus_bool_t dbus_message_is_method_call (DBusMessage* message, const(char)* iface, const(char)* method);
1865 dbus_bool_t dbus_message_is_signal (DBusMessage* message, const(char)* iface, const(char)* signal_name);
1866 dbus_bool_t dbus_message_is_error (DBusMessage* message, const(char)* error_name);
1867 dbus_bool_t dbus_message_has_destination (DBusMessage* message, const(char)* bus_name);
1868 dbus_bool_t dbus_message_has_sender (DBusMessage* message, const(char)* unique_bus_name);
1869 dbus_bool_t dbus_message_has_signature (DBusMessage* message, const(char)* signature);
1870 dbus_uint32_t dbus_message_get_serial (DBusMessage* message);
1871 void dbus_message_set_serial (DBusMessage* message, dbus_uint32_t serial);
1872 dbus_bool_t dbus_message_set_reply_serial (DBusMessage* message, dbus_uint32_t reply_serial);
1873 dbus_uint32_t dbus_message_get_reply_serial (DBusMessage* message);
1874 void dbus_message_set_auto_start (DBusMessage* message, dbus_bool_t auto_start);
1875 dbus_bool_t dbus_message_get_auto_start (DBusMessage* message);
1876 dbus_bool_t dbus_message_get_path_decomposed (DBusMessage* message, char*** path);
1877 dbus_bool_t dbus_message_append_args (DBusMessage* message, int first_arg_type, ...);
1878 dbus_bool_t dbus_message_append_args_valist (DBusMessage* message, int first_arg_type, va_list var_args);
1879 dbus_bool_t dbus_message_get_args (DBusMessage* message, DBusError* error, int first_arg_type, ...);
1880 dbus_bool_t dbus_message_get_args_valist (DBusMessage* message, DBusError* error, int first_arg_type, va_list var_args);
1881 dbus_bool_t dbus_message_contains_unix_fds (DBusMessage* message);
1882 dbus_bool_t dbus_message_iter_init (DBusMessage* message, DBusMessageIter* iter);
1883 dbus_bool_t dbus_message_iter_has_next (DBusMessageIter* iter);
1884 dbus_bool_t dbus_message_iter_next (DBusMessageIter* iter);
1885 char* dbus_message_iter_get_signature (DBusMessageIter* iter);
1886 int dbus_message_iter_get_arg_type (DBusMessageIter* iter);
1887 int dbus_message_iter_get_element_type (DBusMessageIter* iter);
1888 void dbus_message_iter_recurse (DBusMessageIter* iter, DBusMessageIter* sub);
1889 void dbus_message_iter_get_basic (DBusMessageIter* iter, void* value);
1890 int dbus_message_iter_get_array_len (DBusMessageIter* iter);
1891 void dbus_message_iter_get_fixed_array (DBusMessageIter* iter, void* value, int* n_elements);
1892 void dbus_message_iter_init_append (DBusMessage* message, DBusMessageIter* iter);
1893 dbus_bool_t dbus_message_iter_append_basic (DBusMessageIter* iter, int type, const(void)* value);
1894 dbus_bool_t dbus_message_iter_append_fixed_array (DBusMessageIter* iter, int element_type, const(void)* value, int n_elements);
1895 dbus_bool_t dbus_message_iter_open_container (DBusMessageIter* iter, int type, const(char)* contained_signature, DBusMessageIter* sub);
1896 dbus_bool_t dbus_message_iter_close_container (DBusMessageIter* iter, DBusMessageIter* sub);
1897 void dbus_message_iter_abandon_container (DBusMessageIter* iter, DBusMessageIter* sub);
1898 void dbus_message_lock (DBusMessage* message);
1899 dbus_bool_t dbus_set_error_from_message (DBusError* error, DBusMessage* message);
1900 dbus_bool_t dbus_message_allocate_data_slot (dbus_int32_t* slot_p);
1901 void dbus_message_free_data_slot (dbus_int32_t* slot_p);
1902 dbus_bool_t dbus_message_set_data (DBusMessage* message, dbus_int32_t slot, void* data, DBusFreeFunction free_data_func);
1903 void* dbus_message_get_data (DBusMessage* message, dbus_int32_t slot);
1904 int dbus_message_type_from_string (const(char)* type_str);
1905 const(char)* dbus_message_type_to_string (int type);
1906 dbus_bool_t dbus_message_marshal (DBusMessage* msg, char** marshalled_data_p, int* len_p);
1907 DBusMessage* dbus_message_demarshal (const(char)* str, int len, DBusError* error);
1908 int dbus_message_demarshal_bytes_needed (const(char)* str, int len);
1909 // END dbus/dbus-message.d
1910 // START dbus/dbus-connection.d
1911 alias uint function (DBusWatch*, void*) DBusAddWatchFunction;
1912 alias void function (DBusWatch*, void*) DBusWatchToggledFunction;
1913 alias void function (DBusWatch*, void*) DBusRemoveWatchFunction;
1914 alias uint function (DBusTimeout*, void*) DBusAddTimeoutFunction;
1915 alias void function (DBusTimeout*, void*) DBusTimeoutToggledFunction;
1916 alias void function (DBusTimeout*, void*) DBusRemoveTimeoutFunction;
1917 alias void function (DBusConnection*, DBusDispatchStatus, void*) DBusDispatchStatusFunction;
1918 alias void function (void*) DBusWakeupMainFunction;
1919 alias uint function (DBusConnection*, c_ulong, void*) DBusAllowUnixUserFunction;
1920 alias uint function (DBusConnection*, const(char)*, void*) DBusAllowWindowsUserFunction;
1921 alias void function (DBusPendingCall*, void*) DBusPendingCallNotifyFunction;
1922 alias DBusHandlerResult function (DBusConnection*, DBusMessage*, void*) DBusHandleMessageFunction;
1923 alias void function (DBusConnection*, void*) DBusObjectPathUnregisterFunction;
1924 alias DBusHandlerResult function (DBusConnection*, DBusMessage*, void*) DBusObjectPathMessageFunction;
1925 
1926 enum DBusWatchFlags
1927 {
1928     DBUS_WATCH_READABLE = 1,
1929     DBUS_WATCH_WRITABLE = 2,
1930     DBUS_WATCH_ERROR = 4,
1931     DBUS_WATCH_HANGUP = 8
1932 }
1933 
1934 enum DBusDispatchStatus
1935 {
1936     DBUS_DISPATCH_DATA_REMAINS = 0,
1937     DBUS_DISPATCH_COMPLETE = 1,
1938     DBUS_DISPATCH_NEED_MEMORY = 2
1939 }
1940 
1941 struct DBusObjectPathVTable
1942 {
1943     DBusObjectPathUnregisterFunction unregister_function;
1944     DBusObjectPathMessageFunction message_function;
1945     void function (void*) dbus_internal_pad1;
1946     void function (void*) dbus_internal_pad2;
1947     void function (void*) dbus_internal_pad3;
1948     void function (void*) dbus_internal_pad4;
1949 }
1950 
1951 struct DBusPreallocatedSend;
1952 
1953 
1954 struct DBusTimeout;
1955 
1956 
1957 struct DBusPendingCall;
1958 
1959 
1960 struct DBusConnection;
1961 
1962 
1963 struct DBusWatch;
1964 
1965 
1966 DBusConnection* dbus_connection_open (const(char)* address, DBusError* error);
1967 DBusConnection* dbus_connection_open_private (const(char)* address, DBusError* error);
1968 DBusConnection* dbus_connection_ref (DBusConnection* connection);
1969 void dbus_connection_unref (DBusConnection* connection);
1970 void dbus_connection_close (DBusConnection* connection);
1971 dbus_bool_t dbus_connection_get_is_connected (DBusConnection* connection);
1972 dbus_bool_t dbus_connection_get_is_authenticated (DBusConnection* connection);
1973 dbus_bool_t dbus_connection_get_is_anonymous (DBusConnection* connection);
1974 char* dbus_connection_get_server_id (DBusConnection* connection);
1975 dbus_bool_t dbus_connection_can_send_type (DBusConnection* connection, int type);
1976 void dbus_connection_set_exit_on_disconnect (DBusConnection* connection, dbus_bool_t exit_on_disconnect);
1977 void dbus_connection_flush (DBusConnection* connection);
1978 dbus_bool_t dbus_connection_read_write_dispatch (DBusConnection* connection, int timeout_milliseconds);
1979 dbus_bool_t dbus_connection_read_write (DBusConnection* connection, int timeout_milliseconds);
1980 DBusMessage* dbus_connection_borrow_message (DBusConnection* connection);
1981 void dbus_connection_return_message (DBusConnection* connection, DBusMessage* message);
1982 void dbus_connection_steal_borrowed_message (DBusConnection* connection, DBusMessage* message);
1983 DBusMessage* dbus_connection_pop_message (DBusConnection* connection);
1984 DBusDispatchStatus dbus_connection_get_dispatch_status (DBusConnection* connection);
1985 DBusDispatchStatus dbus_connection_dispatch (DBusConnection* connection);
1986 dbus_bool_t dbus_connection_has_messages_to_send (DBusConnection* connection);
1987 dbus_bool_t dbus_connection_send (DBusConnection* connection, DBusMessage* message, dbus_uint32_t* client_serial);
1988 dbus_bool_t dbus_connection_send_with_reply (DBusConnection* connection, DBusMessage* message, DBusPendingCall** pending_return, int timeout_milliseconds);
1989 DBusMessage* dbus_connection_send_with_reply_and_block (DBusConnection* connection, DBusMessage* message, int timeout_milliseconds, DBusError* error);
1990 dbus_bool_t dbus_connection_set_watch_functions (DBusConnection* connection, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void* data, DBusFreeFunction free_data_function);
1991 dbus_bool_t dbus_connection_set_timeout_functions (DBusConnection* connection, DBusAddTimeoutFunction add_function, DBusRemoveTimeoutFunction remove_function, DBusTimeoutToggledFunction toggled_function, void* data, DBusFreeFunction free_data_function);
1992 void dbus_connection_set_wakeup_main_function (DBusConnection* connection, DBusWakeupMainFunction wakeup_main_function, void* data, DBusFreeFunction free_data_function);
1993 void dbus_connection_set_dispatch_status_function (DBusConnection* connection, DBusDispatchStatusFunction function_, void* data, DBusFreeFunction free_data_function);
1994 dbus_bool_t dbus_connection_get_unix_user (DBusConnection* connection, c_ulong* uid);
1995 dbus_bool_t dbus_connection_get_unix_process_id (DBusConnection* connection, c_ulong* pid);
1996 dbus_bool_t dbus_connection_get_adt_audit_session_data (DBusConnection* connection, void** data, dbus_int32_t* data_size);
1997 void dbus_connection_set_unix_user_function (DBusConnection* connection, DBusAllowUnixUserFunction function_, void* data, DBusFreeFunction free_data_function);
1998 dbus_bool_t dbus_connection_get_windows_user (DBusConnection* connection, char** windows_sid_p);
1999 void dbus_connection_set_windows_user_function (DBusConnection* connection, DBusAllowWindowsUserFunction function_, void* data, DBusFreeFunction free_data_function);
2000 void dbus_connection_set_allow_anonymous (DBusConnection* connection, dbus_bool_t value);
2001 void dbus_connection_set_route_peer_messages (DBusConnection* connection, dbus_bool_t value);
2002 dbus_bool_t dbus_connection_add_filter (DBusConnection* connection, DBusHandleMessageFunction function_, void* user_data, DBusFreeFunction free_data_function);
2003 void dbus_connection_remove_filter (DBusConnection* connection, DBusHandleMessageFunction function_, void* user_data);
2004 dbus_bool_t dbus_connection_allocate_data_slot (dbus_int32_t* slot_p);
2005 void dbus_connection_free_data_slot (dbus_int32_t* slot_p);
2006 dbus_bool_t dbus_connection_set_data (DBusConnection* connection, dbus_int32_t slot, void* data, DBusFreeFunction free_data_func);
2007 void* dbus_connection_get_data (DBusConnection* connection, dbus_int32_t slot);
2008 void dbus_connection_set_change_sigpipe (dbus_bool_t will_modify_sigpipe);
2009 void dbus_connection_set_max_message_size (DBusConnection* connection, c_long size);
2010 c_long dbus_connection_get_max_message_size (DBusConnection* connection);
2011 void dbus_connection_set_max_received_size (DBusConnection* connection, c_long size);
2012 c_long dbus_connection_get_max_received_size (DBusConnection* connection);
2013 void dbus_connection_set_max_message_unix_fds (DBusConnection* connection, c_long n);
2014 c_long dbus_connection_get_max_message_unix_fds (DBusConnection* connection);
2015 void dbus_connection_set_max_received_unix_fds (DBusConnection* connection, c_long n);
2016 c_long dbus_connection_get_max_received_unix_fds (DBusConnection* connection);
2017 c_long dbus_connection_get_outgoing_size (DBusConnection* connection);
2018 c_long dbus_connection_get_outgoing_unix_fds (DBusConnection* connection);
2019 DBusPreallocatedSend* dbus_connection_preallocate_send (DBusConnection* connection);
2020 void dbus_connection_free_preallocated_send (DBusConnection* connection, DBusPreallocatedSend* preallocated);
2021 void dbus_connection_send_preallocated (DBusConnection* connection, DBusPreallocatedSend* preallocated, DBusMessage* message, dbus_uint32_t* client_serial);
2022 dbus_bool_t dbus_connection_try_register_object_path (DBusConnection* connection, const(char)* path, const(DBusObjectPathVTable)* vtable, void* user_data, DBusError* error);
2023 dbus_bool_t dbus_connection_register_object_path (DBusConnection* connection, const(char)* path, const(DBusObjectPathVTable)* vtable, void* user_data);
2024 dbus_bool_t dbus_connection_try_register_fallback (DBusConnection* connection, const(char)* path, const(DBusObjectPathVTable)* vtable, void* user_data, DBusError* error);
2025 dbus_bool_t dbus_connection_register_fallback (DBusConnection* connection, const(char)* path, const(DBusObjectPathVTable)* vtable, void* user_data);
2026 dbus_bool_t dbus_connection_unregister_object_path (DBusConnection* connection, const(char)* path);
2027 dbus_bool_t dbus_connection_get_object_path_data (DBusConnection* connection, const(char)* path, void** data_p);
2028 dbus_bool_t dbus_connection_list_registered (DBusConnection* connection, const(char)* parent_path, char*** child_entries);
2029 dbus_bool_t dbus_connection_get_unix_fd (DBusConnection* connection, int* fd);
2030 dbus_bool_t dbus_connection_get_socket (DBusConnection* connection, int* fd);
2031 int dbus_watch_get_fd (DBusWatch* watch);
2032 int dbus_watch_get_unix_fd (DBusWatch* watch);
2033 int dbus_watch_get_socket (DBusWatch* watch);
2034 uint dbus_watch_get_flags (DBusWatch* watch);
2035 void* dbus_watch_get_data (DBusWatch* watch);
2036 void dbus_watch_set_data (DBusWatch* watch, void* data, DBusFreeFunction free_data_function);
2037 dbus_bool_t dbus_watch_handle (DBusWatch* watch, uint flags);
2038 dbus_bool_t dbus_watch_get_enabled (DBusWatch* watch);
2039 int dbus_timeout_get_interval (DBusTimeout* timeout);
2040 void* dbus_timeout_get_data (DBusTimeout* timeout);
2041 void dbus_timeout_set_data (DBusTimeout* timeout, void* data, DBusFreeFunction free_data_function);
2042 dbus_bool_t dbus_timeout_handle (DBusTimeout* timeout);
2043 dbus_bool_t dbus_timeout_get_enabled (DBusTimeout* timeout);
2044 // END dbus/dbus-connection.d
2045 // START dbus/dbus-pending-call.d
2046 DBusPendingCall* dbus_pending_call_ref (DBusPendingCall* pending);
2047 void dbus_pending_call_unref (DBusPendingCall* pending);
2048 dbus_bool_t dbus_pending_call_set_notify (DBusPendingCall* pending, DBusPendingCallNotifyFunction function_, void* user_data, DBusFreeFunction free_user_data);
2049 void dbus_pending_call_cancel (DBusPendingCall* pending);
2050 dbus_bool_t dbus_pending_call_get_completed (DBusPendingCall* pending);
2051 DBusMessage* dbus_pending_call_steal_reply (DBusPendingCall* pending);
2052 void dbus_pending_call_block (DBusPendingCall* pending);
2053 dbus_bool_t dbus_pending_call_allocate_data_slot (dbus_int32_t* slot_p);
2054 void dbus_pending_call_free_data_slot (dbus_int32_t* slot_p);
2055 dbus_bool_t dbus_pending_call_set_data (DBusPendingCall* pending, dbus_int32_t slot, void* data, DBusFreeFunction free_data_func);
2056 void* dbus_pending_call_get_data (DBusPendingCall* pending, dbus_int32_t slot);
2057 // END dbus/dbus-pending-call.d
2058 // START dbus/dbus-server.d
2059 alias void function (DBusServer*, DBusConnection*, void*) DBusNewConnectionFunction;
2060 
2061 struct DBusServer;
2062 
2063 
2064 DBusServer* dbus_server_listen (const(char)* address, DBusError* error);
2065 DBusServer* dbus_server_ref (DBusServer* server);
2066 void dbus_server_unref (DBusServer* server);
2067 void dbus_server_disconnect (DBusServer* server);
2068 dbus_bool_t dbus_server_get_is_connected (DBusServer* server);
2069 char* dbus_server_get_address (DBusServer* server);
2070 char* dbus_server_get_id (DBusServer* server);
2071 void dbus_server_set_new_connection_function (DBusServer* server, DBusNewConnectionFunction function_, void* data, DBusFreeFunction free_data_function);
2072 dbus_bool_t dbus_server_set_watch_functions (DBusServer* server, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void* data, DBusFreeFunction free_data_function);
2073 dbus_bool_t dbus_server_set_timeout_functions (DBusServer* server, DBusAddTimeoutFunction add_function, DBusRemoveTimeoutFunction remove_function, DBusTimeoutToggledFunction toggled_function, void* data, DBusFreeFunction free_data_function);
2074 dbus_bool_t dbus_server_set_auth_mechanisms (DBusServer* server, const(char*)* mechanisms);
2075 dbus_bool_t dbus_server_allocate_data_slot (dbus_int32_t* slot_p);
2076 void dbus_server_free_data_slot (dbus_int32_t* slot_p);
2077 dbus_bool_t dbus_server_set_data (DBusServer* server, int slot, void* data, DBusFreeFunction free_data_func);
2078 void* dbus_server_get_data (DBusServer* server, int slot);
2079 // END dbus/dbus-server.d
2080 // START dbus/dbus-bus.d
2081 DBusConnection* dbus_bus_get (DBusBusType type, DBusError* error);
2082 DBusConnection* dbus_bus_get_private (DBusBusType type, DBusError* error);
2083 dbus_bool_t dbus_bus_register (DBusConnection* connection, DBusError* error);
2084 dbus_bool_t dbus_bus_set_unique_name (DBusConnection* connection, const(char)* unique_name);
2085 const(char)* dbus_bus_get_unique_name (DBusConnection* connection);
2086 c_ulong dbus_bus_get_unix_user (DBusConnection* connection, const(char)* name, DBusError* error);
2087 char* dbus_bus_get_id (DBusConnection* connection, DBusError* error);
2088 int dbus_bus_request_name (DBusConnection* connection, const(char)* name, uint flags, DBusError* error);
2089 int dbus_bus_release_name (DBusConnection* connection, const(char)* name, DBusError* error);
2090 dbus_bool_t dbus_bus_name_has_owner (DBusConnection* connection, const(char)* name, DBusError* error);
2091 dbus_bool_t dbus_bus_start_service_by_name (DBusConnection* connection, const(char)* name, dbus_uint32_t flags, dbus_uint32_t* reply, DBusError* error);
2092 void dbus_bus_add_match (DBusConnection* connection, const(char)* rule, DBusError* error);
2093 void dbus_bus_remove_match (DBusConnection* connection, const(char)* rule, DBusError* error);
2094 // END dbus/dbus-bus.d
2095 // START dbus/dbus.d
2096 
2097 // END dbus/dbus.d
2098 }
2099 
2100 
2101 enum BusService = "org.freedesktop.DBus";
2102 enum BusPath = "/org/freedesktop/DBus";
2103 enum BusInterface = "org.freedesktop.DBus";
2104 
2105 enum NameFlags {
2106   AllowReplace = 1, ReplaceExisting = 2, NoQueue = 4
2107 }
2108 
2109 /// Requests a DBus well-known name.
2110 /// returns if the name is owned after the call.
2111 /// Involves blocking call on a DBus method, may throw an exception on failure.
2112 bool requestName(Connection conn, string name,
2113                  NameFlags flags = NameFlags.NoQueue | NameFlags.AllowReplace) {
2114   auto msg = Message(BusService,BusPath,BusInterface,"RequestName");
2115   msg.build(name,cast(uint)(flags));
2116   auto res = conn.sendWithReplyBlocking(msg).to!uint;
2117   return (res == 1) || (res == 4);
2118 }
2119 
2120 /// A simple main loop that isn't necessarily efficient
2121 /// and isn't guaranteed to work with other tasks and threads.
2122 /// Use only for apps that only do DBus triggered things.
2123 void simpleMainLoop(Connection conn) {
2124   while(dbus_connection_read_write_dispatch(conn.conn, -1)) {} // empty loop body
2125 }
2126 
2127 /// Single tick in the DBus connection which can be used for
2128 /// concurrent updates.
2129 bool tick(Connection conn) {
2130   return cast(bool) dbus_connection_read_write_dispatch(conn.conn, 0);
2131 }
2132 
2133 
Suggestion Box / Bug Report