Index: gobject/valadbusservermodule.vala
===================================================================
--- gobject/valadbusservermodule.vala	(revision 1999)
+++ gobject/valadbusservermodule.vala	(working copy)
@@ -29,6 +29,29 @@
  * The link between a dynamic method and generated code.
  */
 public class Vala.DBusServerModule : DBusClientModule {
+	struct BasicTypeInfo {
+		public weak string signature;
+		public weak string type_name;
+		public weak string cname;
+	}
+
+	const BasicTypeInfo[] basic_types = {
+		{ "y", "BYTE", "guint8" },
+		{ "b", "BOOLEAN", "dbus_bool_t" },
+		{ "n", "INT16", "dbus_int16_t" },
+		{ "q", "UINT16", "dbus_uint16_t" },
+		{ "i", "INT32", "dbus_int32_t" },
+		{ "u", "UINT32", "dbus_uint32_t" },
+		{ "x", "INT64", "dbus_int64_t" },
+		{ "t", "UINT64", "dbus_uint64_t" },
+		{ "d", "DOUBLE", "double" },
+		{ "s", "STRING", "const char*" },
+		{ "o", "OBJECT_PATH", "const char*" },
+		{ "g", "SIGNATURE", "const char*" }
+	};
+
+	int loopindex;
+
 	public DBusServerModule (CCodeGenerator codegen, CCodeModule? next) {
 		base (codegen, next);
 	}
@@ -56,30 +79,50 @@
 		return "result";
 	}
 
-	public override CCodeFragment register_dbus_info (ObjectTypeSymbol bindable) {
+	void generate_unregister_function (ObjectType object_type) {
+		var sym = object_type.type_symbol;
 
-		CCodeFragment fragment = new CCodeFragment ();
+		var cfunc = new CCodeFunction ("_dbus_" + sym.get_lower_case_cprefix () + "unregister", "void");
+		cfunc.add_parameter (new CCodeFormalParameter ("connection", "DBusConnection*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("user_data", "void*"));
 
-		var dbus = bindable.get_attribute ("DBus");
+		source_type_member_declaration.append (cfunc.copy ());
+
+		var block = new CCodeBlock ();
+		cfunc.block = block;
+
+		source_type_member_definition.append (cfunc);
+	}
+
+	void generate_message_function (ObjectType object_type) {
+		var sym = object_type.type_symbol;
+
+		var dbus = sym.get_attribute ("DBus");
 		if (dbus == null) {
-			return fragment;
+			Report.error (sym.source_reference, "`%s' does not specify a D-Bus interface name");
+			return;
 		}
-		var dbus_iface_name = dbus.get_string ("name");
+		string dbus_iface_name = dbus.get_string ("name");
 		if (dbus_iface_name == null) {
-			return fragment;
+			Report.error (sym.source_reference, "`%s' does not specify a D-Bus interface name");
+			return;
 		}
 
 		dbus_glib_h_needed = true;
 
-		var dbus_methods = new StringBuilder ();
-		dbus_methods.append ("{\n");
+		var cfunc = new CCodeFunction ("_dbus_" + sym.get_lower_case_cprefix () + "message", "DBusHandlerResult");
+		cfunc.add_parameter (new CCodeFormalParameter ("connection", "DBusConnection*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("message", "DBusMessage*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("user_data", "void*"));
 
-		var blob = new StringBuilder ();
-		blob.append_c ('"');
+		source_type_member_declaration.append (cfunc.copy ());
 
-		int method_count = 0;
-		long blob_len = 0;
-		foreach (Method m in bindable.get_methods ()) {
+		var block = new CCodeBlock ();
+		cfunc.block = block;
+
+		CCodeIfStatement clastif = null;
+
+		foreach (Method m in sym.get_methods ()) {
 			if (m is CreationMethod || m.binding != MemberBinding.INSTANCE
 			    || m.overrides || m.access != SymbolAccessibility.PUBLIC) {
 				continue;
@@ -88,409 +131,316 @@
 				continue;
 			}
 
-			var parameters = new Gee.ArrayList<FormalParameter> ();
-			foreach (FormalParameter param in m.get_parameters ()) {
-				parameters.add (param);
-			}
-			if (!(m.return_type is VoidType)) {
-				parameters.add (new FormalParameter ("result", new PointerType (new VoidType ())));
-			}
-			parameters.add (new FormalParameter ("error", gerror_type));
+			var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_is_method_call"));
+			ccheck.add_argument (new CCodeIdentifier ("message"));
+			ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
+			ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (Symbol.lower_case_to_camel_case (m.name))));
 
-			dbus_methods.append ("{ (GCallback) ");
-			dbus_methods.append (generate_dbus_wrapper (m, bindable));
-			dbus_methods.append (", ");
-			dbus_methods.append (head.get_marshaller_function (parameters, bool_type, null, true));
-			dbus_methods.append (", ");
-			dbus_methods.append (blob_len.to_string ());
-			dbus_methods.append (" },\n");
+			var callblock = new CCodeBlock ();
+			var cdecl = new CCodeDeclaration ("DBusMessage*");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("reply"));
 
-			head.generate_marshaller (parameters, bool_type, true);
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_wrapper (m, sym)));
+			ccall.add_argument (new CCodeIdentifier ("user_data"));
+			ccall.add_argument (new CCodeIdentifier ("message"));
 
-			long start = blob.len;
+			callblock.add_statement (cdecl);
+			callblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("reply"), ccall)));
 
