+static int copy_many_fields(DBusMessageIter *dest, DBusMessageIter *src);
+
+static int copy_one_field(DBusMessageIter *dest, DBusMessageIter *src) {
+ int type, r;
+
+ type = dbus_message_iter_get_arg_type(src);
+
+ switch (type) {
+
+ case DBUS_TYPE_STRUCT: {
+ DBusMessageIter dest_sub, src_sub;
+
+ dbus_message_iter_recurse(src, &src_sub);
+
+ if (!dbus_message_iter_open_container(dest, DBUS_TYPE_STRUCT, NULL, &dest_sub))
+ return log_oom();
+
+ r = copy_many_fields(&dest_sub, &src_sub);
+ if (r < 0)
+ return r;
+
+ if (!dbus_message_iter_close_container(dest, &dest_sub))
+ return log_oom();
+
+ return 0;
+ }
+
+ case DBUS_TYPE_ARRAY: {
+ DBusMessageIter dest_sub, src_sub;
+
+ dbus_message_iter_recurse(src, &src_sub);
+
+ if (!dbus_message_iter_open_container(dest, DBUS_TYPE_ARRAY, dbus_message_iter_get_signature(&src_sub), &dest_sub))
+ return log_oom();
+
+ r = copy_many_fields(&dest_sub, &src_sub);
+ if (r < 0)
+ return r;
+
+ if (!dbus_message_iter_close_container(dest, &dest_sub))
+ return log_oom();
+
+ return 0;
+ }
+
+ case DBUS_TYPE_VARIANT: {
+ DBusMessageIter dest_sub, src_sub;
+
+ dbus_message_iter_recurse(src, &src_sub);
+
+ if (!dbus_message_iter_open_container(dest, DBUS_TYPE_VARIANT, dbus_message_iter_get_signature(&src_sub), &dest_sub))
+ return log_oom();
+
+ r = copy_one_field(&dest_sub, &src_sub);
+ if (r < 0)
+ return r;
+
+ if (!dbus_message_iter_close_container(dest, &dest_sub))
+ return log_oom();
+
+ return 0;
+ }
+
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_BYTE:
+ case DBUS_TYPE_BOOLEAN:
+ case DBUS_TYPE_UINT16:
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_UINT32:
+ case DBUS_TYPE_INT32:
+ case DBUS_TYPE_UINT64:
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_DOUBLE:
+ case DBUS_TYPE_SIGNATURE: {
+ const void *p;
+
+ dbus_message_iter_get_basic(src, &p);
+ dbus_message_iter_append_basic(dest, type, &p);
+ return 0;
+ }
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int copy_many_fields(DBusMessageIter *dest, DBusMessageIter *src) {
+ int r;
+
+ assert(dest);
+ assert(src);
+
+ while (dbus_message_iter_get_arg_type(src) != DBUS_TYPE_INVALID) {
+
+ r = copy_one_field(dest, src);
+ if (r < 0)
+ return r;
+
+ dbus_message_iter_next(src);
+ }
+
+ return 0;
+}
+