Mercurial > projects > dbus-d
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 ); +} + +