-			blob.append (dbus_iface_name);
-			blob.append ("\\0");
-			start++;
+			ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_send"));
+			ccall.add_argument (new CCodeIdentifier ("connection"));
+			ccall.add_argument (new CCodeIdentifier ("reply"));
+			ccall.add_argument (new CCodeConstant ("NULL"));
+			callblock.add_statement (new CCodeExpressionStatement (ccall));
 
-			blob.append (Symbol.lower_case_to_camel_case (m.name));
-			blob.append ("\\0");
-			start++;
+			ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
+			ccall.add_argument (new CCodeIdentifier ("reply"));
+			callblock.add_statement (new CCodeExpressionStatement (ccall));
 
-			// synchronous
-			blob.append ("S\\0");
-			start++;
+			var cif = new CCodeIfStatement (ccheck, callblock);
+			if (clastif == null) {
+				block.add_statement (cif);
+			} else {
+				clastif.false_statement = cif;
+			}
 
-			foreach (FormalParameter param in m.get_parameters ()) {
-				blob.append (param.name);
-				blob.append ("\\0");
-				start++;
+			clastif = cif;
+		}
 
-				if (param.direction == ParameterDirection.IN) {
-					blob.append ("I\\0");
-					start++;
-				} else if (param.direction == ParameterDirection.OUT) {
-					blob.append ("O\\0");
-					start++;
-					blob.append ("F\\0");
-					start++;
-					blob.append ("N\\0");
-					start++;
-				} else {
-					Report.error (param.source_reference, "unsupported parameter direction for D-Bus method");
-				}
+		var retblock = new CCodeBlock ();
+		retblock.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("DBUS_HANDLER_RESULT_NOT_YET_HANDLED")));
+		if (clastif == null) {
+			block.add_statement (retblock);
+		} else {
+			clastif.false_statement = retblock;
+		}
+		
 
-				blob.append (param.parameter_type.get_type_signature ());
-				blob.append ("\\0");
-				start++;
-			}
+		source_type_member_definition.append (cfunc);
+	}
 
