diff dbus-d/dsrc/org/freedesktop/dbus/DBus.d @ 0:a5576806d36d

recreate repository without any libs for lightweight repository
author Frank Benoit <benoit@tionex.de>
date Sat, 20 Oct 2007 18:07:18 +0200
parents
children 7c2c75740370
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dbus-d/dsrc/org/freedesktop/dbus/DBus.d	Sat Oct 20 18:07:18 2007 +0200
@@ -0,0 +1,1107 @@
+/*
+ * Copyright (C) 2007  Frank Benoit
+ *
+ * Licensed under the Academic Free License version 2.1
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+module org.freedesktop.dbus.DBus;
+
+import tango.io.Stdout;
+import tango.core.Exception;
+import tango.core.Thread;
+import tango.core.Traits;
+import tango.text.convert.Integer;
+import tango.text.Util;
+
+public import tango.stdc.stringz : fromUtf8z;
+//public import tango.core.Tuple;
+//public import org.freedesktop.dbus.DBusInterface;
+
+import org.freedesktop.dbus.c.Connection;
+import org.freedesktop.dbus.c.Errors;
+import org.freedesktop.dbus.c.Message;
+import org.freedesktop.dbus.c.Bus;
+import org.freedesktop.dbus.c.PendingCall;
+import org.freedesktop.dbus.c.Shared;
+import org.freedesktop.dbus.c.Protocol;
+import org.freedesktop.dbus.c.Types;
+import org.freedesktop.dbus.c.Memory : dbus_free;
+import org.freedesktop.dbus.Struct;
+import org.freedesktop.dbus.Variant;
+
+//version=CD;
+
+typedef char[] DBusObjPath;
+typedef char[] DBusSignature;
+
+private void notImplemented( char[] msg = null ){
+    throw new TracedException( "not yet implemented " ~ msg );
+}
+
+private void ensure( bool cond, char[][] msg ... ){
+    if( !cond ){
+        char[200] buf;
+        char[] formattedMsg = layout( buf, msg );
+        throw new TracedException( "ensure failed: "~formattedMsg );
+    }
+}
+
+private void ensureDBus( dbus_bool_t cond ){
+    if( !cond ){
+        throw new TracedException( "ensureDBus" );
+    }
+}
+
+
+alias DBusHandlerResult
+    function(
+        DBusConnection* conn,
+        DBusMessage* message,
+        void* user_data )
+    DBusHandler;
+
+
+char[]     [ ClassInfo ] registeredIntrospectionData;
+DBusHandler[ ClassInfo ] registeredHandlers;
+
+public void registerIntrospectionData( ClassInfo ci, char[] data ){
+    registeredIntrospectionData[ ci ] = data;
+}
+public void registerHandler( ClassInfo ci, DBusHandler handler ){
+    registeredHandlers[ ci ] = handler;
+}
+
+public class DBusObjectImpl {
+	static uint sInstCounter = 0;
+	char[] instName;
+	this(){
+		//Stdout.formatln( "DBusObject ctor" );
+		int cnt;
+		synchronized{
+			cnt = sInstCounter++;
+		}
+		instName = '/' ~ replace( this.classinfo.name.dup, '.', '/' ) ~ '/'  ~ .toUtf8( cnt );
+		//Stdout.formatln( "DBusObject instname={}", instName );
+	}
+
+	public char[] getDBusInstanceName(){
+		return instName;
+	}
+
+    public char[] Introspect(){
+        char[] res = "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
+        "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
+        "<node>\n";
+        bool[ ClassInfo ] all;
+        void appendInterfaces( Interface[] intfs ){
+            foreach( intf; intfs ){
+                if( intf.classinfo.interfaces.length > 0 ){
+                    appendInterfaces( intf.classinfo.interfaces );
+                }
+                all[ intf.classinfo ] = true;
+            }
+        }
+        appendInterfaces( this.classinfo.interfaces );
+        foreach( intf; all.keys ){
+            char[]* intro = intf in registeredIntrospectionData;
+            if( intro !is null ){
+                res ~= *intro;
+            }
+        }
+        DBusObjectImpl[] childs = getChildNodes();
+        foreach( child; childs ){
+            res ~= "  <node name=\""~child.instName~"\"/>\n";
+        }
+        res ~= "</node>\n";
+        //Stdout.formatln( "DBus.d:{} Introspect: {}", __LINE__, res );
+        return res;
+    }
+
+    public DBusObjectImpl[] getChildNodes(){
+        return null;
+    }
+
+    private static extern(C) DBusHandlerResult VTableMessageFunction(
+        DBusConnection* conn,
+        DBusMessage* message,
+        void* user_data )
+    {
+        char[METHOD_SIG_MAXLENGTH] buf;
+        DBusObjectImpl o = cast(DBusObjectImpl)cast(Object)user_data;
+
+        // find all interfaces ...
+        bool[ ClassInfo ] all;
+        void findAllInterfaces( Interface[] intfs ){
+            foreach( intf; intfs ){
+                findAllInterfaces( intf.classinfo.interfaces );
+                all[ intf.classinfo ] = true;
+            }
+        }
+        ClassInfo oci = o.classinfo;
+        do{
+            findAllInterfaces( oci.interfaces );
+            oci = oci.base;
+        } while( oci !is null );
+
+        // call all existing handlers until message handled
+        foreach( intf; all.keys ){
+            DBusHandler* handler = intf in registeredHandlers;
+            if( handler !is null ){
+                DBusHandlerResult res =
+                    (*handler)( conn, message, user_data );
+                if( res == DBusHandlerResult.DBUS_HANDLER_RESULT_HANDLED ){
+                    return DBusHandlerResult.DBUS_HANDLER_RESULT_HANDLED;
+                }
+            }
+        }
+        return DBusHandlerResult.DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+    private static extern(C) void VTableUnregisterFunction(
+        DBusConnection  *connection,
+        void* user_data )
+    {
+        DBusObjectImpl o = cast(DBusObjectImpl)cast(Object)user_data;
+        objectLocker.remove( o );
+    }
+
+    private static DBusObjectPathVTable dbusObjectPathVTable = {
+        message_function    : & VTableMessageFunction,
+        unregister_function : & VTableUnregisterFunction
+    };
+
+ 	public void   registerDBusObject( DBusConnection * conn ){
+ 		ensureDBus( dbus_connection_register_object_path(
+         		conn,
+         		XtoUtf8z( getDBusInstanceName() ),
+         		& dbusObjectPathVTable,
+ 	        	cast(void*)cast(Object)this ));
+ 	    objectLocker[ this ] = true;
+ 	}
+
+}
+
+bool[ DBusObjectImpl ] objectLocker;
+
+
+class DBusConnectionImpl {
+	DBusConnection* conn;
+	
+	public this( char[] addr ){
+		DBusError err;
+		int trial = 0;
+		while( true ){
+			trial++;
+			dbus_error_init(&err);
+
+			scope(exit) 
+				if( dbus_error_is_set(&err) ){
+					dbus_error_free(&err);
+				}
+			
+			conn = dbus_connection_open_private( XtoUtf8z(addr), & err );
+			
+			if( !dbus_error_is_set(&err) && conn !is null ){
+				return;
+			}
+			if( trial > 10 ){
+				if( dbus_error_is_set(&err) ){
+					Stdout.formatln( "Connect Error ({})\n", fromUtf8z( err.message)); 
+					throw new Exception("");
+				}
+				if( conn is null ){
+					throw new IOException("connecting not successful");
+				}
+			}
+			else{
+				Thread.sleep( 0.1 );
+			}
+		}
+	}
+	
+/+	public DBusInterface getRemoteObject( char[] path ){
+		return null;
+	}+/
+	public void mainLoop(){
+		//Stdout.formatln( "   D mainloop starting" );
+		while (dbus_connection_read_write_dispatch (conn, -1)){
+			//Stdout.formatln( "   D mainloop" );
+     			// empty loop body
+		}
+		//Stdout.formatln( "   D mainloop stop" );
+		return;
+
+		DBusError err;
+		dbus_error_init(&err);
+		//CBus.dbus_bus_request_name(conn, XtoUtf8z("test.method.caller"), DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
+		if( dbus_error_is_set(&err) ){
+			Stdout.formatln( "Name Error ({})\n", fromUtf8z( err.message)); 
+      			dbus_error_free(&err);
+      			throw new Exception("");
+		}
+	}
+	public void disconnect(){
+		if( conn !is null ){
+			dbus_connection_close( conn );
+		}
+	}
+}
+
+class DirectConnection : DBusConnectionImpl {
+	public this(  char[] addr  ){
+		super( addr );
+	}
+}
+
+
+
+class DBusExecutionException : TracedException {
+	public this( char[] msg ){
+		super( msg );
+	}
+}
+
+template isDBusSimpleType(T){
+    const bool isDBusSimpleType =
+        is( T == bool   ) ||
+        is( T == byte   ) ||
+        is( T == short  ) ||
+        is( T == ushort ) ||
+        is( T == int    ) ||
+        is( T == uint   ) ||
+        is( T == long   ) ||
+        is( T == ulong  ) ||
+        is( T == double );
+}
+
+
+private void getCallValue( T )( DBusMessageIter* iter, out T t ){
+    version(CD) pragma( msg, "getCallValue: "~T.stringof );
+
+    void testType( int type ){
+        int expected = dbus_message_iter_get_arg_type( iter );
+        ensure( expected == type, "getCallType(%0) type does not match %1 '%2' !=  %3 '%4'", T.stringof, toUtf8(type), [cast(char)type], toUtf8(expected), [cast(char)expected] );
+    }
+
+    static if( false ){}
+    else static if( isAssocArrayType!(T) ){
+        version(CD) pragma( msg, "getCallValue: assic "~typeof(T).stringof );
+        testType( DBUS_TYPE_ARRAY );
+        DBusMessageIter sub;
+        dbus_message_iter_recurse( iter, &sub );
+        dbus_message_iter_next( iter );
+
+        typeof(T.keys  [0]) key;
+        typeof(T.values[0]) value;
+        while( dbus_message_iter_get_arg_type( &sub ) != DBUS_TYPE_INVALID ){
+            ensure( dbus_message_iter_get_arg_type( &sub ) == DBUS_TYPE_DICT_ENTRY, "getCallType type does not match for Assoc" );
+            DBusMessageIter entry;
+            dbus_message_iter_recurse( &sub, &entry );
+            dbus_message_iter_next( &sub );
+
+            getCallValue( &entry, key );
+            getCallValue( &entry, value );
+            t[ key ] = value;
+        }
+    }
+    else static if( is( T == char[] )){ // char[] nicht als dyn array, sondern als String
+        testType( DBUS_TYPE_STRING );
+        char* ptr;
+        dbus_message_iter_get_basic( iter, & ptr );
+        dbus_message_iter_next( iter );
+        t = fromUtf8z( ptr );
+    }
+    else static if( isDynamicArrayType!(T) ){
+        testType( DBUS_TYPE_ARRAY );
+        DBusMessageIter sub;
+        dbus_message_iter_recurse( iter, &sub );
+        dbus_message_iter_next( iter );
+        static if( is( typeof(T[0]) == bool )) {
+            version(CD) pragma( msg, "getCallValue: basic type "~typeof(T[0]).stringof );
+            if( dbus_message_iter_get_arg_type( &sub ) != DBUS_TYPE_INVALID ){
+                // special processing because of dbus bools are 4bytes vs. D bool is 1byte.
+                dbus_bool_t* ptr;
+                int n_elements;
+                dbus_message_iter_get_fixed_array( & sub, &ptr, & n_elements );
+                t.length = n_elements;
+                foreach( idx, v; ptr[ 0 .. n_elements ] ){
+                    t[ idx ] = ( v != 0 );
+                }
+            }
+        }
+        else static if( isDBusSimpleType!( typeof(T[0]) )) {
+            version(CD) pragma( msg, "getCallValue: basic type "~typeof(T[0]).stringof );
+            if( dbus_message_iter_get_arg_type( &sub ) != DBUS_TYPE_INVALID ){
+                typeof(T[0])* ptr;
+                int n_elements;
+                dbus_message_iter_get_fixed_array( & sub, &ptr, & n_elements );
+                t = ptr[ 0 .. n_elements ].dup;
+            }
+        }
+        else{
+            version(CD) pragma( msg, "getCallValue: composed type "~typeof(T[0]).stringof );
+            uint idx = 0;
+            while( dbus_message_iter_get_arg_type( &sub ) != DBUS_TYPE_INVALID ){
+                t.length = t.length +1;
+                getCallValue( &sub, t[idx] );
+                // dbus_message_iter_next( &sub ) : is done in getCallValue for element.
+                idx++;
+            }
+        }
+    }
+    else static if( isDBusSimpleType!(T) ) {
+        testType( DBusTypeIdFromDType!(T) );
+        dbus_message_iter_get_basic( iter, & t );
+        dbus_message_iter_next( iter );
+    }
+    else static if( is( T : DBusObjectImpl )){
+        testType( DBusTypeIdFromDType!(T) );
+        static assert( false );
+    }
+    else static if( is( T == DBusVariant ) ){
+        DBusMessageIter sub;
+        dbus_message_iter_recurse( iter, &sub );
+        dbus_message_iter_next( iter );
+        char* sig = dbus_message_iter_get_signature( &sub );
+        scope(exit) dbus_free( sig );
+        char[] sigText = fromUtf8z( sig );
+        t = createDBusVariant( &sub, sigText );
+    }
+    else static if( is( T == Struct!(typeof(T.t)) ) ){
+        // Stdout.formatln( "DBus getCallValue {}", __LINE__ );
+        DBusMessageIter sub;
+        dbus_message_iter_recurse( iter, &sub );
+        dbus_message_iter_next( iter );
+        foreach( idx, el; t.t ){
+            getCallValue( & sub, t.t[idx] );
+        }
+    }
+    else{
+        pragma( msg, "getCallValue: "~typeof(t).stringof );
+        static assert(false, typeof(t).stringof );
+    }
+}
+
+public Struct!(T) getCallValues( T... )( DBusMessage* message ){
+    version(CD) pragma( msg, "getCallValues: "~T.stringof );
+    Struct!(T) res;
+    DBusMessageIter args;
+    dbus_message_iter_init( message, &args);
+    foreach( idx, t; T ){
+        getCallValue( &args, res.t[idx] );
+    }
+    return res;
+}
+
+
+private void _appendMsgParam( DBusMessageIter* iter, int type, void* ptr ){
+	if ( !dbus_message_iter_append_basic( iter, type, ptr ) ) {
+		throw new TracedException( "Cannot append argument to iterator" );
+	}
+}
+
+
+void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, bool value ){
+    dbus_bool_t val = value;
+    _appendMsgParam( iter, DBUS_TYPE_BOOLEAN, &val );
+}
+void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, byte value ){
+    dbus_bool_t val = value;
+    _appendMsgParam( iter, DBUS_TYPE_BYTE, &val );
+}
+void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, short value ){
+    dbus_int16_t val = value;
+    _appendMsgParam( iter, DBUS_TYPE_INT16, &val );
+}
+void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, ushort value ){
+    dbus_uint16_t val = value;
+    _appendMsgParam( iter, DBUS_TYPE_UINT16, &val );
+}
+void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, int value ){
+    dbus_int32_t val = value;
+    _appendMsgParam( iter, DBUS_TYPE_INT32, &val );
+}
+void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, uint value ){
+    dbus_int32_t val = value;
+    _appendMsgParam( iter, DBUS_TYPE_UINT32, &val );
+}
+void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, long value ){
+    dbus_int64_t val = value;
+    _appendMsgParam( iter, DBUS_TYPE_INT64, &val );
+}
+void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, ulong value ){
+    dbus_uint64_t val = value;
+    _appendMsgParam( iter, DBUS_TYPE_UINT64, &val );
+}
+void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, double value ){
+    double val = value;
+    _appendMsgParam( iter, DBUS_TYPE_DOUBLE, &val );
+}
+
+
+
+private const char[] nullChar = "\0";
+char* XtoUtf8z (char[] s) {
+  if (s.length == 0)
+    return nullChar.ptr;
+  if (s[$-1] == '\0')
+    return s.ptr;
+  s ~= '\0';
+  return s.ptr;
+}
+
+void appendMsgParam( DBusConnection* conn, DBusMessageIter* iter, char[] value ){
+    //toUtf8z( value ); // toUtf8z return null for a null char[], but a valid ptr is needed.
+    char* val = XtoUtf8z( value );
+    _appendMsgParam( iter, DBUS_TYPE_STRING, &val );
+}
+
+void appendMsgParamObject( DBusConnection* conn, DBusMessageIter* iter, DBusObjectImpl value ){
+    value.registerDBusObject( conn );
+    char* path = XtoUtf8z( value.getDBusInstanceName());
+    _appendMsgParam( iter, DBUS_TYPE_OBJECT_PATH, &path );
+}
+
+void appendMsgParamVariant( DBusConnection* conn, DBusMessageIter* iter, DBusVariant value ){
+    DBusMessageIter sub;
+    ensureDBus( dbus_message_iter_open_container( iter, DBUS_TYPE_VARIANT, XtoUtf8z( value.getSig() ), &sub ));
+    if( DBusVariantValueBool v = cast(DBusVariantValueBool)value ){
+        appendMsgParam( conn, &sub, v.value );
+    }
+    else if( DBusVariantValueByte v = cast(DBusVariantValueByte)value ){
+        appendMsgParam( conn, &sub, v.value );
+    }
+    else if( DBusVariantValueShort v = cast(DBusVariantValueShort)value ){
+        appendMsgParam( conn, &sub, v.value );
+    }
+    else if( DBusVariantValueUShort v = cast(DBusVariantValueUShort)value ){
+        appendMsgParam( conn, &sub, v.value );
+    }
+    else if( DBusVariantValueInt v = cast(DBusVariantValueInt)value ){
+        appendMsgParam( conn, &sub, v.value );
+    }
+    else if( DBusVariantValueUInt v = cast(DBusVariantValueUInt)value ){
+        appendMsgParam( conn, &sub, v.value );
+    }
+    else if( DBusVariantValueLong v = cast(DBusVariantValueLong)value ){
+        appendMsgParam( conn, &sub, v.value );
+    }
+    else if( DBusVariantValueULong v = cast(DBusVariantValueULong)value ){
+        appendMsgParam( conn, &sub, v.value );
+    }
+    else if( DBusVariantValueDouble v = cast(DBusVariantValueDouble)value ){
+        appendMsgParam( conn, &sub, v.value );
+    }
+    else if( DBusVariantValueString v = cast(DBusVariantValueString)value ){
+        appendMsgParam( conn, &sub, v.value );
+    }
+
+    else if( DBusVariantStruct v = cast(DBusVariantStruct)value ){
+        DBusMessageIter sub2;
+        ensureDBus( dbus_message_iter_open_container( &sub, DBUS_TYPE_STRUCT, XtoUtf8z( v.getSig() ), &sub2 ));
+        foreach( el; v.values ){
+            appendMsgParamVariant( conn, &sub2, el );
+        }
+        ensureDBus( dbus_message_iter_close_container( &sub, &sub2 ));
+    }
+    else if( DBusVariantArray v = cast(DBusVariantArray)value ){
+        DBusMessageIter sub2;
+        ensureDBus( dbus_message_iter_open_container( &sub, DBUS_TYPE_ARRAY, XtoUtf8z( v.getSig() ), &sub2 ));
+        foreach( el; v.values ){
+            appendMsgParamVariant( conn, &sub2, el );
+        }
+        ensureDBus( dbus_message_iter_close_container( &sub, &sub2 ));
+    }
+    else if( DBusVariantMap v = cast(DBusVariantMap)value ){
+        DBusMessageIter sub2;
+        ensureDBus( dbus_message_iter_open_container( &sub, DBUS_TYPE_ARRAY, XtoUtf8z( v.getSig() ), &sub2 ));
+        foreach( entry; v.values ){
+            DBusMessageIter el;
+            ensureDBus( dbus_message_iter_open_container( &sub2, DBUS_TYPE_DICT_ENTRY, null, &el ));
+            appendMsgParamVariant( conn, &el, entry.key );
+            appendMsgParamVariant( conn, &el, entry.value );
+            ensureDBus( dbus_message_iter_close_container( &sub2, &el ));
+        }
+        ensureDBus( dbus_message_iter_close_container( &sub, &sub2 ));
+    }
+    else{
+        Stdout.formatln( "appendMsgParamVariant not handled case for sig: {}", value.getSig() ).flush(); 
+        ensure( false, "appendMsgParamVariant not handled case for sig: %0", value.getSig() );
+    }
+    ensureDBus( dbus_message_iter_close_container( iter, &sub ));
+}
+
+void appendMsgParamArray( T )( DBusConnection* conn, DBusMessageIter* iter, T[] value ){
+    //pragma( msg, "appendMsgParamArray: "~typeof(T).stringof );
+	DBusMessageIter sub;
+    //Stderr.formatln( "DBus {} {}", __LINE__,createDBusSignature!(T) ).flush;
+	ensureDBus( dbus_message_iter_open_container( iter, DBUS_TYPE_ARRAY, XtoUtf8z( createDBusSignature!(T)), &sub ));
+	foreach( item; value ){
+        appendItem!( typeof( item ))( conn, &sub, item );
+	}
+	ensureDBus( dbus_message_iter_close_container( iter, &sub ));
+}
+
+void appendMsgParamStruct( T... )( DBusConnection* conn, DBusMessageIter* iter, T t ){
+    //pragma( msg, "appendMsgParamStruct: "~typeof(T).stringof );
+    DBusMessageIter sub;
+    ensureDBus( dbus_message_iter_open_container( iter, DBUS_TYPE_STRUCT, XtoUtf8z( createDBusSignature!(T)), &sub ));
+    foreach( item; t ){
+        appendItem( conn, &sub, item );
+    }
+    ensureDBus( dbus_message_iter_close_container( iter, &sub ));
+}
+
+void appendMsgParamAssoc( K, V )( DBusConnection* conn, DBusMessageIter* iter, V[K] map ){
+    //pragma( msg, "appendMsgParamAssoc: key="~typeof(K).stringof~" value="~typeof(V).stringof );
+    DBusMessageIter sub;
+    ensureDBus( dbus_message_iter_open_container( iter, DBUS_TYPE_ARRAY,
+        XtoUtf8z( createDBusSignature!(V[K])[1..$] ), // "{ss}" this is without the leading 'a' for the array.
+        &sub ));
+    foreach( key, value; map ){
+        DBusMessageIter el;
+        ensureDBus( dbus_message_iter_open_container( &sub, DBUS_TYPE_DICT_ENTRY, null, &el ));
+        appendItem!( K )( conn, &el, key );
+        appendItem!( V )( conn, &el, value );
+        ensureDBus( dbus_message_iter_close_container( &sub, &el ));
+    }
+    ensureDBus( dbus_message_iter_close_container( iter, &sub ));
+}
+
+template createDBusSignature(T...){
+    //pragma( msg, "createDBusSignature(T) : T="~typeof(T).stringof );
+    static if( T.length > 1 ){
+        //pragma( msg, "R.length>1" );
+        const char[] createDBusSignature = createDBusSignature!(T[0]) ~ createDBusSignature!(T[1..$]);
+    }
+    else static if( isAssocArrayType!(T[0])   ){
+        //pragma( msg, "createDBusSignature: key="~typeof(T.keys[0] ).stringof~" value="~typeof(T.values[0] ).stringof );
+        const char[] createDBusSignature =
+            DBUS_TYPE_ARRAY_AS_STRING ~
+            DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING ~
+            createDBusSignature!( typeof(T[0].keys[0] )) ~
+            createDBusSignature!( typeof(T[0].values[0] )) ~
+            DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
+    }
+    else static if( isDynamicArrayType!(T[0]) ){
+        //pragma( msg, "createDBusSignature: arr="~typeof(T[0]).stringof );
+        static if( is( T[0] == char[] ) ){
+            const char[] createDBusSignature = DBUS_TYPE_STRING_AS_STRING;
+        }
+        else{
+            const char[] createDBusSignature = DBUS_TYPE_ARRAY_AS_STRING ~ createDBusSignature!(typeof(T[0][0]));
+        }
+    }
+	else static if( is( T[0] == bool        ) ){ const char[] createDBusSignature = DBUS_TYPE_BOOLEAN_AS_STRING; }
+	else static if( is( T[0] == byte        ) ){ const char[] createDBusSignature = DBUS_TYPE_BYTE_AS_STRING;   }
+	else static if( is( T[0] == short       ) ){ const char[] createDBusSignature = DBUS_TYPE_INT16_AS_STRING;  }
+	else static if( is( T[0] == ushort      ) ){ const char[] createDBusSignature = DBUS_TYPE_UINT16_AS_STRING; }
+	else static if( is( T[0] == int         ) ){ const char[] createDBusSignature = DBUS_TYPE_INT32_AS_STRING;  }
+	else static if( is( T[0] == uint        ) ){ const char[] createDBusSignature = DBUS_TYPE_UINT32_AS_STRING; }
+	else static if( is( T[0] == long        ) ){ const char[] createDBusSignature = DBUS_TYPE_INT64_AS_STRING;  }
+	else static if( is( T[0] == ulong       ) ){ const char[] createDBusSignature = DBUS_TYPE_UINT64_AS_STRING; }
+	else static if( is( T[0] == double      ) ){ const char[] createDBusSignature = DBUS_TYPE_DOUBLE_AS_STRING; }
+    else static if( is( T[0] : DBusObjectImpl ) ){ const char[] createDBusSignature = DBUS_TYPE_OBJECT_PATH_AS_STRING; }
+    else static if( is( T[0] == DBusVariant ) ){ const char[] createDBusSignature = DBUS_TYPE_VARIANT_AS_STRING; }
+    else static if( is( T[0] == Struct!(typeof(T[0].t)) )){
+        //pragma( msg, "createDBusSignature Struct: t="~typeof(T[0].t).stringof );
+        const char[] createDBusSignature =
+            DBUS_STRUCT_BEGIN_CHAR_AS_STRING ~
+            createDBusSignature!( typeof(T[0].t) ) ~
+            DBUS_STRUCT_END_CHAR_AS_STRING;
+    }
+	else {
+        pragma( msg, "createDBusSignature(T) : T="~typeof(T).stringof );
+        static assert( false );
+    }
+}
+
+template DBusTypeIdFromDType(T){
+    //pragma( msg, "DBusTypeIdFromDType: "~typeof(T).stringof );
+    static if(false){}
+    else static if( is( T == char[]      ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_STRING; }
+    else static if( isDynamicArrayType!(T) ){ const int DBusTypeIdFromDType = DBUS_TYPE_ARRAY; }
+    else static if( is( T == bool        ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_BOOLEAN; }
+    else static if( is( T == byte        ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_BYTE; }
+    else static if( is( T == short       ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_INT16; }
+    else static if( is( T == ushort      ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_UINT16; }
+    else static if( is( T == int         ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_INT32; }
+    else static if( is( T == uint        ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_UINT32; }
+    else static if( is( T == long        ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_INT64; }
+    else static if( is( T == ulong       ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_UINT64; }
+    else static if( is( T == double      ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_DOUBLE; }
+    else static if( is( T : DBusObjectImpl    ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_OBJECT_PATH; }
+    else static if( is( T == DBusVariant ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_OBJECT_PATH; }
+    else static if( is( T == Struct!(typeof(T.t)) ) ){ const int DBusTypeIdFromDType = DBUS_TYPE_OBJECT_PATH; }
+	else static assert(false);
+}
+
+void appendItem( T... )( DBusConnection* conn, DBusMessageIter * args, T t ){
+    //pragma( msg, ">>>appendItem input: "~typeof(t).stringof );
+    //Stderr.formatln( "DBus {} {}", __LINE__,T[0].stringof ).flush;
+    static if( T.length > 1 ){
+        //pragma( msg, "T.length>1" );
+        appendItem(T[0])( conn, args, t[0] );
+        appendItem(T[1..$])( conn, args, t[1..$] );
+    }
+    else static if( isAssocArrayType!(T[0]) ){
+        //pragma( msg, ">>> appendItem: assoc" );
+        //Stdout.formatln( "DBus {}", __LINE__ );
+        appendMsgParamAssoc( conn, args, t[0] );
+    }
+    else static if( is( T[0] == char[] )){ // char[] nicht als dyn array, sondern als String
+        //pragma( msg, ">>> appendItem: char[]" );
+        appendMsgParam( conn, args, t[0]);
+    }
+    else static if( isDynamicArrayType!(T[0]) ){
+        //pragma( msg, ">>> appendItem: []" );
+        //Stdout.formatln( "DBus {}", __LINE__ );
+        appendMsgParamArray( conn, args, t[0] );
+    }
+	else static if( isDBusSimpleType!( T[0] ) ) {
+        //pragma( msg, ">>> appendItem: integral" );
+		appendMsgParam( conn, args, t[0] );
+	}
+	else static if( is( T[0] : DBusObjectImpl )){
+        //pragma( msg, ">>> appendItem: interface/class" );
+		appendMsgParamObject( conn, args, cast(DBusObjectImpl)t[0]);
+	}
+    else static if( is( T[0] == DBusVariant ) ){
+        appendMsgParamVariant( conn, args, t[0]);
+    }
+    else static if( is( T[0] == DBusObjPath ) ){
+        //pragma( msg, ">>> appendItem: path" );
+        Stdout.formatln( "DBus {}", __LINE__ );
+        notImplemented();
+    }
+    else static if( is( T[0] == DBusSignature ) ){
+        //pragma( msg, ">>> appendItem: sig" );
+        Stdout.formatln( "DBus {}", __LINE__ );
+        notImplemented();
+    }
+    else static if( is( T[0] == Struct!(typeof(T[0].t)) ) ){
+        //pragma( msg, ">>> appendItem: struct" );
+        appendMsgParamStruct( conn, args, t[0].t );
+        //pragma( msg, "struct: "~typeof(t).stringof );
+    }
+	else{
+        pragma( msg, "appendItem: "~typeof(t).stringof );
+		static assert(false, typeof(t).stringof );
+    }
+}
+
+void sendReply( DBusConnection* conn, DBusMessage* message ){
+
+    Stdout.flush();
+    Stderr.flush();
+
+    DBusMessage* reply = dbus_message_new_method_return(message);
+    scope(exit){
+        dbus_message_unref(reply);
+    }
+    dbus_bool_t res = dbus_connection_send(conn, reply, null );
+    dbus_connection_flush(conn);
+    if( !res ){
+        throw new TracedException( "Cannot send. Out of memory." );
+    }
+}
+
+void sendReplyData( T... )( DBusConnection* conn, DBusMessage* message, Struct!(T) t ){
+
+    Stdout.flush();
+    Stderr.flush();
+
+    //Stdout.formatln( "DBus {}", __LINE__ );
+	DBusMessage* reply = dbus_message_new_method_return(message);
+	scope(exit){
+		dbus_message_unref(reply);
+	}
+    //Stdout.formatln( "DBus {}", __LINE__ );
+
+	static if( t.t.length > 0 ){
+		DBusMessageIter args;
+		dbus_message_iter_init_append( reply, &args);
+		foreach( t_item; t.t ){
+        //Stdout.formatln( "DBus {}", __LINE__ );
+        //pragma( msg, "sendReply t: "~typeof(t).stringof );
+        //pragma( msg, "sendReply t_item: "~typeof(t_item).stringof );
+			appendItem( conn, & args, t_item );
+        //pragma( msg, "sendReply OK" );
+		}
+	}
+    //Stdout.formatln( "DBus {}", __LINE__ );
+	//Stdout.formatln( "reply sig : {}", fromUtf8z(dbus_message_get_signature(reply)));
+	dbus_bool_t res = dbus_connection_send(conn, reply, null );
+	dbus_connection_flush(conn);
+	if( !res ){
+		throw new TracedException( "Cannot send. Out of memory." );
+	}
+}
+
+void sendException( DBusConnection* conn, DBusMessage* message, Exception e ){
+
+    Stdout.flush();
+    Stderr.flush();
+
+    char* type;
+    char[] msg = e.msg;
+    if( IOException e2 = cast(IOException)e ){
+        type = XtoUtf8z(DBUS_ERROR_IO_ERROR);
+        msg = "IOException " ~ msg;
+    }
+    else{
+        type = XtoUtf8z(DBUS_ERROR_FAILED);
+    }
+    if( TracedException te = cast(TracedException)e ){
+        foreach( m; te ){
+            msg ~= m ~ \n;
+        }
+    }
+
+	DBusMessage* reply =
+		dbus_message_new_error(message, type, XtoUtf8z("D Exception: " ~ msg) );
+	scope(exit){
+		dbus_message_unref(reply);
+	}
+	dbus_bool_t res = dbus_connection_send(conn, reply, null );
+	dbus_connection_flush(conn);
+	if( !res ){
+		throw new TracedException( "Cannot send. Out of dbus-memory." );
+	}
+}
+
+bool checkIntf( char[] intfName, DBusMessage* message ){
+	char[] namedInterface = fromUtf8z( dbus_message_get_interface(message));
+	if( namedInterface.length == 0 ){
+		return true; // no interface named in call, so lets try
+	}
+	return namedInterface == intfName;
+}
+
+public const int METHOD_SIG_MAXLENGTH = 100;
+
+char[] methodSignature( DBusMessage* message, char[] buf = null ){
+	char[] name = fromUtf8z( dbus_message_get_member(message));
+	if( buf.length < name.length ){
+		buf.length = name.length;
+	}
+	buf[ 0 .. name.length ] = name;
+	
+	char[] sig = fromUtf8z( dbus_message_get_signature(message));
+	int sz = name.length+sig.length+1;
+	if( buf.length < sz ){
+		buf.length= sz;
+	}
+    int type = dbus_message_get_type( message );
+    switch( type ){
+    case DBUS_MESSAGE_TYPE_METHOD_CALL:
+        buf[name.length] = '|';
+        break;
+    case DBUS_MESSAGE_TYPE_SIGNAL:
+        buf[name.length] = '>';
+        break;
+    case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+    case DBUS_MESSAGE_TYPE_ERROR:
+    case DBUS_MESSAGE_TYPE_INVALID:
+    default:
+        ensure( false, "methodSignature for unknown type %0", toUtf8(type) );
+    }
+	buf[name.length+1 .. sz ] = sig;
+	return buf[0..sz];
+}
+
+char[] nextSingleCompleteTypeSig( char[] sigText, inout int ate = 0 ){
+    if( sigText.length > ate || sigText.length == 0 ){
+        return null;
+    }
+    char[] sig = sigText[ ate .. $ ];
+
+    switch( sig[0] ){
+    case 'y':
+    case 'b':
+    case 'n':
+    case 'q':
+    case 'i':
+    case 'u':
+    case 'x':
+    case 't':
+    case 'd':
+    case 's':
+    case 'o':
+    case 'g':
+    case 'v':
+        ate = 1;
+        return sig[0..1];
+    default:
+        ensure( sig.length > 1, "nextSingleCompleteTypeSig found %0 as a single type sig, which is unknown", sig[0..1] );
+    }
+
+    if( sig[0] == 'a' ){
+        if( sig[ 1 ] == '{' ){
+            int idx = 2;
+            nextSingleCompleteTypeSig( sig, idx );
+            nextSingleCompleteTypeSig( sig, idx );
+            ensure( sig.length > idx, "nextSingleCompleteTypeSig 2" );
+            ensure( sig[ idx ] == '}', "nextSingleCompleteTypeSig 3" );
+            idx++;
+            ate += idx;
+            return sig[ 0 .. idx ];
+        }
+        else{
+            int idx = 1;
+            nextSingleCompleteTypeSig( sig, idx );
+            ate += idx;
+            return sig[ 0 .. idx ];
+        }
+    }
+    else if( sig[0] == '(' ){
+        int idx = 1;
+        ensure( sig.length > idx, "nextSingleCompleteTypeSig 4" );
+        while( sig[ idx ] != ')' ){
+            nextSingleCompleteTypeSig( sig, idx );
+            ensure( sig.length > idx, "nextSingleCompleteTypeSig 5" );
+        }
+        idx++;
+        ate += idx;
+        return sig[ 0 .. idx ];
+    }
+    assert(false);
+}
+
+DBusVariant createDBusVariant( DBusMessageIter * iter, char[] sigText ){
+    if( sigText.length == 0 ){
+        return null;
+    }
+
+    void getBasic( void* ptr ){
+        dbus_message_iter_get_basic( iter, ptr );
+        dbus_message_iter_next( iter );
+    }
+
+    switch( sigText[0] ){
+    case 'y':
+        {
+            DBusVariantValueByte res = new DBusVariantValueByte();
+            getBasic( & res.value );
+            return res;
+        }
+    case 'b':
+        {
+            DBusVariantValueBool res = new DBusVariantValueBool();
+            getBasic( & res.value );
+            return res;
+        }
+    case 'n':
+        {
+            DBusVariantValueShort res = new DBusVariantValueShort();
+            getBasic( & res.value );
+            return res;
+        }
+    case 'q':
+        {
+            DBusVariantValueUShort res = new DBusVariantValueUShort();
+            getBasic( & res.value );
+            return res;
+        }
+    case 'i':
+        {
+            DBusVariantValueInt res = new DBusVariantValueInt();
+            getBasic( & res.value );
+            return res;
+        }
+    case 'u':
+        {
+            DBusVariantValueUInt res = new DBusVariantValueUInt();
+            getBasic( & res.value );
+            return res;
+        }
+    case 'x':
+        {
+            DBusVariantValueLong res = new DBusVariantValueLong();
+            getBasic( & res.value );
+            return res;
+        }
+    case 't':
+        {
+            DBusVariantValueULong res = new DBusVariantValueULong();
+            getBasic( & res.value );
+            return res;
+        }
+    case 'd':
+        {
+            DBusVariantValueDouble res = new DBusVariantValueDouble();
+            getBasic( & res.value );
+            return res;
+        }
+    case 's':
+        {
+            DBusVariantValueString res = new DBusVariantValueString();
+            char* ptr;
+            getBasic( & ptr );
+            res.value = fromUtf8z( ptr );
+            return res;
+        }
+    case 'v':
+        {
+            DBusVariantValueVariant res = new DBusVariantValueVariant();
+            DBusMessageIter subIter;
+            dbus_message_iter_recurse( iter, &subIter );
+            dbus_message_iter_next( iter );
+            res.value = createDBusVariant( & subIter, sigText[1..$] );
+            return res;
+        }
+    case 'o': //"DBusObject"
+        assert(false);
+    case 'g': //"DBusSignature"
+        assert(false);
+    default:
+        break;
+    }
+    if( sigText[0] == 'a' ){
+        if( sigText.length > 1 && sigText[ 1 ] == '{' ){
+            int idx = 2;
+            char[] sigKey   = nextSingleCompleteTypeSig( sigText, idx );
+            char[] sigValue = nextSingleCompleteTypeSig( sigText, idx );
+            DBusVariantMap res = new DBusVariantMap( sigKey, sigValue );
+
+            DBusMessageIter subIter;
+            dbus_message_iter_recurse( iter, &subIter );
+            dbus_message_iter_next( iter );
+
+            while( dbus_message_iter_get_arg_type( &subIter ) != DBUS_TYPE_INVALID ){
+                ensure( dbus_message_iter_get_arg_type( &subIter ) == DBUS_TYPE_DICT_ENTRY, "createDBusVariant 1" );
+                DBusMessageIter entry;
+                dbus_message_iter_recurse( &subIter, &entry );
+                dbus_message_iter_next( &subIter );
+
+                DBusVariantMapItem item;
+                item.key   = createDBusVariant( & subIter, sigKey   );
+                item.value = createDBusVariant( & subIter, sigValue );
+                res.values ~= item;
+            }
+            return res;
+        }
+        else{
+            int idx = 1;
+            char[] sigElement = nextSingleCompleteTypeSig( sigText, idx );
+            DBusVariantArray res = new DBusVariantArray( sigElement );
+
+            DBusMessageIter subIter;
+            dbus_message_iter_recurse( iter, &subIter );
+            dbus_message_iter_next( iter );
+
+            while( dbus_message_iter_get_arg_type( &subIter ) != DBUS_TYPE_INVALID ){
+                DBusMessageIter entry;
+                dbus_message_iter_recurse( &subIter, &entry );
+                dbus_message_iter_next( &subIter );
+                res.values ~= createDBusVariant( & subIter, sigElement );
+            }
+            return res;
+        }
+    }
+    else if( sigText[0] == '(' ){
+
+        DBusVariantStruct res = new DBusVariantStruct();
+
+        int idx = 1;
+        ensure( sigText.length > idx, "createDBusVariant 2" );
+
+        DBusMessageIter subIter;
+        dbus_message_iter_recurse( iter, &subIter );
+        dbus_message_iter_next( iter );
+
+        while( sigText[ idx ] != ')' ){
+            char[] sigElement = nextSingleCompleteTypeSig( sigText, idx );
+            ensure( sigText.length > idx, "createDBusVariant 3" );
+            res.values ~= createDBusVariant( & subIter, sigElement );
+        }
+        return res;
+    }
+    assert(false);
+}
+
+T getVariantAsKnownType( T )( DBusVariant var ){
+    T res;
+    static if( false ){}
+    else static if( isAssocArrayType!(T) ){
+        version(CD) pragma( msg, "getVariantAsKnownType: assoc "~typeof(T).stringof );
+        DBusVariantMap map = cast(DBusVariantMap)var;
+        ensure( map !is null, "getVariantAsKnownType map is null" );
+        typeof(T.keys  [0]) k;
+        typeof(T.values[0]) v;
+        foreach( value; map.values ){
+            k = getVariantAsKnownType!( typeof(T.keys  [0]) )( value.key   );
+            v = getVariantAsKnownType!( typeof(T.values[0]) )( value.value );
+            res[ k ] = v;
+        }
+    }
+    else static if( is( T == char[] )){ // char[] nicht als dyn array, sondern als String
+        version(CD) pragma( msg, "getVariantAsKnownType: string "~typeof(T).stringof );
+        DBusVariantValueString str = cast(DBusVariantValueString)var;
+        ensure( str !is null, "getVariantAsKnownType string is null" );
+        res = str.value;
+    }
+    else static if( isDynamicArrayType!(T) ){
+        version(CD) pragma( msg, "getVariantAsKnownType: [] "~typeof(T).stringof );
+        DBusVariantArray arr = cast(DBusVariantArray)var;
+        ensure( arr !is null, "getVariantAsKnownType array is null" );
+        res = new typeof(T[0])[ arr.values.length ];
+        foreach( idx, value; arr.values ){
+            res[ idx ] = getVariantAsKnownType!( typeof(T[0]) )( value );
+        }
+    }
+    else static if( isDBusSimpleType!(T) ) {
+        DBusVariantValue!(T) v = cast(DBusVariantValue!(T))var;
+        ensure( v !is null, "getVariantAsKnownType value is null" );
+        res = v.value;
+    }
+    else static if( is( T : DBusObjectImpl )){
+        static assert( false );
+    }
+    else static if( is( T == DBusVariant ) ){
+        res = var;
+    }
+    else static if( is( T == Struct!(typeof(T.t)) ) ){
+        DBusVariantStruct v = cast(DBusVariantStruct)var;
+        ensure( v !is null, "getVariantAsKnownType isnull" );
+        foreach( idx, item; res.t ){
+            res.t[idx] = getVariantAsKnownType!( typeof(item) )( v.values[idx] );
+        }
+    }
+    else{
+        pragma( msg, "appendItem: "~typeof(t).stringof );
+        static assert(false, typeof(t).stringof );
+    }
+    return res;
+}
+
+
+
+
+void testTemplateCompilation(){
+  getCallValues!( int[] )( null );
+  getCallValues!( int[ char[] ] )( null );
+  getCallValues!( DBusVariant[ DBusVariant ] )( null );
+  getCallValues!( Struct!( int[], long, char[], Struct!( bool ) ) )( null );
+
+  getVariantAsKnownType!( int[] )( null );
+  getVariantAsKnownType!( int[ char[] ] )( null );
+  getVariantAsKnownType!( DBusVariant[ DBusVariant ] )( null );
+  getVariantAsKnownType!( Struct!( int[], long, char[], Struct!( bool ) ) )( null );
+}
+
+