virDomainGraphicsListenDefParseXML(virDomainGraphicsListenDefPtr def,
                                   virDomainGraphicsDefPtr graphics,
                                   xmlNodePtr node,
                                   xmlNodePtr parent,
                                   unsigned int flags)
{
    int ret = -1;
    const char *graphicsType = virDomainGraphicsTypeToString(graphics->type);
    int tmp, typeVal;
    g_autofree char *type = virXMLPropString(node, "type");
    g_autofree char *address = virXMLPropString(node, "address");
    g_autofree char *network = virXMLPropString(node, "network");
    g_autofree char *socketPath = virXMLPropString(node, "socket");
    g_autofree char *fromConfig = virXMLPropString(node, "fromConfig");
    g_autofree char *autoGenerated = virXMLPropString(node, "autoGenerated");
    g_autofree char *addressCompat = NULL;
    g_autofree char *socketCompat = NULL;

    if (parent) {
        addressCompat = virXMLPropString(parent, "listen");
        socketCompat = virXMLPropString(parent, "socket");
    }

    if (!type) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("graphics listen type must be specified"));
        goto error;
    }

    if ((typeVal = virDomainGraphicsListenTypeFromString(type)) < 0) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unknown graphics listen type '%s'"), type);
        goto error;
    }
    def->type = typeVal;

    switch (def->type) {
    case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET:
        if (graphics->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
            graphics->type != VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("listen type 'socket' is not available for "
                             "graphics type '%s'"), graphicsType);
            goto error;
        }
        break;
    case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE:
        if (graphics->type != VIR_DOMAIN_GRAPHICS_TYPE_SPICE &&
            graphics->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("listen type 'none' is not available for "
                             "graphics type '%s'"), graphicsType);
            goto error;
        }
        break;
    case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS:
    case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK:
    case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST:
        break;
    }

    if (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS) {
        if (address && addressCompat && STRNEQ(address, addressCompat)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("graphics 'listen' attribute '%s' must match "
                             "'address' attribute of first listen element "
                             "(found '%s')"), addressCompat, address);
            goto error;
        }

        if (!address)
            address = g_steal_pointer(&addressCompat);
    }

    if (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET) {
        if (socketPath && socketCompat && STRNEQ(socketPath, socketCompat)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("graphics 'socket' attribute '%s' must match "
                             "'socket' attribute of first listen element "
                             "(found '%s')"), socketCompat, socketPath);
            goto error;
        }

        if (!socketPath)
            socketPath = g_steal_pointer(&socketCompat);
    }

    if (address && address[0] &&
        (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS ||
         (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK &&
          !(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)))) {
        def->address = g_steal_pointer(&address);
    }

    if (network && network[0]) {
        if (def->type != VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("'network' attribute is valid only for listen "
                             "type 'network'"));
            goto error;
        }
        def->network = g_steal_pointer(&network);
    }

    if (socketPath && socketPath[0]) {
        if (def->type != VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("'socket' attribute is valid only for listen "
                             "type 'socket'"));
            goto error;
        }
        def->socket = g_steal_pointer(&socketPath);
    }

    if (fromConfig &&
        flags & VIR_DOMAIN_DEF_PARSE_STATUS) {
        if (virStrToLong_i(fromConfig, NULL, 10, &tmp) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid fromConfig value: %s"),
                           fromConfig);
            goto error;
        }
        def->fromConfig = tmp != 0;
    }

    if (autoGenerated &&
        flags & VIR_DOMAIN_DEF_PARSE_STATUS) {
        if (virStringParseYesNo(autoGenerated, &def->autoGenerated) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid autoGenerated value: %s"),
                           autoGenerated);
            goto error;
        }
    }

    ret = 0;
 error:
    if (ret < 0)
        virDomainGraphicsListenDefClear(def);
    return ret;
}