-			if (!(m.return_type is VoidType)) {
-				blob.append (dbus_result_name (m));
-				blob.append ("\\0");
-				start++;
+	CCodeExpression get_vtable (ObjectType object_type) {
+		var sym = object_type.type_symbol;
 
-				blob.append ("O\\0");
-				start++;
-				blob.append ("F\\0");
-				start++;
-				blob.append ("N\\0");
-				start++;
+		var vtable = new CCodeInitializerList ();
+		vtable.append (new CCodeIdentifier ("_dbus_" + sym.get_lower_case_cprefix () + "unregister"));
+		vtable.append (new CCodeIdentifier ("_dbus_" + sym.get_lower_case_cprefix () + "message"));
 
-				blob.append (m.return_type.get_type_signature ());
-				blob.append ("\\0");
-				start++;
-			}
+		generate_unregister_function (object_type);
+		generate_message_function (object_type);
 
-			blob.append ("\\0");
-			start++;
+		var cdecl = new CCodeDeclaration ("const DBusObjectPathVTable");
+		cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("_dbus_" + sym.get_lower_case_cprefix () + "vtable", vtable));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		source_constant_declaration.append (cdecl);
 
-			blob_len += blob.len - start;
+		return new CCodeIdentifier ("_dbus_" + sym.get_lower_case_cprefix () + "vtable");
+	}
 
-			method_count++;
+	public override void visit_invocation_expression (InvocationExpression expr) {
+		var mtype = expr.call.value_type as MethodType;
+		if (mtype == null || mtype.method_symbol.get_cname () != "dbus_g_connection_register_g_object") {
+			base.visit_invocation_expression (expr);
+			return;
 		}
 
-		blob.append_c ('"');
+		expr.accept_children (codegen);
 
-		dbus_methods.append ("}\n");
+		var ma = (MemberAccess) expr.call;
 
-		var dbus_signals = new StringBuilder ();
-		dbus_signals.append_c ('"');
-		foreach (Signal sig in bindable.get_signals ()) {
-			if (sig.access != SymbolAccessibility.PUBLIC) {
-				continue;
-			}
-			if (!is_dbus_visible (sig)) {
-				continue;
-			}
+		var raw_conn = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_get_connection"));
+		raw_conn.add_argument ((CCodeExpression) ma.inner.ccodenode);
 
-			dbus_signals.append (dbus_iface_name);
-			dbus_signals.append ("\\0");
-			dbus_signals.append (Symbol.lower_case_to_camel_case (sig.name));
-			dbus_signals.append ("\\0");
+		var args_it = expr.get_argument_list ().iterator ();
+		args_it.next ();
+		var path_arg = args_it.get ();
+		args_it.next ();
+		var obj_arg = args_it.get ();
+
+		var object_type = (ObjectType) obj_arg.value_type;
+
+		var cregister = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_register_object_path"));
+		cregister.add_argument (raw_conn);
+		cregister.add_argument ((CCodeExpression) path_arg.ccodenode);
+		cregister.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_vtable (object_type)));
+		cregister.add_argument ((CCodeExpression) obj_arg.ccodenode);
+		expr.ccodenode = cregister;
+	}
+
+	public override CCodeFragment register_dbus_info (ObjectTypeSymbol bindable) {
+		return new CCodeFragment ();
+	}
+
+	CCodeExpression? get_array_length (CCodeExpression expr) {
+		var id = expr as CCodeIdentifier;
+		var ma = expr as CCodeMemberAccess;
+		if (id != null) {
+			return new CCodeIdentifier (id.name + "_length1");
+		} else if (ma != null) {
+			return new CCodeMemberAccess.pointer (ma.inner, ma.member_name + "_length1");
 		}
-		dbus_signals.append_c('"');
+		return null;
+	}
 
-		var dbus_props = new StringBuilder();
-		dbus_props.append_c ('"');
-		foreach (Property prop in bindable.get_properties ()) {
-			if (prop.access != SymbolAccessibility.PUBLIC) {
-				continue;
+	bool get_basic_type_info (string signature, out BasicTypeInfo basic_type) {
+		foreach (BasicTypeInfo info in basic_types) {
+			if (info.signature == signature) {
+				basic_type = info;
+				return true;
 			}
-			if (!is_dbus_visible (prop)) {
-				continue;
-			}
-
-			dbus_props.append (dbus_iface_name);
-			dbus_props.append ("\\0");
-			dbus_props.append (Symbol.lower_case_to_camel_case (prop.name));
-			dbus_props.append ("\\0");
 		}
-		dbus_props.append_c ('"');
+		return false;
+	}
 
-		var dbus_methods_decl = new CCodeDeclaration ("const DBusGMethodInfo");
-		dbus_methods_decl.modifiers = CCodeModifiers.STATIC;
-		dbus_methods_decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("%s_dbus_methods[]".printf (bindable.get_lower_case_cname ()), new CCodeConstant (dbus_methods.str)));
+	CCodeExpression read_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression iter_expr, CCodeExpression? expr) {
+		string temp_name = "_tmp%d".printf (next_temp_var_id++);
 
-		fragment.append (dbus_methods_decl);
+		var cdecl = new CCodeDeclaration (basic_type.cname);
+		cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
+		fragment.append (cdecl);
 
-		var dbus_object_info = new CCodeDeclaration ("const DBusGObjectInfo");
-		dbus_object_info.modifiers = CCodeModifiers.STATIC;
-		dbus_object_info.add_declarator (new CCodeVariableDeclarator.with_initializer ("%s_dbus_object_info".printf (bindable.get_lower_case_cname ()), new CCodeConstant ("{ 0, %s_dbus_methods, %d, %s, %s, %s }".printf (bindable.get_lower_case_cname (), method_count, blob.str, dbus_signals.str, dbus_props.str))));
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_basic"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
+		fragment.append (new CCodeExpressionStatement (iter_call));
+		return new CCodeIdentifier (temp_name);
+	}
 
-		fragment.append (dbus_object_info);
+	CCodeExpression? read_expression (CCodeFragment fragment, DataType type, CCodeExpression iter_expr, CCodeExpression? expr) {
+		BasicTypeInfo basic_type;
+		if (get_basic_type_info (type.get_type_signature (), out basic_type)) {
+			return read_basic (fragment, basic_type, iter_expr, expr);
+		} else if (type is ArrayType) {
+			// return read_array (fragment, (ArrayType) type, iter_expr, expr);
+			return null;
+		} else if (type.data_type is Struct) {
+			// return read_struct (fragment, (Struct) type.data_type, iter_expr, expr);
+			return null;
+		} else if (type is ObjectType) {
+			if (type.data_type.get_full_name () == "GLib.HashTable") {
+				// return read_hash_table (fragment, (ObjectType) type, iter_expr, expr);
+				return null;
+			}
+			return null;
+		} else {
+			Report.error (type.source_reference, "D-Bus deserialization of type `%s' is not supported".printf (type.to_string ()));
+			return null;
+		}
+	}
 
-		var install_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_object_type_install_info"));
-		install_call.add_argument (new CCodeIdentifier (bindable.get_type_id ()));
-		install_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("%s_dbus_object_info".printf (bindable.get_lower_case_cname ()))));
+	void write_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression iter_expr, CCodeExpression expr) {
+		string temp_name = "_tmp%d".printf (next_temp_var_id++);
 
-		fragment.append (new CCodeExpressionStatement (install_call));
+		var cdecl = new CCodeDeclaration (basic_type.cname);
+		cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
+		fragment.append (cdecl);
 
-		return fragment;
+		fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), expr)));
+
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_append_basic"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_" + basic_type.type_name));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
+		fragment.append (new CCodeExpressionStatement (iter_call));
 	}
 
-	string generate_dbus_wrapper (Method m, ObjectTypeSymbol bindable) {
-		string wrapper_name = "_dbus_%s".printf (m.get_cname ());
+	void write_array (CCodeFragment fragment, ArrayType array_type, CCodeExpression iter_expr, CCodeExpression array_expr) {
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_ARRAY"));
+		iter_call.add_argument (new CCodeConstant ("\"%s\"".printf (array_type.element_type.get_type_signature ())));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		fragment.append (new CCodeExpressionStatement (iter_call));
 
-		// declaration
+		var cdecl = new CCodeDeclaration ("int");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("i"));
+		fragment.append (cdecl);
 
-		var function = new CCodeFunction (wrapper_name, "gboolean");
-		function.modifiers = CCodeModifiers.STATIC;
-		m.ccodenode = function;
+		var cforblock = new CCodeBlock ();
+		var cforfragment = new CCodeFragment ();
+		cforblock.add_statement (cforfragment);
+		var cfor = new CCodeForStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), get_array_length (array_expr)), cforblock);
+		cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
+		cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
 
-		function.add_parameter (new CCodeFormalParameter ("self", bindable.get_cname () + "*"));
+		write_expression (cforfragment, array_type.element_type, new CCodeIdentifier ("subiter"), new CCodeElementAccess (array_expr, new CCodeIdentifier ("i")));
+		fragment.append (cfor);
 
-		foreach (FormalParameter param in m.get_parameters ()) {
-			string ptr = (param.direction == ParameterDirection.OUT ? "*" : "");
-			var array_type = param.parameter_type as ArrayType;
-			if (array_type != null && array_type.element_type.data_type != string_type.data_type) {
-				if (dbus_use_ptr_array (array_type)) {
-					function.add_parameter (new CCodeFormalParameter ("dbus_%s".printf (param.name), "GPtrArray*" + ptr));
-				} else {
-					function.add_parameter (new CCodeFormalParameter ("dbus_%s".printf (param.name), "GArray*" + ptr));
-				}
-			} else if (param.parameter_type.get_type_signature ().has_prefix ("(")) {
-				function.add_parameter (new CCodeFormalParameter ("dbus_%s".printf (param.name), "GValueArray*" + ptr));
-			} else {
-				function.add_parameter ((CCodeFormalParameter) param.ccodenode);
-			}
-		}
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		fragment.append (new CCodeExpressionStatement (iter_call));
+	}
 
-		if (!(m.return_type is VoidType)) {
-			var array_type = m.return_type as ArrayType;
-			if (array_type != null) {
-				if (array_type.element_type.data_type == string_type.data_type) {
-					function.add_parameter (new CCodeFormalParameter ("result", array_type.get_cname () + "*"));
-				} else if (dbus_use_ptr_array (array_type)) {
-					function.add_parameter (new CCodeFormalParameter ("dbus_result", "GPtrArray**"));
-				} else {
-					function.add_parameter (new CCodeFormalParameter ("dbus_result", "GArray**"));
-				}
-			} else if (m.return_type.get_type_signature ().has_prefix ("(")) {
-				function.add_parameter (new CCodeFormalParameter ("dbus_result", "GValueArray**"));
-			} else {
-				function.add_parameter (new CCodeFormalParameter ("result", m.return_type.get_cname () + "*"));
+	void write_expression (CCodeFragment fragment, DataType type, CCodeExpression iter_expr, CCodeExpression expr) {
+		BasicTypeInfo basic_type;
+		if (get_basic_type_info (type.get_type_signature (), out basic_type)) {
+			write_basic (fragment, basic_type, iter_expr, expr);
+		} else if (type is ArrayType) {
+			write_array (fragment, (ArrayType) type, iter_expr, expr);
+		} else if (type.data_type is Struct) {
+			// write_struct (fragment, (Struct) type.data_type, iter_expr, expr);
+		} else if (type is ObjectType) {
+			if (type.data_type.get_full_name () == "GLib.HashTable") {
+				// write_hash_table (fragment, (ObjectType) type, iter_expr, expr);
 			}
+		} else {
+			Report.error (type.source_reference, "D-Bus serialization of type `%s' is not supported".printf (type.to_string ()));
 		}
+	}
 
-		function.add_parameter (new CCodeFormalParameter ("error", "GError**"));
+	string generate_dbus_wrapper (Method m, ObjectTypeSymbol sym) {
+		string wrapper_name = "_dbus_%s".printf (m.get_cname ());
 
-		// definition
+		// declaration
 
-		var block = new CCodeBlock ();
+		CCodeDeclaration cdecl;
 
-		foreach (FormalParameter param in m.get_parameters ()) {
-			if (param.parameter_type.get_type_signature ().has_prefix ("(")) {
-				var st = (Struct) param.parameter_type.data_type;
+		var function = new CCodeFunction (wrapper_name, "DBusMessage*");
+		function.modifiers = CCodeModifiers.STATIC;
 
-				var cdecl = new CCodeDeclaration (st.get_cname ());
-				cdecl.add_declarator (new CCodeVariableDeclarator (param.name));
-				block.add_statement (cdecl);
+		function.add_parameter (new CCodeFormalParameter ("self", sym.get_cname () + "*"));
+		function.add_parameter (new CCodeFormalParameter ("message", "DBusMessage*"));
 
-				if (param.direction == ParameterDirection.IN) {
-					// struct input parameter
-					int i = 0;
-					foreach (Field f in st.get_fields ()) {
-						if (f.binding == MemberBinding.INSTANCE) {
-							var cget_call = new CCodeFunctionCall (new CCodeIdentifier (f.field_type.data_type.get_get_value_function ()));
-							cget_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeElementAccess (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_%s".printf (param.name)), "values"), new CCodeConstant (i.to_string ()))));
-							var assign = new CCodeAssignment (new CCodeMemberAccess (new CCodeIdentifier (param.name), f.name), cget_call);
-							block.add_statement (new CCodeExpressionStatement (assign));
-							i++;
-						}
-					}
-				}
-			}
-		}
+		var block = new CCodeBlock ();
+		var prefragment = new CCodeFragment ();
+		var postfragment = new CCodeFragment ();
 
-		if (!(m.return_type is VoidType)) {
-			var array_type = m.return_type as ArrayType;
-			if (array_type != null) {
-				if (array_type.element_type.data_type != string_type.data_type) {
-					var cdecl = new CCodeDeclaration (m.return_type.get_cname ());
-					cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
-					block.add_statement (cdecl);
-				}
+		cdecl = new CCodeDeclaration ("DBusMessageIter");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("iter"));
+		cdecl.add_declarator (new CCodeVariableDeclarator ("subiter"));
+		block.add_statement (cdecl);
 
-				var len_cdecl = new CCodeDeclaration ("int");
-				len_cdecl.add_declarator (new CCodeVariableDeclarator ("result_length1"));
-				block.add_statement (len_cdecl);
-			}
-		}
+		block.add_statement (prefragment);
 
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init"));
+		iter_call.add_argument (new CCodeIdentifier ("message"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("iter")));
+		prefragment.append (new CCodeExpressionStatement (iter_call));
+
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init_append"));
+		iter_call.add_argument (new CCodeIdentifier ("reply"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("iter")));
+		postfragment.append (new CCodeExpressionStatement (iter_call));
+
 		var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
 
 		ccall.add_argument (new CCodeIdentifier ("self"));
 
 		foreach (FormalParameter param in m.get_parameters ()) {
-			var array_type = param.parameter_type as ArrayType;
-			if (array_type != null) {
-				if (param.direction == ParameterDirection.IN) {
-					if (array_type.element_type.data_type == string_type.data_type) {
-						ccall.add_argument (new CCodeIdentifier (param.name));
-						if (!m.no_array_length) {
-							var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
-							cstrvlen.add_argument (new CCodeIdentifier (param.name));
-							ccall.add_argument (cstrvlen);
-						}
-					} else if (dbus_use_ptr_array (array_type)) {
-						ccall.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_%s".printf (param.name)), "pdata"));
-						if (!m.no_array_length) {
-							ccall.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_%s".printf (param.name)), "len"));
-						}
-					} else {
-						ccall.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_%s".printf (param.name)), "data"));
-						if (!m.no_array_length) {
-							ccall.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_%s".printf (param.name)), "len"));
-						}
-					}
-				} else {
-					if (array_type.element_type.data_type != string_type.data_type) {
-						var cdecl = new CCodeDeclaration (param.parameter_type.get_cname ());
-						cdecl.add_declarator (new CCodeVariableDeclarator (param.name));
-						block.add_statement (cdecl);
-
-						ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
-					} else {
-						ccall.add_argument (new CCodeIdentifier (param.name));
-					}
-
-					if (!m.no_array_length) {
-						var len_cdecl = new CCodeDeclaration ("int");
-						len_cdecl.add_declarator (new CCodeVariableDeclarator ("%s_length1".printf (param.name)));
-						block.add_statement (len_cdecl);
-
-						ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("%s_length1".printf (param.name))));
-					}
-				}
-			} else if (param.parameter_type.get_type_signature ().has_prefix ("(")) {
-				// struct input or output parameters
+			cdecl = new CCodeDeclaration (param.parameter_type.get_cname ());
+			cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (param.name, default_value_for_type (param.parameter_type, true)));
+			prefragment.append (cdecl);
+			if (param.direction != ParameterDirection.IN
+			    || param.parameter_type.data_type is Struct) {
 				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
 			} else {
 				ccall.add_argument (new CCodeIdentifier (param.name));
 			}
-		}
 
-		CCodeExpression expr;
-		if (m.return_type is VoidType) {
-			expr = ccall;
-		} else {
-			var array_type = m.return_type as ArrayType;
-			if (array_type != null) {
-				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result_length1")));
-				if (array_type.element_type.data_type != string_type.data_type) {
-					expr = new CCodeAssignment (new CCodeIdentifier ("result"), ccall);
+			if (param.parameter_type is ArrayType) {
+				cdecl = new CCodeDeclaration ("int");
+				cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (param.name + "_length1", new CCodeConstant ("0")));
+				prefragment.append (cdecl);
+				if (param.direction != ParameterDirection.IN) {
+					ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name + "_length1")));
 				} else {
-					expr = new CCodeAssignment (new CCodeIdentifier ("*result"), ccall);
+					ccall.add_argument (new CCodeIdentifier (param.name + "_length1"));
 				}
-			} else {
-				expr = new CCodeAssignment (new CCodeIdentifier ("*result"), ccall);
 			}
-		}
 
-		if (m.get_error_types ().size > 0) {
-			ccall.add_argument (new CCodeIdentifier ("error"));
-		}
-
-		block.add_statement (new CCodeExpressionStatement (expr));
-
-		foreach (FormalParameter param in m.get_parameters ()) {
-			if (param.direction == ParameterDirection.OUT
-			    && param.parameter_type.get_type_signature ().has_prefix ("(")) {
-				// struct output parameter
-				var st = (Struct) param.parameter_type.data_type;
-
-				var array_construct = new CCodeFunctionCall (new CCodeIdentifier ("g_value_array_new"));
-				array_construct.add_argument (new CCodeConstant ("0"));
-
-				var dbus_param = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("dbus_%s".printf (param.name)));
-
-				block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (dbus_param, array_construct)));
-
-				var type_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_struct"));
-				type_call.add_argument (new CCodeConstant ("\"GValueArray\""));
-
-				foreach (Field f in st.get_fields ()) {
-					if (f.binding != MemberBinding.INSTANCE) {
-						continue;
-					}
-
-					string val_name = "val_%s_%s".printf (param.name, f.name);
-
-					// 0-initialize struct with struct initializer { 0 }
-					var cvalinit = new CCodeInitializerList ();
-					cvalinit.append (new CCodeConstant ("0"));
-
-					var cval_decl = new CCodeDeclaration ("GValue");
-					cval_decl.add_declarator (new CCodeVariableDeclarator.with_initializer (val_name, cvalinit));
-					block.add_statement (cval_decl);
-
-					var val_ptr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (val_name));
-
-					var cinit_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
-					cinit_call.add_argument (val_ptr);
-					cinit_call.add_argument (new CCodeIdentifier (f.field_type.data_type.get_type_id ()));
-					block.add_statement (new CCodeExpressionStatement (cinit_call));
-
-					var cset_call = new CCodeFunctionCall (new CCodeIdentifier (f.field_type.data_type.get_set_value_function ()));
-					cset_call.add_argument (val_ptr);
-					cset_call.add_argument (new CCodeMemberAccess (new CCodeIdentifier (param.name), f.name));
-					block.add_statement (new CCodeExpressionStatement (cset_call));
-
-					var cappend_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_array_append"));
-					cappend_call.add_argument (dbus_param);
-					cappend_call.add_argument (val_ptr);
-					block.add_statement (new CCodeExpressionStatement (cappend_call));
-
-					type_call.add_argument (new CCodeIdentifier (f.field_type.data_type.get_type_id ()));
-				}
+			if (param.direction == ParameterDirection.IN) {
+				var target = new CCodeIdentifier (param.name);
+				var expr = read_expression (prefragment, param.parameter_type, new CCodeIdentifier ("iter"), target);
+				prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
+			} else {
+				write_expression (postfragment, param.parameter_type, new CCodeIdentifier ("iter"), new CCodeIdentifier (param.name));
 			}
 		}
 
 		if (!(m.return_type is VoidType)) {
-			var array_type = m.return_type as ArrayType;
-			if (array_type != null && array_type.element_type.data_type != string_type.data_type) {
-				var garray = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("dbus_result"));
+			cdecl = new CCodeDeclaration (m.return_type.get_cname ());
+			cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
+			block.add_statement (cdecl);
+			block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), ccall)));
 
-				var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
-				sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+			write_expression (postfragment, m.return_type, new CCodeIdentifier ("iter"), new CCodeIdentifier ("result"));
+		} else {
+			block.add_statement (new CCodeExpressionStatement (ccall));
+		}
 
-				if (dbus_use_ptr_array (array_type)) {
-					var array_construct = new CCodeFunctionCall (new CCodeIdentifier ("g_ptr_array_sized_new"));
-					array_construct.add_argument (new CCodeIdentifier ("result_length1"));
+		cdecl = new CCodeDeclaration ("DBusMessage*");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("reply"));
+		block.add_statement (cdecl);
 
-					block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (garray, array_construct)));
+		var msgcall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_new_method_return"));
+		msgcall.add_argument (new CCodeIdentifier ("message"));
+		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("reply"), msgcall)));
 
-					var memcpy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
-					memcpy_call.add_argument (new CCodeMemberAccess.pointer (garray, "pdata"));
-					memcpy_call.add_argument (new CCodeIdentifier ("result"));
-					memcpy_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeIdentifier ("result_length1"), sizeof_call));
-					block.add_statement (new CCodeExpressionStatement (memcpy_call));
+		block.add_statement (postfragment);
 
-					var len_assignment = new CCodeAssignment (new CCodeMemberAccess.pointer (garray, "len"), new CCodeIdentifier ("result_length1"));
-					block.add_statement (new CCodeExpressionStatement (len_assignment));
-				} else {
-					var array_construct = new CCodeFunctionCall (new CCodeIdentifier ("g_array_new"));
-					array_construct.add_argument (new CCodeConstant ("TRUE"));
-					array_construct.add_argument (new CCodeConstant ("TRUE"));
-					array_construct.add_argument (sizeof_call);
+		block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("reply")));
 
-					block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (garray, array_construct)));
-
-					var cappend_call = new CCodeFunctionCall (new CCodeIdentifier ("g_array_append_vals"));
-					cappend_call.add_argument (garray);
-					cappend_call.add_argument (new CCodeIdentifier ("result"));
-					cappend_call.add_argument (new CCodeIdentifier ("result_length1"));
-					block.add_statement (new CCodeExpressionStatement (cappend_call));
-				}
-			}
-		}
-
-		var no_error = new CCodeBinaryExpression (CCodeBinaryOperator.OR, new CCodeIdentifier ("!error"), new CCodeIdentifier ("!*error"));
-		block.add_statement (new CCodeReturnStatement (no_error));
-
-		// append to file
-
 		source_type_member_declaration.append (function.copy ());
 
 		function.block = block;
