/** @file vbox_tmpl.c
 * Template File to support multiple versions of VirtualBox
 * at runtime :).
 *
 * IMPORTANT:
 * Please dont include this file in the src/Makefile.am, it
 * is automatically include by other files.
 */

/*
 * Copyright (C) 2008-2009 Sun Microsystems, Inc.
 *
 * This file is part of a free software library; you can redistribute
 * it and/or modify it under the terms of the GNU Lesser General
 * Public License version 2.1 as published by the Free Software
 * Foundation and shipped in the "COPYING" file with this library.
 * The library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY of any kind.
 *
 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if
 * any license choice other than GPL or LGPL is available it will
 * apply instead, Sun elects to use only the Lesser General Public
 * License version 2.1 (LGPLv2) at this time for any software where
 * a choice of LGPL license versions is made available with the
 * language indicating that LGPLv2 or any later version may be used,
 * or where a choice of which version of the LGPL is applied is
 * otherwise unspecified.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 USA or visit http://www.sun.com if you need
 * additional information or have any questions.
 */

#include <config.h>

#include <dlfcn.h>
#include <sys/utsname.h>

#include "internal.h"

#include "datatypes.h"
#include "domain_conf.h"
#include "network_conf.h"
#include "virterror_internal.h"
#include "domain_event.h"
#include "uuid.h"
#include "event.h"
#include "memory.h"
#include "nodeinfo.h"
#include "logging.h"
#include "vbox_driver.h"

/* This one changes from version to version. */
#if VBOX_API_VERSION == 2002
# include "vbox_CAPI_v2_2.h"
#elif VBOX_API_VERSION == 3000
# include "vbox_CAPI_v3_0.h"
#else
# error "Unsupport VBOX_API_VERSION"
#endif

/* Include this *last* or we'll get the wrong vbox_CAPI_*.h. */
#include "vbox_XPCOMCGlue.h"


#define VIR_FROM_THIS VIR_FROM_VBOX

#define vboxError(conn, code, fmt...) \
        virReportErrorHelper(conn, VIR_FROM_VBOX, code, __FILE__, \
                            __FUNCTION__, __LINE__, fmt)

#define DEBUGPRUnichar(msg, strUtf16) \
if (strUtf16) {\
    char *strUtf8 = NULL;\
\
    g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(strUtf16, &strUtf8);\
    if (strUtf8) {\
        DEBUG("%s: %s", msg, strUtf8);\
        g_pVBoxGlobalData->pFuncs->pfnUtf8Free(strUtf8);\
    }\
}

#define DEBUGUUID(msg, iid) \
{\
    DEBUG (msg ": {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",\
          (unsigned)(iid)->m0,\
          (unsigned)(iid)->m1,\
          (unsigned)(iid)->m2,\
          (unsigned)(iid)->m3[0],\
          (unsigned)(iid)->m3[1],\
          (unsigned)(iid)->m3[2],\
          (unsigned)(iid)->m3[3],\
          (unsigned)(iid)->m3[4],\
          (unsigned)(iid)->m3[5],\
          (unsigned)(iid)->m3[6],\
          (unsigned)(iid)->m3[7]);\
}\

typedef struct {
    virMutex lock;
    int version;

    virDomainObjList domains;
    virCapsPtr caps;

    IVirtualBox *vboxObj;
    ISession *vboxSession;

    /** Our version specific API table pointer. */
    PCVBOXXPCOM pFuncs;

#if VBOX_API_VERSION == 2002

} vboxGlobalData;

#else /* !(VBOX_API_VERSION == 2002) */

    /* An array of callbacks */
    virDomainEventCallbackListPtr domainEventCallbacks;

    int fdWatch;
    int domainEventDispatching;

    IVirtualBoxCallback *vboxCallback;

    nsIEventQueue  *vboxQueue;
    int volatile vboxCallBackRefCount;

    /* pointer back to the connection */
    virConnectPtr conn;

} vboxGlobalData;

/* g_pVBoxGlobalData has to be global variable,
 * there is no other way to make the callbacks
 * work other then having g_pVBoxGlobalData as
 * global, because the functions namely AddRef,
 * Release, etc consider it as global and you
 * can't change the function definition as it
 * is XPCOM nsISupport::* function and it expects
 * them that way
 */

vboxGlobalData *g_pVBoxGlobalData = NULL;

#endif /* !(VBOX_API_VERSION == 2002) */

static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml);
static int vboxDomainCreate(virDomainPtr dom);
static int vboxDomainUndefine(virDomainPtr dom);

static void vboxDriverLock(vboxGlobalData *data) {
    virMutexLock(&data->lock);
}

static void vboxDriverUnlock(vboxGlobalData *data) {
    virMutexUnlock(&data->lock);
}

#if VBOX_API_VERSION == 2002
static void nsIDtoChar(unsigned char *uuid, const nsID *iid) {
    char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
    char uuidstrdst[VIR_UUID_STRING_BUFLEN];
    unsigned char uuidinterim[VIR_UUID_BUFLEN];
    int i;

    memcpy(uuidinterim, iid, VIR_UUID_BUFLEN);
    virUUIDFormat(uuidinterim, uuidstrsrc);

    uuidstrdst[0]  = uuidstrsrc[6];
    uuidstrdst[1]  = uuidstrsrc[7];
    uuidstrdst[2]  = uuidstrsrc[4];
    uuidstrdst[3]  = uuidstrsrc[5];
    uuidstrdst[4]  = uuidstrsrc[2];
    uuidstrdst[5]  = uuidstrsrc[3];
    uuidstrdst[6]  = uuidstrsrc[0];
    uuidstrdst[7]  = uuidstrsrc[1];

    uuidstrdst[8]  = uuidstrsrc[8];

    uuidstrdst[9]  = uuidstrsrc[11];
    uuidstrdst[10] = uuidstrsrc[12];
    uuidstrdst[11] = uuidstrsrc[9];
    uuidstrdst[12] = uuidstrsrc[10];

    uuidstrdst[13] = uuidstrsrc[13];

    uuidstrdst[14] = uuidstrsrc[16];
    uuidstrdst[15] = uuidstrsrc[17];
    uuidstrdst[16] = uuidstrsrc[14];
    uuidstrdst[17] = uuidstrsrc[15];

    for(i = 18; i < VIR_UUID_STRING_BUFLEN; i++) {
        uuidstrdst[i] = uuidstrsrc[i];
    }

    uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0';
    virUUIDParse(uuidstrdst, uuid);
}

static void nsIDFromChar(nsID *iid, const unsigned char *uuid) {
    char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
    char uuidstrdst[VIR_UUID_STRING_BUFLEN];
    unsigned char uuidinterim[VIR_UUID_BUFLEN];
    int i;

    virUUIDFormat(uuid, uuidstrsrc);

    uuidstrdst[0]  = uuidstrsrc[6];
    uuidstrdst[1]  = uuidstrsrc[7];
    uuidstrdst[2]  = uuidstrsrc[4];
    uuidstrdst[3]  = uuidstrsrc[5];
    uuidstrdst[4]  = uuidstrsrc[2];
    uuidstrdst[5]  = uuidstrsrc[3];
    uuidstrdst[6]  = uuidstrsrc[0];
    uuidstrdst[7]  = uuidstrsrc[1];

    uuidstrdst[8]  = uuidstrsrc[8];

    uuidstrdst[9]  = uuidstrsrc[11];
    uuidstrdst[10] = uuidstrsrc[12];
    uuidstrdst[11] = uuidstrsrc[9];
    uuidstrdst[12] = uuidstrsrc[10];

    uuidstrdst[13] = uuidstrsrc[13];

    uuidstrdst[14] = uuidstrsrc[16];
    uuidstrdst[15] = uuidstrsrc[17];
    uuidstrdst[16] = uuidstrsrc[14];
    uuidstrdst[17] = uuidstrsrc[15];

    for(i = 18; i < VIR_UUID_STRING_BUFLEN; i++) {
        uuidstrdst[i] = uuidstrsrc[i];
    }

    uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0';
    virUUIDParse(uuidstrdst, uuidinterim);
    memcpy(iid, uuidinterim, VIR_UUID_BUFLEN);
}

typedef nsID vboxIID;

#define vboxIIDFromUUID(uuid, iid) nsIDFromChar((iid), (uuid))
#define vboxIIDToUUID(uuid, iid) nsIDtoChar((uuid), (iid))
#define vboxIIDUnalloc(iid) data->pFuncs->pfnComUnallocMem(iid)
#define vboxIIDFree(iid) VIR_FREE(iid)

#else /* !(VBOX_API_VERSION == 2002) */

typedef PRUnichar vboxIID;

#define vboxIIDFromUUID(uuid, iid)\
{\
    char vboxIIDUtf8[VIR_UUID_STRING_BUFLEN];\
\
    virUUIDFormat((uuid), vboxIIDUtf8);\
    data->pFuncs->pfnUtf8ToUtf16(vboxIIDUtf8, (&(iid)));\
}

#define vboxIIDToUUID(uuid, iid)\
{\
    char *vboxIIDUtf8  = NULL;\
    data->pFuncs->pfnUtf16ToUtf8((iid), &vboxIIDUtf8);\
    virUUIDParse(vboxIIDUtf8, (uuid));\
    data->pFuncs->pfnUtf8Free(vboxIIDUtf8);\
}

#define vboxIIDFree(iid) data->pFuncs->pfnUtf16Free(iid)

#endif /* !(VBOX_API_VERSION == 2002) */

static virCapsPtr vboxCapsInit(void) {
    struct utsname utsname;
    virCapsPtr caps;
    virCapsGuestPtr guest;

    uname(&utsname);

    if ((caps = virCapabilitiesNew(utsname.machine,
                                   0, 0)) == NULL)
        goto no_memory;

    if (nodeCapsInitNUMA(caps) < 0)
        goto no_memory;

    virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x08, 0x00, 0x27 });

    if ((guest = virCapabilitiesAddGuest(caps,
                                         "hvm",
                                         utsname.machine,
                                         sizeof(void *) * CHAR_BIT,
                                         NULL,
                                         NULL,
                                         0,
                                         NULL)) == NULL)
        goto no_memory;

    if (virCapabilitiesAddGuestDomain(guest,
                                      "vbox",
                                      NULL,
                                      NULL,
                                      0,
                                      NULL) == NULL)
        goto no_memory;
    return caps;

no_memory:
    virCapabilitiesFree(caps);
    return NULL;
}

static int vboxInitialize(virConnectPtr conn, vboxGlobalData *data) {

    /* Get the API table for out version, g_pVBoxFuncs is for the oldest
       version of the API that we support so we cannot use that. */
    data->pFuncs = g_pfnGetFunctions(VBOX_XPCOMC_VERSION);

    if (data->pFuncs == NULL)
        goto cleanup;

#if VBOX_XPCOMC_VERSION == 0x00010000U
    data->pFuncs->pfnComInitialize(&data->vboxObj, &data->vboxSession);
#else  /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
    data->pFuncs->pfnComInitialize(IVIRTUALBOX_IID_STR, &data->vboxObj,
                               ISESSION_IID_STR, &data->vboxSession);

#if VBOX_API_VERSION == 2002

    /* No event queue functionality in 2.2.* as of now */

#else  /* !(VBOX_API_VERSION == 2002) */

    /* Initial the fWatch needed for Event Callbacks */
    data->fdWatch = -1;

    data->pFuncs->pfnGetEventQueue(&data->vboxQueue);

    if (data->vboxQueue == NULL) {
        vboxError(conn, VIR_ERR_INTERNAL_ERROR, "nsIEventQueue object is null");
        goto cleanup;
    }

#endif /* !(VBOX_API_VERSION == 2002) */
#endif /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */

    if (data->vboxObj == NULL) {
        vboxError(conn, VIR_ERR_INTERNAL_ERROR, "IVirtualBox object is null");
        goto cleanup;
    }

    if (data->vboxSession == NULL) {
        vboxError(conn, VIR_ERR_INTERNAL_ERROR, "ISession object is null");
        goto cleanup;
    }

    return 0;

cleanup:
    return -1;
}

static int vboxExtractVersion(virConnectPtr conn, vboxGlobalData *data) {
    unsigned int major      = 0;
    unsigned int minor      = 0;
    unsigned int micro      = 0;
    int          ret        = -1;
    PRUnichar *versionUtf16 = NULL;
    nsresult rc;

    if (data->version > 0)
        return 0;

    rc = data->vboxObj->vtbl->GetVersion(data->vboxObj, &versionUtf16);
    if (NS_SUCCEEDED(rc)) {
        char *vboxVersion = NULL;

        data->pFuncs->pfnUtf16ToUtf8(versionUtf16, &vboxVersion);

        if (sscanf(vboxVersion, "%u.%u.%u", &major, &minor, &micro) == 3)
            ret = 0;

        data->pFuncs->pfnUtf8Free(vboxVersion);
        data->pFuncs->pfnComUnallocMem(versionUtf16);
    } else {
        ret = -1;
    }

    data->version = (major * 1000 * 1000) + (minor * 1000) + micro;

    if (ret != 0)
        vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s",
                  "Cound not extract VirtualBox version");
    return ret;
}

static void vboxUninitialize(vboxGlobalData *data) {
    if (!data)
        return;

    if (data->pFuncs)
        data->pFuncs->pfnComUninitialize();

    virDomainObjListFree(&data->domains);
    virCapabilitiesFree(data->caps);
#if VBOX_API_VERSION == 2002
    /* No domainEventCallbacks in 2.2.* version */
#else  /* !(VBOX_API_VERSION == 2002) */
    VIR_FREE(data->domainEventCallbacks);
#endif /* !(VBOX_API_VERSION == 2002) */
    VIR_FREE(data);
}

static virDrvOpenStatus vboxOpen(virConnectPtr conn,
                                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                 int flags ATTRIBUTE_UNUSED) {
    vboxGlobalData *data = NULL;
    uid_t uid = getuid();

    if (conn->uri == NULL) {
        conn->uri = xmlParseURI(uid ? "vbox:///session" : "vbox:///system");
        if (conn->uri == NULL) {
            virReportOOMError(conn);
            return VIR_DRV_OPEN_ERROR;
        }
    }

    if (conn->uri->scheme == NULL ||
        STRNEQ (conn->uri->scheme, "vbox"))
        return VIR_DRV_OPEN_DECLINED;

    /* Leave for remote driver */
    if (conn->uri->server != NULL)
        return VIR_DRV_OPEN_DECLINED;

    if (conn->uri->path == NULL || STREQ(conn->uri->path, "")) {
        vboxError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
                  _("no VirtualBox driver path specified (try vbox:///session)"));
        return VIR_DRV_OPEN_ERROR;
    }

    if (uid != 0) {
        if (STRNEQ (conn->uri->path, "/session")) {
            vboxError(conn, VIR_ERR_INTERNAL_ERROR,
                      _("unknown driver path '%s' specified (try vbox:///session)"), conn->uri->path);
            return VIR_DRV_OPEN_ERROR;
        }
    } else { /* root */
        if (STRNEQ (conn->uri->path, "/system") &&
            STRNEQ (conn->uri->path, "/session")) {
            vboxError(conn, VIR_ERR_INTERNAL_ERROR,
                      _("unknown driver path '%s' specified (try vbox:///system)"), conn->uri->path);
            return VIR_DRV_OPEN_ERROR;
        }
    }

    if (VIR_ALLOC(data) < 0) {
        virReportOOMError(conn);
        return VIR_DRV_OPEN_ERROR;
    }

    if (!(data->caps = vboxCapsInit()) ||
        vboxInitialize(conn, data) < 0 ||
        vboxExtractVersion(conn, data) < 0) {
        vboxUninitialize(data);
        return VIR_DRV_OPEN_ERROR;
    }

#if VBOX_API_VERSION == 2002

    /* No domainEventCallbacks in 2.2.* version */

#else  /* !(VBOX_API_VERSION == 2002) */

    if (VIR_ALLOC(data->domainEventCallbacks) < 0) {
        virReportOOMError(conn);
        return VIR_DRV_OPEN_ERROR;
    }

    data->conn = conn;
    g_pVBoxGlobalData = data;

#endif /* !(VBOX_API_VERSION == 2002) */

    conn->privateData = data;
    DEBUG0("in vboxOpen");

    return VIR_DRV_OPEN_SUCCESS;
}

static int vboxClose(virConnectPtr conn) {
    vboxGlobalData *data = conn->privateData;
    DEBUG("%s: in vboxClose",conn->driver->name);

    vboxUninitialize(data);
    conn->privateData = NULL;

    return 0;
}

static int vboxGetVersion(virConnectPtr conn, unsigned long *version) {
    vboxGlobalData *data = conn->privateData;
    DEBUG("%s: in vboxGetVersion",conn->driver->name);

    vboxDriverLock(data);
    *version = data->version;
    vboxDriverUnlock(data);

    return 0;
}

static char *vboxGetHostname(virConnectPtr conn) {
    char *hostname;

    /* the return string should be freed by caller */
    hostname = virGetHostname();
    if (hostname == NULL) {
        vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s",
                  "failed to determine host name");
        return NULL;
    }

    return hostname;
}

static int vboxGetMaxVcpus(virConnectPtr conn, const char *type ATTRIBUTE_UNUSED) {
    vboxGlobalData *data = conn->privateData;
    PRUint32 maxCPUCount = 0;
    int ret = -1;

    /* VirtualBox Supports only hvm and thus the type passed to it
     * has no meaning, setting it to ATTRIBUTE_UNUSED
     */
    if(data->vboxObj) {
        ISystemProperties *systemProperties = NULL;

        data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
        if (systemProperties) {
            systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, &maxCPUCount);
            systemProperties->vtbl->nsisupports.Release((nsISupports *)systemProperties);
        }
    }

    if (maxCPUCount > 0)
        ret = maxCPUCount;

    return ret;
}


static char *vboxGetCapabilities(virConnectPtr conn) {
    vboxGlobalData *data = conn->privateData;
    char *ret;

    vboxDriverLock(data);
    ret = virCapabilitiesFormatXML(data->caps);
    vboxDriverUnlock(data);

    return ret;
}

static int vboxListDomains(virConnectPtr conn, int *ids, int nids) {
    nsresult rc;
    vboxGlobalData *data = conn->privateData;
    IMachine **machines  = NULL;
    PRUint32 machineCnt  = 0;
    PRUint32 state;
    int ret = -1;
    int i, j;

    if(data->vboxObj) {
        rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
        if (NS_FAILED(rc)) {
            vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
                      "Could not get list of Domains",(unsigned)rc);
            goto cleanup;
        }

        if (machineCnt == 0) {
            ret = 0;
            goto cleanup;
        }

        for (i = 0,j = 0; (i < machineCnt) && (j < nids); ++i) {
            IMachine *machine = machines[i];

            if (machine) {
                PRBool isAccessible = PR_FALSE;
                machine->vtbl->GetAccessible(machine, &isAccessible);
                if (isAccessible) {
                    machine->vtbl->GetState(machine, &state);
                    if ((state == MachineState_Starting)   ||
                        (state == MachineState_Running)    ||
                        (state == MachineState_Stuck)      ||
                        (state == MachineState_Stopping)   ||
                        (state == MachineState_Saving)     ||
                        (state == MachineState_Restoring)  ||
                        (state == MachineState_Discarding) ||
                        (state == MachineState_Paused) ) {
                        ret++;
                        ids[j++] = i + 1;
                    }
                }
            }
        }
        ret++;
    }

cleanup:
    for (i = 0; i < machineCnt; ++i)
        if (machines[i])
            machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
    return ret;
}

static int vboxNumOfDomains(virConnectPtr conn) {
    nsresult rc;
    vboxGlobalData *data = conn->privateData;
    IMachine **machines  = NULL;
    PRUint32 machineCnt  = 0;
    PRUint32 state;
    int ret = -1;
    int i;

    if(data->vboxObj) {
        rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
        if (NS_FAILED(rc)) {
            vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
                      "Could not get number of Domains",(unsigned)rc);
            goto cleanup;
        }

        if (machineCnt == 0) {
            ret = 0;
            goto cleanup;
        }

        /* Do the cleanup as required by GetMachines() */
        for (i = 0; i < machineCnt; ++i) {
            IMachine *machine = machines[i];

            if (machine) {
                PRBool isAccessible = PR_FALSE;
                machine->vtbl->GetAccessible(machine, &isAccessible);
                if (isAccessible) {
                    machine->vtbl->GetState(machine, &state);
                    if ((state == MachineState_Starting)   ||
                        (state == MachineState_Running)    ||
                        (state == MachineState_Stuck)      ||
                        (state == MachineState_Stopping)   ||
                        (state == MachineState_Saving)     ||
                        (state == MachineState_Restoring)  ||
                        (state == MachineState_Discarding) ||
                        (state == MachineState_Paused) ) {
                        ret++;
                    }
                }
            }
        }
        ret++;
    }

cleanup:
    for (i = 0; i < machineCnt; ++i)
        if (machines[i])
            machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
    return ret;
}

static virDomainPtr vboxDomainCreateXML(virConnectPtr conn, const char *xml,
                                        unsigned int flags ATTRIBUTE_UNUSED) {
    virDomainPtr dom = NULL;

    /* VirtualBox currently doesn't have support for running
     * virtual machines without actually defining them and thus
     * for time being just define new machine and start it.
     *
     * TODO: After the appropriate API's are added in VirtualBox
     * change this behaviour to the expected one.
     */

    dom = vboxDomainDefineXML(conn, xml);
    if (dom) {
        if (vboxDomainCreate(dom) < 0)
            goto cleanup;
    } else {
        goto cleanup;
    }

    return dom;

cleanup:
    vboxDomainUndefine(dom);
    return NULL;
}

static virDomainPtr vboxDomainLookupByID(virConnectPtr conn, int id) {
    nsresult rc;
    vboxGlobalData *data = conn->privateData;
    IMachine **machines  = NULL;
    PRUint32 machineCnt  = 0;
    virDomainPtr dom     = NULL;
    vboxIID *iid         = NULL;
    unsigned char iidl[VIR_UUID_BUFLEN];
    PRUint32 state;
    int i;

    /* Internal vbox IDs start from 0, the public libvirt ID
     * starts from 1, so refuse id==0, and adjust the rest*/
    if (id == 0) {
        vboxError(conn, VIR_ERR_NO_DOMAIN,
                  _("no domain with matching id %d"), id);
        return NULL;
    }
    id = id - 1;

    if(data->vboxObj) {
        rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
        if (NS_FAILED(rc)) {
            vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
                      "Could not get list of machines",(unsigned)rc);
            return NULL;
        }

        if (id < machineCnt) {
            if (machines[id]) {
                PRBool isAccessible = PR_FALSE;
                machines[id]->vtbl->GetAccessible(machines[id], &isAccessible);
                if (isAccessible) {
                    machines[id]->vtbl->GetState(machines[id], &state);
                    if ((state == MachineState_Starting)   ||
                        (state == MachineState_Running)    ||
                        (state == MachineState_Stuck)      ||
                        (state == MachineState_Stopping)   ||
                        (state == MachineState_Saving)     ||
                        (state == MachineState_Restoring)  ||
                        (state == MachineState_Discarding) ||
                        (state == MachineState_Paused) ) {
                        PRUnichar *machineNameUtf16 = NULL;
                        char      *machineNameUtf8  = NULL;

                        machines[id]->vtbl->GetName(machines[id], &machineNameUtf16);
                        data->pFuncs->pfnUtf16ToUtf8(machineNameUtf16, &machineNameUtf8);

                        machines[id]->vtbl->GetId(machines[id], &iid);
                        vboxIIDToUUID(iidl, iid);
#if VBOX_API_VERSION == 2002
                        vboxIIDUnalloc(iid);
#else
                        vboxIIDFree(iid);
#endif

                        /* get a new domain pointer from virGetDomain, if it fails
                         * then no need to assign the id, else assign the id, cause
                         * it is -1 by default. rest is taken care by virGetDomain
                         * itself, so need not worry.
                         */

                        dom = virGetDomain(conn, machineNameUtf8, iidl);
                        if (dom)
                            dom->id = id + 1;

                        /* Cleanup all the XPCOM allocated stuff here */
                        data->pFuncs->pfnUtf8Free(machineNameUtf8);
                        data->pFuncs->pfnUtf16Free(machineNameUtf16);
                    }
                }
            }
        }

        /* Do the cleanup as required by GetMachines() */
        for (i = 0; i < machineCnt; ++i) {
            if (machines[i])
                machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
        }
    }

    return dom;
}

static virDomainPtr vboxDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid) {
    nsresult rc;
    vboxGlobalData *data = conn->privateData;
    IMachine **machines  = NULL;
    PRUint32 machineCnt  = 0;
    virDomainPtr dom     = NULL;
    vboxIID *iid         = NULL;
    char      *machineNameUtf8  = NULL;
    PRUnichar *machineNameUtf16 = NULL;
    unsigned char iidl[VIR_UUID_BUFLEN];
    int i, matched = 0;

    if(data->vboxObj) {
        rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
        if (NS_FAILED(rc)) {
            vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
                      "Could not get list of machines",(unsigned)rc);
            return NULL;
        }

        for (i = 0; i < machineCnt; ++i) {
            IMachine *machine = machines[i];
            PRBool isAccessible = PR_FALSE;

            if (!machine)
                continue;

            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {

                machine->vtbl->GetId(machine, &iid);
                if (!iid)
                    continue;
                vboxIIDToUUID(iidl, iid);
#if VBOX_API_VERSION == 2002
                vboxIIDUnalloc(iid);
#else
                vboxIIDFree(iid);
#endif

                if (memcmp(uuid, iidl, VIR_UUID_BUFLEN) == 0) {

                    PRUint32 state;

                    matched = 1;

                    machine->vtbl->GetName(machine, &machineNameUtf16);
                    data->pFuncs->pfnUtf16ToUtf8(machineNameUtf16, &machineNameUtf8);

                    machine->vtbl->GetState(machine, &state);

                    /* get a new domain pointer from virGetDomain, if it fails
                     * then no need to assign the id, else assign the id, cause
                     * it is -1 by default. rest is taken care by virGetDomain
                     * itself, so need not worry.
                     */

                    dom = virGetDomain(conn, machineNameUtf8, iidl);
                    if (dom)
                        if ((state == MachineState_Starting)   ||
                            (state == MachineState_Running)    ||
                            (state == MachineState_Stuck)      ||
                            (state == MachineState_Stopping)   ||
                            (state == MachineState_Saving)     ||
                            (state == MachineState_Restoring)  ||
                            (state == MachineState_Discarding) ||
                            (state == MachineState_Paused) )
                            dom->id = i + 1;
                }

                if (matched == 1)
                    break;
            }
        }

        /* Do the cleanup and take care you dont leak any memory */
        if (machineNameUtf8)
            data->pFuncs->pfnUtf8Free(machineNameUtf8);
        if (machineNameUtf16)
            data->pFuncs->pfnComUnallocMem(machineNameUtf16);
        for (i = 0; i < machineCnt; ++i) {
            if (machines[i])
                machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
        }
    }

    return dom;
}

static virDomainPtr vboxDomainLookupByName(virConnectPtr conn, const char *name) {
    nsresult rc;
    vboxGlobalData *data = conn->privateData;
    IMachine **machines  = NULL;
    PRUint32 machineCnt  = 0;
    virDomainPtr dom     = NULL;
    vboxIID *iid         = NULL;
    char      *machineNameUtf8  = NULL;
    PRUnichar *machineNameUtf16 = NULL;
    unsigned char iidl[VIR_UUID_BUFLEN];
    int i, matched = 0;

    if(data->vboxObj) {
        rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
        if (NS_FAILED(rc)) {
            vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
                      "Could not get list of machines",(unsigned)rc);
            return NULL;
        }

        for (i = 0; i < machineCnt; ++i) {
            IMachine *machine = machines[i];
            PRBool isAccessible = PR_FALSE;

            if (!machine)
                continue;

            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {

                machine->vtbl->GetName(machine, &machineNameUtf16);
                data->pFuncs->pfnUtf16ToUtf8(machineNameUtf16, &machineNameUtf8);

                if (STREQ(name, machineNameUtf8)) {

                    PRUint32 state;

                    matched = 1;

                    machine->vtbl->GetId(machine, &iid);
                    vboxIIDToUUID(iidl, iid);
#if VBOX_API_VERSION == 2002
                    vboxIIDUnalloc(iid);
#else
                    vboxIIDFree(iid);
#endif

                    machine->vtbl->GetState(machine, &state);

                    /* get a new domain pointer from virGetDomain, if it fails
                     * then no need to assign the id, else assign the id, cause
                     * it is -1 by default. rest is taken care by virGetDomain
                     * itself, so need not worry.
                     */

                    dom = virGetDomain(conn, machineNameUtf8, iidl);
                    if (dom)
                        if ((state == MachineState_Starting)   ||
                            (state == MachineState_Running)    ||
                            (state == MachineState_Stuck)      ||
                            (state == MachineState_Stopping)   ||
                            (state == MachineState_Saving)     ||
                            (state == MachineState_Restoring)  ||
                            (state == MachineState_Discarding) ||
                            (state == MachineState_Paused) )
                            dom->id = i + 1;
                }

                if (machineNameUtf8) {
                    data->pFuncs->pfnUtf8Free(machineNameUtf8);
                    machineNameUtf8 = NULL;
                }
                if (machineNameUtf16) {
                    data->pFuncs->pfnComUnallocMem(machineNameUtf16);
                    machineNameUtf16 = NULL;
                }
                if (matched == 1)
                    break;
            }
        }

        /* Do the cleanup and take care you dont leak any memory */
        for (i = 0; i < machineCnt; ++i) {
            if (machines[i])
                machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
        }
    }

    return dom;
}

static int vboxDomainSuspend(virDomainPtr dom) {
    nsresult rc;
    vboxGlobalData *data = dom->conn->privateData;
    IMachine *machine    = NULL;
    vboxIID  *iid        = NULL;
    IConsole *console    = NULL;
    PRUint32 state;
    int ret = -1;

#if VBOX_API_VERSION == 2002
    if (VIR_ALLOC(iid) < 0) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }
#endif

    if (data->vboxObj) {
        PRBool isAccessible = PR_FALSE;

        vboxIIDFromUUID(dom->uuid, iid);
        rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
        if (NS_FAILED(rc)) {
            vboxError(dom->conn, VIR_ERR_INVALID_DOMAIN,
                            "no domain with matching id %d", dom->id);
            goto cleanup;
        }

        if (!machine)
            goto cleanup;

        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
            machine->vtbl->GetState(machine, &state);

            if (state == MachineState_Running) {
                 /* set state pause */
                data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
                data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
                if (console) {
                    console->vtbl->Pause(console);
                    console->vtbl->nsisupports.Release((nsISupports *)console);
                    ret = 0;
                } else {
                    vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
                              "%s", "error while suspend the domain");
                    goto cleanup;
                }
                data->vboxSession->vtbl->Close(data->vboxSession);
            } else {
                vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
                          "%s", "machine not in running state to suspend it");
                goto cleanup;
            }
        }
    }

cleanup:
    if (machine)
        machine->vtbl->nsisupports.Release((nsISupports *)machine);

    vboxIIDFree(iid);
    return ret;
}

static int vboxDomainResume(virDomainPtr dom) {
    nsresult rc;
    vboxGlobalData *data = dom->conn->privateData;
    IMachine *machine    = NULL;
    vboxIID  *iid        = NULL;
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
    int ret = -1;

#if VBOX_API_VERSION == 2002
    if (VIR_ALLOC(iid) < 0) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }
#endif

    if (data->vboxObj) {
        PRBool isAccessible = PR_FALSE;

        vboxIIDFromUUID(dom->uuid, iid);
        rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
        if (NS_FAILED(rc)) {
            vboxError(dom->conn, VIR_ERR_INVALID_DOMAIN,
                            "no domain with matching id %d", dom->id);
            goto cleanup;
        }

        if (!machine)
            goto cleanup;

        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
            machine->vtbl->GetState(machine, &state);

            if (state == MachineState_Paused) {
                 /* resume the machine here */
                data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
                data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
                if (console) {
                    console->vtbl->Resume(console);
                    console->vtbl->nsisupports.Release((nsISupports *)console);
                    ret = 0;
                } else {
                    vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
                              "%s", "error while resuming the domain");
                    goto cleanup;
                }
                data->vboxSession->vtbl->Close(data->vboxSession);
            } else {
                vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
                          "%s", "machine not paused, so can't resume it");
                goto cleanup;
            }
        }
    }

cleanup:
    if (machine)
        machine->vtbl->nsisupports.Release((nsISupports *)machine);

    vboxIIDFree(iid);
    return ret;
}

static int vboxDomainShutdown(virDomainPtr dom) {
    nsresult rc;
    vboxGlobalData *data = dom->conn->privateData;
    IMachine *machine    = NULL;
    vboxIID  *iid        = NULL;
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
    int ret = -1;

#if VBOX_API_VERSION == 2002
    if (VIR_ALLOC(iid) < 0) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }
#endif

    if(data->vboxObj) {
        PRBool isAccessible = PR_FALSE;

        vboxIIDFromUUID(dom->uuid, iid);
        rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
        if (NS_FAILED(rc)) {
            vboxError(dom->conn, VIR_ERR_INVALID_DOMAIN,
                            "no domain with matching id %d", dom->id);
            goto cleanup;
        }

        if (!machine)
            goto cleanup;

        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
            machine->vtbl->GetState(machine, &state);

            if (state == MachineState_Paused) {
                vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
                          "%s", "machine paused, so can't power it down");
                goto cleanup;
            } else if (state == MachineState_PoweredOff) {
                vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
                          "%s", "machine already powered down");
                goto cleanup;
            }

            data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
            data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (console) {
                console->vtbl->PowerButton(console);
                console->vtbl->nsisupports.Release((nsISupports *)console);
                ret = 0;
            }
            data->vboxSession->vtbl->Close(data->vboxSession);
        }
    }

cleanup:
    if (machine)
        machine->vtbl->nsisupports.Release((nsISupports *)machine);

    vboxIIDFree(iid);
    return ret;
}

static int vboxDomainReboot(virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) {
    nsresult rc;
    vboxGlobalData *data = dom->conn->privateData;
    IMachine *machine    = NULL;
    vboxIID  *iid        = NULL;
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
    int ret = -1;

#if VBOX_API_VERSION == 2002
    if (VIR_ALLOC(iid) < 0) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }
#endif

    if(data->vboxObj) {
        PRBool isAccessible = PR_FALSE;

        vboxIIDFromUUID(dom->uuid, iid);
        rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
        if (NS_FAILED(rc)) {
            vboxError(dom->conn, VIR_ERR_INVALID_DOMAIN,
                            "no domain with matching id %d", dom->id);
            goto cleanup;
        }

        if (!machine)
            goto cleanup;

        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
            machine->vtbl->GetState(machine, &state);

            if (state == MachineState_Running) {
                data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
                data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
                if (console) {
                    console->vtbl->Reset(console);
                    console->vtbl->nsisupports.Release((nsISupports *)console);
                    ret = 0;
                }
                data->vboxSession->vtbl->Close(data->vboxSession);
            } else {
                vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
                          "%s", "machine not running, so can't reboot it");
                goto cleanup;
            }
        }
    }

cleanup:
    if (machine)
        machine->vtbl->nsisupports.Release((nsISupports *)machine);

    vboxIIDFree(iid);
    return ret;
}

static int vboxDomainDestroy(virDomainPtr dom) {
    nsresult rc;
    vboxGlobalData *data = dom->conn->privateData;
    IMachine *machine    = NULL;
    vboxIID  *iid        = NULL;
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
    int ret = -1;

#if VBOX_API_VERSION == 2002
    if (VIR_ALLOC(iid) < 0) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }
#endif

    if(data->vboxObj) {
        PRBool isAccessible = PR_FALSE;

        vboxIIDFromUUID(dom->uuid, iid);
        rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
        if (NS_FAILED(rc)) {
            vboxError(dom->conn, VIR_ERR_INVALID_DOMAIN,
                            "no domain with matching id %d", dom->id);
            goto cleanup;
        }

        if (!machine)
            goto cleanup;

        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
            machine->vtbl->GetState(machine, &state);

            if (state == MachineState_PoweredOff) {
                vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
                          "%s", "machine already powered down");
                goto cleanup;
            }

            data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
            data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (console) {

#if VBOX_API_VERSION == 2002
                console->vtbl->PowerDown(console);
#else
                IProgress *progress;
                console->vtbl->PowerDown(console, &progress);
                if (progress)
                    progress->vtbl->nsisupports.Release((nsISupports *)progress);
#endif
                console->vtbl->nsisupports.Release((nsISupports *)console);
                ret = 0;
            }
            data->vboxSession->vtbl->Close(data->vboxSession);
        }
    }

cleanup:
    if (machine)
        machine->vtbl->nsisupports.Release((nsISupports *)machine);

    vboxIIDFree(iid);
    return ret;
}

static char *vboxDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED) {
    /* Returning "hvm" always as suggested on list, cause
     * this functions seems to be badly named and it
     * is supposed to pass the ABI name and not the domain
     * operating system driver as I had imagined ;)
     */
    return strdup("hvm");
}

static int vboxDomainSetMemory(virDomainPtr dom, unsigned long memory) {
    nsresult rc;
    vboxGlobalData *data = dom->conn->privateData;
    IMachine *machine    = NULL;
    vboxIID  *iid        = NULL;
    PRUint32 state       = MachineState_Null;
    int ret = -1;

#if VBOX_API_VERSION == 2002
    if (VIR_ALLOC(iid) < 0) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }
#endif

    if(data->vboxObj) {
        PRBool isAccessible = PR_FALSE;

        vboxIIDFromUUID(dom->uuid, iid);
        rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
        if (NS_FAILED(rc)) {
            vboxError(dom->conn, VIR_ERR_INVALID_DOMAIN,
                            "no domain with matching id %d", dom->id);
            goto cleanup;
        }

        if (!machine)
            goto cleanup;

        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
            machine->vtbl->GetState(machine, &state);

            if (state != MachineState_PoweredOff) {
                vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
                          "%s", "memory size can't be changed unless domain is powered down");
                goto cleanup;
            }

            rc = data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, iid);
            if (NS_SUCCEEDED(rc)) {
                rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
                if (NS_SUCCEEDED(rc) && machine) {

                    rc = machine->vtbl->SetMemorySize(machine, memory / 1024);
                    if (NS_SUCCEEDED(rc)) {
                        machine->vtbl->SaveSettings(machine);
                        ret = 0;
                    } else {
                        vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s:%lu Kb, rc=%08x",
                                  "could not set the memory size of the domain to",
                                  memory, (unsigned)rc);
                    }
                }
                data->vboxSession->vtbl->Close(data->vboxSession);
            }
        }
    }

cleanup:
    if (machine)
        machine->vtbl->nsisupports.Release((nsISupports *)machine);

    vboxIIDFree(iid);
    return ret;
}

static int vboxDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) {
    nsresult rc;
    vboxGlobalData *data = dom->conn->privateData;
    IMachine **machines  = NULL;
    PRUint32 machineCnt  = 0;
    char *machineName    = NULL;
    PRUnichar *machineNameUtf16 = NULL;
    int i, ret = -1;

    if(data->vboxObj) {
        rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
        if (NS_FAILED(rc)) {
            vboxError(NULL, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
                      "Could not get list of machines",(unsigned)rc);
            goto cleanup;
        }

        info->nrVirtCpu = 0;
        for (i = 0; i < machineCnt; ++i) {
            IMachine *machine = machines[i];
            PRBool isAccessible = PR_FALSE;

            if (!machine)
                continue;

            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {

                machine->vtbl->GetName(machine, &machineNameUtf16);
                data->pFuncs->pfnUtf16ToUtf8(machineNameUtf16, &machineName);

                if (STREQ(dom->name, machineName)) {
                    /* Get the Machine State (also match it with
                    * virDomainState). Get the Machine memory and
                    * for time being set maxmem and memory to same
                    * Also since there is no direct way of checking
                    * the cputime required (one condition being the
                    * VM is remote), return zero for cputime. Get the
                    * number of CPU (This is 1 for current
                    * VirtualBox builds).
                    */
                    PRUint32 CPUCount   = 0;
                    PRUint32 memorySize = 0;
                    PRUint32 state      = MachineState_Null;
                    PRUint32 maxMemorySize = 4 * 1024;
                    ISystemProperties *systemProperties = NULL;

                    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
                    if (systemProperties) {
                        systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize);
                        systemProperties->vtbl->nsisupports.Release((nsISupports *)systemProperties);
                        systemProperties = NULL;
                    }


                    machine->vtbl->GetCPUCount(machine, &CPUCount);
                    machine->vtbl->GetMemorySize(machine, &memorySize);
                    machine->vtbl->GetState(machine, &state);

                    info->cpuTime = 0;
                    info->nrVirtCpu = CPUCount;
                    info->memory = memorySize * 1024;
                    info->maxMem = maxMemorySize * 1024;
                    switch(state) {
                        case MachineState_Running:
                            info->state = VIR_DOMAIN_RUNNING;
                            break;
                        case MachineState_Stuck:
                            info->state = VIR_DOMAIN_BLOCKED;
                            break;
                        case MachineState_Paused:
                            info->state = VIR_DOMAIN_PAUSED;
                            break;
                        case MachineState_Stopping:
                            info->state = VIR_DOMAIN_SHUTDOWN;
                            break;
                        case MachineState_PoweredOff:
                            info->state = VIR_DOMAIN_SHUTOFF;
                            break;
                        case MachineState_Aborted:
                            info->state = VIR_DOMAIN_CRASHED;
                            break;
                        case MachineState_Null:
                        default:
                            info->state = VIR_DOMAIN_NOSTATE;
                            break;
                    }
                }

                if (machineName)
                    data->pFuncs->pfnUtf8Free(machineName);
                if (machineNameUtf16)
                    data->pFuncs->pfnComUnallocMem(machineNameUtf16);
                if (info->nrVirtCpu)
                    break;
            }

        }

        /* Do the cleanup and take care you dont leak any memory */
        for (i = 0; i < machineCnt; ++i) {
            if (machines[i])
                machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
        }
    }

    ret = 0;

cleanup:
    return ret;
}

static int vboxDomainSave(virDomainPtr dom, const char *path ATTRIBUTE_UNUSED) {
    nsresult rc;
    vboxGlobalData *data = dom->conn->privateData;
    IConsole *console    = NULL;
    vboxIID  *iid        = NULL;
    int ret = -1;

    /* VirtualBox currently doesn't support saving to a file
     * at a location other then the machine folder and thus
     * setting path to ATTRIBUTE_UNUSED for now, will change
     * this behaviour once get the VirtualBox API in right
     * shape to do this
     */
#if VBOX_API_VERSION == 2002
    if (VIR_ALLOC(iid) < 0) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }
#endif

    if(data->vboxObj) {

        /* Open a Session for the machine */
        vboxIIDFromUUID(dom->uuid, iid);
        rc = data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (NS_SUCCEEDED(rc) && console) {
                IProgress *progress = NULL;

                console->vtbl->SaveState(console, &progress);

                if (progress) {
#if VBOX_API_VERSION == 2002
                    nsresult resultCode;
#else
                    PRInt32 resultCode;
#endif

                    progress->vtbl->WaitForCompletion(progress, -1);
                    progress->vtbl->GetResultCode(progress, &resultCode);
                    if (NS_SUCCEEDED(resultCode)) {
                        ret = 0;
                    }
                    progress->vtbl->nsisupports.Release((nsISupports *)progress);
                }
                console->vtbl->nsisupports.Release((nsISupports *)console);
            }
            data->vboxSession->vtbl->Close(data->vboxSession);
        }

#if VBOX_API_VERSION == 2002
        DEBUGUUID("UUID of machine being saved:", iid);
#else
        DEBUGPRUnichar("UUID of machine being saved:", iid);
#endif
    }

#if VBOX_API_VERSION == 2002
cleanup:
#endif
    vboxIIDFree(iid);
    return ret;
}

static char *vboxDomainDumpXML(virDomainPtr dom, int flags) {
    nsresult rc;
    vboxGlobalData *data = dom->conn->privateData;
    virDomainDefPtr def  = NULL;
    IMachine *machine    = NULL;
    vboxIID  *iid        = NULL;
    char *ret            = NULL;
    int gotAllABoutDef   = -1;

#if VBOX_API_VERSION == 2002
    if (VIR_ALLOC(iid) < 0) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }
#endif

    if (VIR_ALLOC(def) < 0) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }

    if(data->vboxObj) {

        vboxIIDFromUUID(dom->uuid, iid);
        rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
        if (NS_SUCCEEDED(rc) && machine) {
            PRBool accessible = PR_FALSE;

            machine->vtbl->GetAccessible(machine, &accessible);
            if (accessible) {
                int i = 0;
                struct utsname utsname;
                PRBool PAEEnabled                   = PR_FALSE;
                PRBool ACPIEnabled                  = PR_FALSE;
                PRBool IOAPICEnabled                = PR_FALSE;
                PRBool VRDPEnabled                  = PR_FALSE;
                PRInt32 hddNum                      = 0;
                PRUint32 CPUCount                   = 0;
                PRUint32 memorySize                 = 0;
                PRUint32 netAdpCnt                  = 0;
                PRUint32 netAdpIncCnt               = 0;
                PRUint32 maxMemorySize              = 4 * 1024;
                PRUint32 USBFilterCount             = 0;
                PRUint32 maxBootPosition            = 0;
                PRUint32 serialPortCount            = 0;
                PRUint32 serialPortIncCount         = 0;
                PRUint32 parallelPortCount          = 0;
                PRUint32 parallelPortIncCount       = 0;
                IBIOSSettings *bios                 = NULL;
                IDVDDrive *dvdDrive                 = NULL;
                IHardDisk *hardDiskPM               = NULL;
                IHardDisk *hardDiskPS               = NULL;
                IHardDisk *hardDiskSS               = NULL;
                PRUnichar *hddBusUtf16              = NULL;
                IVRDPServer *VRDPServer             = NULL;
                IFloppyDrive *floppyDrive           = NULL;
                IAudioAdapter *audioAdapter         = NULL;
                IUSBController *USBController       = NULL;
                ISystemProperties *systemProperties = NULL;
                char *hddBus = strdup("IDE");


                def->virtType = VIR_DOMAIN_VIRT_VBOX;
                def->id = dom->id;
                memcpy(def->uuid, dom->uuid, VIR_UUID_BUFLEN);
                def->name = strdup(dom->name);

                machine->vtbl->GetMemorySize(machine, &memorySize);
                def->memory = memorySize * 1024;

                data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
                if (systemProperties) {
                    systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize);
                    systemProperties->vtbl->GetMaxBootPosition(systemProperties, &maxBootPosition);
                    systemProperties->vtbl->GetNetworkAdapterCount(systemProperties, &netAdpCnt);
                    systemProperties->vtbl->GetSerialPortCount(systemProperties, &serialPortCount);
                    systemProperties->vtbl->GetParallelPortCount(systemProperties, &parallelPortCount);
                    systemProperties->vtbl->nsisupports.Release((nsISupports *)systemProperties);
                    systemProperties = NULL;
                }
                /* Currently setting memory and maxMemory as same, cause
                 * the notation here seems to be inconsistent while
                 * reading and while dumping xml
                 */
                /* def->maxmem = maxMemorySize * 1024; */
                def->maxmem = memorySize * 1024;

                machine->vtbl->GetCPUCount(machine, &CPUCount);
                def->vcpus = CPUCount;

                /* Skip cpumasklen, cpumask, onReboot, onPoweroff, onCrash */

                def->os.type = strdup("hvm");

                uname(&utsname);
                def->os.arch = strdup(utsname.machine);

                def->os.nBootDevs = 0;
                for (i = 0; (i < VIR_DOMAIN_BOOT_LAST) && (i < maxBootPosition); i++) {
                    PRUint32 device = DeviceType_Null;

                    machine->vtbl->GetBootOrder(machine, i+1, &device);

                    if (device == DeviceType_Floppy) {
                        def->os.bootDevs[i] = VIR_DOMAIN_BOOT_FLOPPY;
                        def->os.nBootDevs++;
                    } else if (device == DeviceType_DVD) {
                        def->os.bootDevs[i] = VIR_DOMAIN_BOOT_CDROM;
                        def->os.nBootDevs++;
                    } else if (device == DeviceType_HardDisk) {
                        def->os.bootDevs[i] = VIR_DOMAIN_BOOT_DISK;
                        def->os.nBootDevs++;
                    } else if (device == DeviceType_Network) {
                        def->os.bootDevs[i] = VIR_DOMAIN_BOOT_NET;
                        def->os.nBootDevs++;
                    } else if (device == DeviceType_USB) {
                        /* Not supported by libvirt yet */
                    } else if (device == DeviceType_SharedFolder) {
                        /* Not supported by libvirt yet */
                    }
                }

                def->features = 0;
                machine->vtbl->GetPAEEnabled(machine, &PAEEnabled);
                if (PAEEnabled) {
                    def->features = def->features | (1 << VIR_DOMAIN_FEATURE_PAE);
                }

                machine->vtbl->GetBIOSSettings(machine, &bios);
                if (bios) {
                    bios->vtbl->GetACPIEnabled(bios, &ACPIEnabled);
                    if (ACPIEnabled) {
                        def->features = def->features | (1 << VIR_DOMAIN_FEATURE_ACPI);
                    }

                    bios->vtbl->GetIOAPICEnabled(bios, &IOAPICEnabled);
                    if (IOAPICEnabled) {
                        def->features = def->features | (1 << VIR_DOMAIN_FEATURE_APIC);
                    }

                    bios->vtbl->nsisupports.Release((nsISupports *)bios);
                }

                /* Currently VirtualBox always uses locatime
                 * so locatime is always true here */
                def->localtime = 1;

                /* dump display options vrdp/gui/sdl */
                {
                    int vrdpPresent           = 0;
                    int sdlPresent            = 0;
                    int guiPresent            = 0;
                    int totalPresent          = 0;
                    char *guiDisplay          = NULL;
                    char *sdlDisplay          = NULL;
                    PRUnichar *keyTypeUtf16   = NULL;
                    PRUnichar *valueTypeUtf16 = NULL;
                    char      *valueTypeUtf8  = NULL;

                    def->ngraphics = 0;

                    data->pFuncs->pfnUtf8ToUtf16("FRONTEND/Type", &keyTypeUtf16);
                    machine->vtbl->GetExtraData(machine, keyTypeUtf16, &valueTypeUtf16);
                    data->pFuncs->pfnUtf16Free(keyTypeUtf16);

                    if (valueTypeUtf16) {
                        data->pFuncs->pfnUtf16ToUtf8(valueTypeUtf16, &valueTypeUtf8);
                        data->pFuncs->pfnUtf16Free(valueTypeUtf16);

                        if ( STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui") ) {
                            PRUnichar *keyDislpayUtf16   = NULL;
                            PRUnichar *valueDisplayUtf16 = NULL;
                            char      *valueDisplayUtf8  = NULL;

                            data->pFuncs->pfnUtf8ToUtf16("FRONTEND/Display", &keyDislpayUtf16);
                            machine->vtbl->GetExtraData(machine, keyDislpayUtf16, &valueDisplayUtf16);
                            data->pFuncs->pfnUtf16Free(keyDislpayUtf16);

                            if (valueDisplayUtf16) {
                                data->pFuncs->pfnUtf16ToUtf8(valueDisplayUtf16, &valueDisplayUtf8);
                                data->pFuncs->pfnUtf16Free(valueDisplayUtf16);

                                if (strlen(valueDisplayUtf8) <= 0) {
                                    data->pFuncs->pfnUtf8Free(valueDisplayUtf8);
                                    valueDisplayUtf8 = NULL;
                                }
                            }

                            if (STREQ(valueTypeUtf8, "sdl")) {
                                sdlPresent = 1;
                                if (valueDisplayUtf8)
                                    sdlDisplay = strdup(valueDisplayUtf8);
                                if (sdlDisplay == NULL) {
                                    vboxError(dom->conn, VIR_ERR_SYSTEM_ERROR, "%s", "strdup failed");
                                    /* just don't go to cleanup yet as it is ok to have
                                     * sdlDisplay as NULL and we check it below if it
                                     * exist and then only use it there
                                     */
                                }
                                totalPresent++;
                            }

                            if (STREQ(valueTypeUtf8, "gui")) {
                                guiPresent = 1;
                                if (valueDisplayUtf8)
                                    guiDisplay = strdup(valueDisplayUtf8);
                                if (guiDisplay == NULL) {
                                    vboxError(dom->conn, VIR_ERR_SYSTEM_ERROR, "%s", "strdup failed");
                                    /* just don't go to cleanup yet as it is ok to have
                                     * guiDisplay as NULL and we check it below if it
                                     * exist and then only use it there
                                     */
                                }
                                totalPresent++;
                            }
                            if (valueDisplayUtf8)
                                data->pFuncs->pfnUtf8Free(valueDisplayUtf8);
                        }

                        if (STREQ(valueTypeUtf8, "vrdp"))
                            vrdpPresent = 1;

                        data->pFuncs->pfnUtf8Free(valueTypeUtf8);
                    }

                    if ((totalPresent > 0) && (VIR_ALLOC_N(def->graphics, totalPresent) >= 0)) {
                        if ((guiPresent) && (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) {
                            def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP;
                            if (guiDisplay)
                                def->graphics[def->ngraphics]->data.desktop.display = guiDisplay;
                            def->ngraphics++;
                        }

                        if ((sdlPresent) && (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) {
                            def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
                            if (sdlDisplay)
                                def->graphics[def->ngraphics]->data.sdl.display = sdlDisplay;
                            def->ngraphics++;
                        }
                    } else if ((vrdpPresent != 1) && (totalPresent == 0) && (VIR_ALLOC_N(def->graphics, 1) >= 0)) {
                        if (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0) {
                            def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP;
                            def->graphics[def->ngraphics]->data.desktop.display = strdup(getenv("DISPLAY"));
                            if (def->graphics[def->ngraphics]->data.desktop.display == NULL) {
                                vboxError(dom->conn, VIR_ERR_SYSTEM_ERROR, "%s", "strdup failed");
                                /* just don't go to cleanup yet as it is ok to have
                                 * display as NULL
                                 */
                            }
                            totalPresent++;
                            def->ngraphics++;
                        }
                    }

                    machine->vtbl->GetVRDPServer(machine, &VRDPServer);
                    if (VRDPServer) {
                        VRDPServer->vtbl->GetEnabled(VRDPServer, &VRDPEnabled);
                        if (VRDPEnabled) {

                            totalPresent++;

                            if ((VIR_REALLOC_N(def->graphics, totalPresent) >= 0) &&
                                (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) {
                                PRUint32 VRDPport            = 0;
                                PRUnichar *netAddressUtf16   = NULL;
                                char      *netAddressUtf8    = NULL;
                                PRBool allowMultiConnection  = PR_FALSE;
                                PRBool reuseSingleConnection = PR_FALSE;

                                def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_RDP;

                                VRDPServer->vtbl->GetPort(VRDPServer, &VRDPport);
                                if (VRDPport) {
                                    def->graphics[def->ngraphics]->data.rdp.port = VRDPport;
                                } else {
                                    def->graphics[def->ngraphics]->data.rdp.autoport = 1;
                                }

                                VRDPServer->vtbl->GetNetAddress(VRDPServer, &netAddressUtf16);
                                if (netAddressUtf16) {
                                    data->pFuncs->pfnUtf16ToUtf8(netAddressUtf16, &netAddressUtf8);
                                    if (STRNEQ(netAddressUtf8, ""))
                                            def->graphics[def->ngraphics]->data.rdp.listenAddr = strdup(netAddressUtf8);
                                    data->pFuncs->pfnUtf16Free(netAddressUtf16);
                                    data->pFuncs->pfnUtf8Free(netAddressUtf8);
                                }

                                VRDPServer->vtbl->GetAllowMultiConnection(VRDPServer, &allowMultiConnection);
                                if (allowMultiConnection) {
                                    def->graphics[def->ngraphics]->data.rdp.multiUser = 1;
                                }

                                VRDPServer->vtbl->GetReuseSingleConnection(VRDPServer, &reuseSingleConnection);
                                if (reuseSingleConnection) {
                                    def->graphics[def->ngraphics]->data.rdp.replaceUser = 1;
                                }

                                def->ngraphics++;
                            }
                        }
                        VRDPServer->vtbl->nsisupports.Release((nsISupports *)VRDPServer);
                    }
                }

                /* dump IDE hdds if present */
                data->pFuncs->pfnUtf8ToUtf16(hddBus, &hddBusUtf16);
                VIR_FREE(hddBus);

                def->ndisks = 0;
                machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 0,  &hardDiskPM);
                if (hardDiskPM)
                    def->ndisks++;

                machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 1,  &hardDiskPS);
                if (hardDiskPS)
                    def->ndisks++;

                machine->vtbl->GetHardDisk(machine, hddBusUtf16, 1, 1,  &hardDiskSS);
                if (hardDiskSS)
                    def->ndisks++;

                data->pFuncs->pfnUtf16Free(hddBusUtf16);

                if ((def->ndisks > 0) && (VIR_ALLOC_N(def->disks, def->ndisks) >= 0)) {
                    for (i = 0; i < def->ndisks; i++) {
                        if (VIR_ALLOC(def->disks[i]) >= 0) {
                            def->disks[i]->device = VIR_DOMAIN_DISK_DEVICE_DISK;
                            def->disks[i]->bus = VIR_DOMAIN_DISK_BUS_IDE;
                            def->disks[i]->type = VIR_DOMAIN_DISK_TYPE_FILE;
                        }
                    }
                }

                if (hardDiskPM) {
                    PRUnichar *hddlocationUtf16 = NULL;
                    char *hddlocation           = NULL;
                    PRUint32 hddType            = HardDiskType_Normal;

                    hardDiskPM->vtbl->imedium.GetLocation((IMedium *)hardDiskPM, &hddlocationUtf16);
                    data->pFuncs->pfnUtf16ToUtf8(hddlocationUtf16, &hddlocation);

                    hardDiskPM->vtbl->GetType(hardDiskPM, &hddType);

                    if (hddType == HardDiskType_Immutable)
                        def->disks[hddNum]->readonly = 1;
                    def->disks[hddNum]->src = strdup(hddlocation);
                    def->disks[hddNum]->dst = strdup("hda");
                    hddNum++;

                    data->pFuncs->pfnUtf8Free(hddlocation);
                    data->pFuncs->pfnUtf16Free(hddlocationUtf16);
                    hardDiskPM->vtbl->imedium.nsisupports.Release((nsISupports *)hardDiskPM);
                }

                if (hardDiskPS) {
                    PRUnichar *hddlocationUtf16 = NULL;
                    char *hddlocation           = NULL;
                    PRUint32 hddType            = HardDiskType_Normal;

                    hardDiskPS->vtbl->imedium.GetLocation((IMedium *)hardDiskPS, &hddlocationUtf16);
                    data->pFuncs->pfnUtf16ToUtf8(hddlocationUtf16, &hddlocation);

                    hardDiskPS->vtbl->GetType(hardDiskPS, &hddType);

                    if (hddType == HardDiskType_Immutable)
                        def->disks[hddNum]->readonly = 1;
                    def->disks[hddNum]->src = strdup(hddlocation);
                    def->disks[hddNum]->dst = strdup("hdb");
                    hddNum++;

                    data->pFuncs->pfnUtf8Free(hddlocation);
                    data->pFuncs->pfnUtf16Free(hddlocationUtf16);
                    hardDiskPS->vtbl->imedium.nsisupports.Release((nsISupports *)hardDiskPS);
                }

                if (hardDiskSS) {
                    PRUnichar *hddlocationUtf16 = NULL;
                    char *hddlocation           = NULL;
                    PRUint32 hddType            = HardDiskType_Normal;

                    hardDiskSS->vtbl->imedium.GetLocation((IMedium *)hardDiskSS, &hddlocationUtf16);
                    data->pFuncs->pfnUtf16ToUtf8(hddlocationUtf16, &hddlocation);

                    hardDiskSS->vtbl->GetType(hardDiskSS, &hddType);

                    if (hddType == HardDiskType_Immutable)
                        def->disks[hddNum]->readonly = 1;
                    def->disks[hddNum]->src = strdup(hddlocation);
                    def->disks[hddNum]->dst = strdup("hdd");
                    hddNum++;

                    data->pFuncs->pfnUtf8Free(hddlocation);
                    data->pFuncs->pfnUtf16Free(hddlocationUtf16);
                    hardDiskSS->vtbl->imedium.nsisupports.Release((nsISupports *)hardDiskSS);
                }

                /* dump network cards if present */
                def->nnets = 0;
                /* Get which network cards are enabled */
                for (i = 0; i < netAdpCnt; i++) {
                    INetworkAdapter *adapter = NULL;

                    machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                    if (adapter) {
                        PRBool enabled = PR_FALSE;

                        adapter->vtbl->GetEnabled(adapter, &enabled);
                        if (enabled) {
                            def->nnets++;
                        }

                        adapter->vtbl->nsisupports.Release((nsISupports *)adapter);
                    }
                }

                /* Allocate memory for the networkcards which are enabled */
                if ((def->nnets > 0) && (VIR_ALLOC_N(def->nets, def->nnets) >= 0)) {
                    for (i = 0; i < def->nnets; i++) {
                        if (VIR_ALLOC(def->nets[i]) >= 0) {
                        }
                    }
                }

                /* Now get the details about the network cards here */
                for (i = 0;(netAdpIncCnt < def->nnets) && (i < netAdpCnt); i++) {
                    INetworkAdapter *adapter = NULL;

                    machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                    if (adapter) {
                        PRBool enabled = PR_FALSE;

                        adapter->vtbl->GetEnabled(adapter, &enabled);
                        if (enabled) {
                            PRUint32 attachmentType    = NetworkAttachmentType_Null;
                            PRUint32 adapterType       = NetworkAdapterType_Null;
                            PRUnichar *MACAddressUtf16 = NULL;
                            char *MACAddress           = NULL;
                            char macaddr[VIR_MAC_STRING_BUFLEN] = {0};

                            adapter->vtbl->GetAttachmentType(adapter, &attachmentType);
                            if (attachmentType == NetworkAttachmentType_NAT) {

                                def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER;

                            } else if (attachmentType == NetworkAttachmentType_Bridged) {
                                PRUnichar *hostIntUtf16 = NULL;
                                char *hostInt           = NULL;

                                def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_BRIDGE;

                                adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);

                                data->pFuncs->pfnUtf16ToUtf8(hostIntUtf16, &hostInt);
                                def->nets[netAdpIncCnt]->data.bridge.brname = strdup(hostInt);

                                data->pFuncs->pfnUtf8Free(hostInt);
                                data->pFuncs->pfnUtf16Free(hostIntUtf16);

                            } else if (attachmentType == NetworkAttachmentType_Internal) {
                                PRUnichar *intNetUtf16 = NULL;
                                char *intNet           = NULL;

                                def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_INTERNAL;

                                adapter->vtbl->GetInternalNetwork(adapter, &intNetUtf16);

                                data->pFuncs->pfnUtf16ToUtf8(intNetUtf16, &intNet);
                                def->nets[netAdpIncCnt]->data.internal.name = strdup(intNet);

                                data->pFuncs->pfnUtf8Free(intNet);
                                data->pFuncs->pfnUtf16Free(intNetUtf16);

                            } else if (attachmentType == NetworkAttachmentType_HostOnly) {
                                PRUnichar *hostIntUtf16 = NULL;
                                char *hostInt           = NULL;

                                def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_NETWORK;

                                adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);

                                data->pFuncs->pfnUtf16ToUtf8(hostIntUtf16, &hostInt);
                                def->nets[netAdpIncCnt]->data.network.name = strdup(hostInt);

                                data->pFuncs->pfnUtf8Free(hostInt);
                                data->pFuncs->pfnUtf16Free(hostIntUtf16);

                            } else {
                                /* default to user type i.e. NAT in VirtualBox if this
                                 * dump is ever used to create a machine.
                                 */
                                def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER;
                            }

                            adapter->vtbl->GetAdapterType(adapter, &adapterType);
                            if (adapterType == NetworkAdapterType_Am79C970A) {
                                def->nets[netAdpIncCnt]->model = strdup("Am79C970A");
                            } else if (adapterType == NetworkAdapterType_Am79C973) {
                                def->nets[netAdpIncCnt]->model = strdup("Am79C973");
                            } else if (adapterType == NetworkAdapterType_I82540EM) {
                                def->nets[netAdpIncCnt]->model = strdup("82540EM");
                            } else if (adapterType == NetworkAdapterType_I82545EM) {
                                def->nets[netAdpIncCnt]->model = strdup("82545EM");
                            } else if (adapterType == NetworkAdapterType_I82543GC) {
                                def->nets[netAdpIncCnt]->model = strdup("82543GC");
                            }

                            adapter->vtbl->GetMACAddress(adapter, &MACAddressUtf16);
                            data->pFuncs->pfnUtf16ToUtf8(MACAddressUtf16, &MACAddress);
                            snprintf(macaddr, VIR_MAC_STRING_BUFLEN,
                                     "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c",
                                     MACAddress[0], MACAddress[1], MACAddress[2], MACAddress[3],
                                     MACAddress[4], MACAddress[5], MACAddress[6], MACAddress[7],
                                     MACAddress[8], MACAddress[9], MACAddress[10], MACAddress[11]);

                            virParseMacAddr(macaddr, def->nets[netAdpIncCnt]->mac);

                            netAdpIncCnt++;

                            data->pFuncs->pfnUtf16Free(MACAddressUtf16);
                            data->pFuncs->pfnUtf8Free(MACAddress);
                        }

                        adapter->vtbl->nsisupports.Release((nsISupports *)adapter);
                    }
                }

                /* dump sound card if active */

                /* Set def->nsounds to one as VirtualBox currently supports
                 * only one sound card
                 */

                machine->vtbl->GetAudioAdapter(machine, &audioAdapter);
                if (audioAdapter) {
                    PRBool enabled = PR_FALSE;

                    audioAdapter->vtbl->GetEnabled(audioAdapter, &enabled);
                    if (enabled) {
                        PRUint32 audioController = AudioControllerType_AC97;

                        def->nsounds = 1;
                        if (VIR_ALLOC_N(def->sounds, def->nsounds) >= 0) {
                            if (VIR_ALLOC(def->sounds[0]) >= 0) {
                                audioAdapter->vtbl->GetAudioController(audioAdapter, &audioController);
                                if (audioController == AudioControllerType_SB16) {
                                    def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_SB16;
                                } else if (audioController == AudioControllerType_AC97) {
                                    def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_AC97;
                                }
                            } else {
                                VIR_FREE(def->sounds);
                                def->nsounds = 0;
                            }
                        } else {
                            def->nsounds = 0;
                        }
                    }
                    audioAdapter->vtbl->nsisupports.Release((nsISupports *)audioAdapter);
                }

                /* dump CDROM/DVD if the drive is attached and has DVD/CD in it */
                machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                if (dvdDrive) {
                    PRUint32 state = DriveState_Null;

                    dvdDrive->vtbl->GetState(dvdDrive, &state);
                    if (state == DriveState_ImageMounted) {
                        IDVDImage *dvdImage = NULL;

                        dvdDrive->vtbl->GetImage(dvdDrive, &dvdImage);
                        if (dvdImage) {
                            PRUnichar *locationUtf16 = NULL;
                            char *location           = NULL;

                            dvdImage->vtbl->imedium.GetLocation((IMedium *)dvdImage, &locationUtf16);
                            data->pFuncs->pfnUtf16ToUtf8(locationUtf16, &location);

                            def->ndisks++;
                            if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
                                if (VIR_ALLOC(def->disks[def->ndisks - 1]) >= 0) {
                                    def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
                                    def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_IDE;
                                    def->disks[def->ndisks - 1]->type = VIR_DOMAIN_DISK_TYPE_FILE;
                                    def->disks[def->ndisks - 1]->readonly = 1;
                                    def->disks[def->ndisks - 1]->src = strdup(location);
                                    def->disks[def->ndisks - 1]->dst = strdup("hdc");
                                } else {
                                    def->ndisks--;
                                }
                            } else {
                                def->ndisks--;
                            }

                            data->pFuncs->pfnUtf8Free(location);
                            data->pFuncs->pfnUtf16Free(locationUtf16);
                            dvdImage->vtbl->imedium.nsisupports.Release((nsISupports *)dvdImage);
                        }
                    }
                    dvdDrive->vtbl->nsisupports.Release((nsISupports *)dvdDrive);
                }

                /* dump Floppy if the drive is attached and has floppy in it */
                machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
                if (floppyDrive) {
                    PRBool enabled = PR_FALSE;

                    floppyDrive->vtbl->GetEnabled(floppyDrive, &enabled);
                    if (enabled) {
                        PRUint32 state = DriveState_Null;

                        floppyDrive->vtbl->GetState(floppyDrive, &state);
                        if (state == DriveState_ImageMounted) {
                            IFloppyImage *floppyImage = NULL;

                            floppyDrive->vtbl->GetImage(floppyDrive, &floppyImage);
                            if (floppyImage) {
                                PRUnichar *locationUtf16 = NULL;
                                char *location           = NULL;

                                floppyImage->vtbl->imedium.GetLocation((IMedium *)floppyImage, &locationUtf16);
                                data->pFuncs->pfnUtf16ToUtf8(locationUtf16, &location);

                                def->ndisks++;
                                if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
                                    if (VIR_ALLOC(def->disks[def->ndisks - 1]) >= 0) {
                                        def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
                                        def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_FDC;
                                        def->disks[def->ndisks - 1]->type = VIR_DOMAIN_DISK_TYPE_FILE;
                                        def->disks[def->ndisks - 1]->readonly = 0;
                                        def->disks[def->ndisks - 1]->src = strdup(location);
                                        def->disks[def->ndisks - 1]->dst = strdup("fda");
                                    } else {
                                        def->ndisks--;
                                    }
                                } else {
                                    def->ndisks--;
                                }

                                data->pFuncs->pfnUtf8Free(location);
                                data->pFuncs->pfnUtf16Free(locationUtf16);
                                floppyImage->vtbl->imedium.nsisupports.Release((nsISupports *)floppyImage);
                            }
                        }
                    }

                    floppyDrive->vtbl->nsisupports.Release((nsISupports *)floppyDrive);
                }

                /* dump serial port if active */
                def->nserials = 0;
                /* Get which serial ports are enabled/active */
                for (i = 0; i < serialPortCount; i++) {
                    ISerialPort *serialPort = NULL;

                    machine->vtbl->GetSerialPort(machine, i, &serialPort);
                    if (serialPort) {
                        PRBool enabled = PR_FALSE;

                        serialPort->vtbl->GetEnabled(serialPort, &enabled);
                        if (enabled) {
                            def->nserials++;
                        }

                        serialPort->vtbl->nsisupports.Release((nsISupports *)serialPort);
                    }
                }

                /* Allocate memory for the serial ports which are enabled */
                if ((def->nserials > 0) && (VIR_ALLOC_N(def->serials, def->nserials) >= 0)) {
                    for (i = 0; i < def->nserials; i++) {
                        if (VIR_ALLOC(def->serials[i]) >= 0) {
                        }
                    }
                }

                /* Now get the details about the serial ports here */
                for (i = 0;(serialPortIncCount < def->nserials) && (i < serialPortCount); i++) {
                    ISerialPort *serialPort = NULL;

                    machine->vtbl->GetSerialPort(machine, i, &serialPort);
                    if (serialPort) {
                        PRBool enabled = PR_FALSE;

                        serialPort->vtbl->GetEnabled(serialPort, &enabled);
                        if (enabled) {
                            PRUint32 hostMode    = PortMode_Disconnected;
                            PRUint32 IOBase      = 0;
                            PRUint32 IRQ         = 0;
                            PRUnichar *pathUtf16 = NULL;
                            char *path           = NULL;

                            serialPort->vtbl->GetHostMode(serialPort, &hostMode);
                            if (hostMode == PortMode_HostPipe) {
                                def->serials[serialPortIncCount]->type = VIR_DOMAIN_CHR_TYPE_PIPE;
                            } else if (hostMode == PortMode_HostDevice) {
                                def->serials[serialPortIncCount]->type = VIR_DOMAIN_CHR_TYPE_DEV;
                            } else {
                                def->serials[serialPortIncCount]->type = VIR_DOMAIN_CHR_TYPE_NULL;
                            }

                            serialPort->vtbl->GetIRQ(serialPort, &IRQ);
                            serialPort->vtbl->GetIOBase(serialPort, &IOBase);
                            if ((IRQ == 4) && (IOBase == 1016)) {
                                def->serials[serialPortIncCount]->dstPort = 0;
                            } else if ((IRQ == 3) && (IOBase == 760)) {
                                def->serials[serialPortIncCount]->dstPort = 1;
                            }

                            serialPort->vtbl->GetPath(serialPort, &pathUtf16);

                            data->pFuncs->pfnUtf16ToUtf8(pathUtf16, &path);
                            def->serials[serialPortIncCount]->data.file.path = strdup(path);

                            serialPortIncCount++;

                            data->pFuncs->pfnUtf16Free(pathUtf16);
                            data->pFuncs->pfnUtf8Free(path);
                        }

                        serialPort->vtbl->nsisupports.Release((nsISupports *)serialPort);
                    }
                }

                /* dump parallel ports if active */
                def->nparallels = 0;
                /* Get which parallel ports are enabled/active */
                for (i = 0; i < parallelPortCount; i++) {
                    IParallelPort *parallelPort = NULL;

                    machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                    if (parallelPort) {
                        PRBool enabled = PR_FALSE;

                        parallelPort->vtbl->GetEnabled(parallelPort, &enabled);
                        if (enabled) {
                            def->nparallels++;
                        }

                        parallelPort->vtbl->nsisupports.Release((nsISupports *)parallelPort);
                    }
                }

                /* Allocate memory for the parallel ports which are enabled */
                if ((def->nparallels > 0) && (VIR_ALLOC_N(def->parallels, def->nparallels) >= 0)) {
                    for (i = 0; i < def->nparallels; i++) {
                        if (VIR_ALLOC(def->parallels[i]) >= 0) {
                        }
                    }
                }

                /* Now get the details about the parallel ports here */
                for (i = 0;(parallelPortIncCount < def->nparallels) && (i < parallelPortCount); i++) {
                    IParallelPort *parallelPort = NULL;

                    machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                    if (parallelPort) {
                        PRBool enabled = PR_FALSE;

                        parallelPort->vtbl->GetEnabled(parallelPort, &enabled);
                        if (enabled) {
                            PRUint32 IOBase      = 0;
                            PRUint32 IRQ         = 0;
                            PRUnichar *pathUtf16 = NULL;
                            char *path           = NULL;

                            parallelPort->vtbl->GetIRQ(parallelPort, &IRQ);
                            parallelPort->vtbl->GetIOBase(parallelPort, &IOBase);
                            if ((IRQ == 7) && (IOBase == 888)) {
                                def->parallels[parallelPortIncCount]->dstPort = 0;
                            } else if ((IRQ == 5) && (IOBase == 632)) {
                                def->parallels[parallelPortIncCount]->dstPort = 1;
                            }

                            def->parallels[parallelPortIncCount]->type = VIR_DOMAIN_CHR_TYPE_FILE;

                            parallelPort->vtbl->GetPath(parallelPort, &pathUtf16);

                            data->pFuncs->pfnUtf16ToUtf8(pathUtf16, &path);
                            def->parallels[parallelPortIncCount]->data.file.path = strdup(path);

                            parallelPortIncCount++;

                            data->pFuncs->pfnUtf16Free(pathUtf16);
                            data->pFuncs->pfnUtf8Free(path);
                        }

                        parallelPort->vtbl->nsisupports.Release((nsISupports *)parallelPort);
                    }
                }

                /* dump USB devices/filters if active */
                def->nhostdevs = 0;
                machine->vtbl->GetUSBController(machine, &USBController);
                if (USBController) {
                    PRBool enabled = PR_FALSE;

                    USBController->vtbl->GetEnabled(USBController, &enabled);
                    if (enabled) {
                        PRUint32 deviceFiltersNum        = 0;
                        IUSBDeviceFilter **deviceFilters = NULL;

                        USBController->vtbl->GetDeviceFilters(USBController,
                                                              &deviceFiltersNum,
                                                              &deviceFilters);

                        if (deviceFiltersNum > 0) {

                            /* check if the filters are active and then only
                             * alloc mem and set def->nhostdevs
                             */

                            for(i = 0; i < deviceFiltersNum; i++) {
                                PRBool active = PR_FALSE;

                                deviceFilters[i]->vtbl->GetActive(deviceFilters[i], &active);
                                if (active) {
                                    def->nhostdevs++;
                                }
                            }

                            if (def->nhostdevs > 0) {
                                /* Alloc mem needed for the filters now */
                                if (VIR_ALLOC_N(def->hostdevs, def->nhostdevs) >= 0) {

                                    for(i = 0; (USBFilterCount < def->nhostdevs) || (i < deviceFiltersNum); i++) {
                                        PRBool active = PR_FALSE;

                                        deviceFilters[i]->vtbl->GetActive(deviceFilters[i], &active);
                                        if (active) {
                                            if (VIR_ALLOC(def->hostdevs[USBFilterCount]) >= 0) {
                                                PRUnichar *vendorIdUtf16  = NULL;
                                                char *vendorIdUtf8        = NULL;
                                                unsigned vendorId         = 0;
                                                PRUnichar *productIdUtf16 = NULL;
                                                char *productIdUtf8       = NULL;
                                                unsigned productId        = 0;
                                                char *endptr              = NULL;

                                                def->hostdevs[USBFilterCount]->mode =
                                                    VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
                                                def->hostdevs[USBFilterCount]->source.subsys.type =
                                                    VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB;

                                                deviceFilters[i]->vtbl->GetVendorId(deviceFilters[i], &vendorIdUtf16);
                                                deviceFilters[i]->vtbl->GetProductId(deviceFilters[i], &productIdUtf16);

                                                data->pFuncs->pfnUtf16ToUtf8(vendorIdUtf16, &vendorIdUtf8);
                                                data->pFuncs->pfnUtf16ToUtf8(productIdUtf16, &productIdUtf8);

                                                vendorId  = strtol(vendorIdUtf8, &endptr, 16);
                                                productId = strtol(productIdUtf8, &endptr, 16);

                                                def->hostdevs[USBFilterCount]->source.subsys.u.usb.vendor  = vendorId;
                                                def->hostdevs[USBFilterCount]->source.subsys.u.usb.product = productId;

                                                data->pFuncs->pfnUtf16Free(vendorIdUtf16);
                                                data->pFuncs->pfnUtf8Free(vendorIdUtf8);

                                                data->pFuncs->pfnUtf16Free(productIdUtf16);
                                                data->pFuncs->pfnUtf8Free(productIdUtf8);

                                                USBFilterCount++;
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        /* Cleanup */
                        for(i = 0; i < deviceFiltersNum; i++) {
                            if (deviceFilters[i])
                                deviceFilters[i]->vtbl->nsisupports.Release((nsISupports *)deviceFilters[i]);
                        }
                    }
                    USBController->vtbl->nsisupports.Release((nsISupports *)USBController);
                }

                /* all done so set gotAllABoutDef and pass def to virDomainDefFormat
                 * to generate XML for it
                 */
                gotAllABoutDef = 0;
            }
            machine->vtbl->nsisupports.Release((nsISupports *)machine);
            machine = NULL;
        }
    }

    if (gotAllABoutDef == 0)
        ret = virDomainDefFormat(dom->conn, def, flags);

cleanup:
    vboxIIDFree(iid);
    virDomainDefFree(def);
    return ret;
}

static int vboxListDefinedDomains(virConnectPtr conn, char ** const names, int maxnames) {
    nsresult rc;
    vboxGlobalData *data = conn->privateData;
    IMachine **machines  = NULL;
    PRUint32 machineCnt  = 0;
    char *machineName    = NULL;
    PRUnichar *machineNameUtf16 = NULL;
    PRUint32 state;
    int ret = -1;
    int i, j;

    if(data->vboxObj) {
        rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
        if (NS_FAILED(rc)) {
            vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
                      "Could not get list of Defined Domains",(unsigned)rc);
            goto cleanup;
        }

        if (machineCnt == 0) {
            ret = 0;
            goto cleanup;
        }

        for (i = 0,j = 0; (i < machineCnt) && (j < maxnames); i++) {
            IMachine *machine = machines[i];

            if (machine) {
                PRBool isAccessible = PR_FALSE;
                machine->vtbl->GetAccessible(machine, &isAccessible);
                if (isAccessible) {
                    machine->vtbl->GetState(machine, &state);
                    if ((state != MachineState_Starting)   &&
                        (state != MachineState_Running)    &&
                        (state != MachineState_Stuck)      &&
                        (state != MachineState_Stopping)   &&
                        (state != MachineState_Saving)     &&
                        (state != MachineState_Restoring)  &&
                        (state != MachineState_Discarding) &&
                        (state != MachineState_Paused) ) {
                        machine->vtbl->GetName(machine, &machineNameUtf16);
                        data->pFuncs->pfnUtf16ToUtf8(machineNameUtf16, &machineName);
                        if (!(names[j++] = strdup(machineName))) {
                            virReportOOMError(conn);
                            for ( ; j >= 0 ; j--)
                                VIR_FREE(names[j]);
                            ret = -1;
                            goto cleanup;
                        }
                        ret++;
                    }
                }
            }
        }
        ret++;
    }

cleanup:
    data->pFuncs->pfnUtf8Free(machineName);
    data->pFuncs->pfnUtf16Free(machineNameUtf16);
    for (i = 0; i < machineCnt; ++i)
        if (machines[i])
            machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
    return ret;
}

static int vboxNumOfDefinedDomains(virConnectPtr conn) {
    nsresult rc;
    vboxGlobalData *data = conn->privateData;
    IMachine **machines  = NULL;
    PRUint32 machineCnt  = 0;
    PRUint32 state       = MachineState_Null;
    int ret = -1;
    int i;

    if(data->vboxObj) {
        rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
        if (NS_FAILED(rc)) {
            vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
                      "Could not get number of Defined Domains",(unsigned)rc);
            goto cleanup;
        }

        if (machineCnt == 0) {
            ret = 0;
            goto cleanup;
        }

        /* Do the cleanup as required by GetMachines() */
        for (i = 0; i < machineCnt; ++i) {
            IMachine *machine = machines[i];

            if (machine) {
                PRBool isAccessible = PR_FALSE;
                machine->vtbl->GetAccessible(machine, &isAccessible);
                if (isAccessible) {
                    machine->vtbl->GetState(machine, &state);
                    if ((state != MachineState_Starting)   &&
                        (state != MachineState_Running)    &&
                        (state != MachineState_Stuck)      &&
                        (state != MachineState_Stopping)   &&
                        (state != MachineState_Saving)     &&
                        (state != MachineState_Restoring)  &&
                        (state != MachineState_Discarding) &&
                        (state != MachineState_Paused) ) {
                        ret++;
                    }
                }
            }
        }
        ret++;
    }

cleanup:
    for (i = 0; i < machineCnt; ++i)
        if (machines[i])
            machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
    return ret;
}

static int vboxDomainCreate(virDomainPtr dom) {
    nsresult rc;
    vboxGlobalData *data   = dom->conn->privateData;
    IMachine **machines    = NULL;
    IProgress *progress    = NULL;
    PRUint32 machineCnt    = 0;
    PRUnichar *env         = NULL;
    PRUnichar *sessionType = NULL;
    char displayutf8[32]   = {0};
    unsigned char iidl[VIR_UUID_BUFLEN] = {0};
    int i, ret = -1;


    if (!dom->name) {
        vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s",
                  "Error while reading the domain name");
        goto cleanup;
    }

    if(data->vboxObj) {
        rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines);
        if (NS_FAILED(rc)) {
            vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
                      "Could not get list of machines",(unsigned)rc);
            goto cleanup;
        }

        for (i = 0; i < machineCnt; ++i) {
            IMachine *machine = machines[i];
            PRBool isAccessible = PR_FALSE;

            if (!machine)
                continue;

            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                vboxIID *iid = NULL;

                machine->vtbl->GetId(machine, &iid);
                if (!iid)
                    continue;
                vboxIIDToUUID(iidl, iid);

                if (memcmp(dom->uuid, iidl, VIR_UUID_BUFLEN) == 0) {
                    PRUint32 state = MachineState_Null;
                    machine->vtbl->GetState(machine, &state);

                    if ( (state == MachineState_PoweredOff) ||
                         (state == MachineState_Saved) ||
                         (state == MachineState_Aborted) ) {
                        int vrdpPresent              = 0;
                        int sdlPresent               = 0;
                        int guiPresent               = 0;
                        char *guiDisplay             = NULL;
                        char *sdlDisplay             = NULL;
                        PRUnichar *keyTypeUtf16      = NULL;
                        PRUnichar *valueTypeUtf16    = NULL;
                        char      *valueTypeUtf8     = NULL;
                        PRUnichar *keyDislpayUtf16   = NULL;
                        PRUnichar *valueDisplayUtf16 = NULL;
                        char      *valueDisplayUtf8  = NULL;

                        data->pFuncs->pfnUtf8ToUtf16("FRONTEND/Type", &keyTypeUtf16);
                        machine->vtbl->GetExtraData(machine, keyTypeUtf16, &valueTypeUtf16);
                        data->pFuncs->pfnUtf16Free(keyTypeUtf16);

                        if (valueTypeUtf16) {
                            data->pFuncs->pfnUtf16ToUtf8(valueTypeUtf16, &valueTypeUtf8);
                            data->pFuncs->pfnUtf16Free(valueTypeUtf16);

                            if ( STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui") ) {

                                data->pFuncs->pfnUtf8ToUtf16("FRONTEND/Display", &keyDislpayUtf16);
                                machine->vtbl->GetExtraData(machine, keyDislpayUtf16, &valueDisplayUtf16);
                                data->pFuncs->pfnUtf16Free(keyDislpayUtf16);

                                if (valueDisplayUtf16) {
                                    data->pFuncs->pfnUtf16ToUtf8(valueDisplayUtf16, &valueDisplayUtf8);
                                    data->pFuncs->pfnUtf16Free(valueDisplayUtf16);

                                    if (strlen(valueDisplayUtf8) <= 0) {
                                        data->pFuncs->pfnUtf8Free(valueDisplayUtf8);
                                        valueDisplayUtf8 = NULL;
                                    }
                                }

                                if (STREQ(valueTypeUtf8, "sdl")) {
                                    sdlPresent = 1;
                                    if (valueDisplayUtf8) {
                                        sdlDisplay = strdup(valueDisplayUtf8);
                                        if (sdlDisplay == NULL) {
                                            vboxError(dom->conn, VIR_ERR_SYSTEM_ERROR, "%s", "strdup failed");
                                            /* just don't go to cleanup yet as it is ok to have
                                             * sdlDisplay as NULL and we check it below if it
                                             * exist and then only use it there
                                             */
                                        }
                                    }
                                }

                                if (STREQ(valueTypeUtf8, "gui")) {
                                    guiPresent = 1;
                                    if (valueDisplayUtf8) {
                                        guiDisplay = strdup(valueDisplayUtf8);
                                        if (guiDisplay == NULL) {
                                            vboxError(dom->conn, VIR_ERR_SYSTEM_ERROR, "%s", "strdup failed");
                                            /* just don't go to cleanup yet as it is ok to have
                                             * guiDisplay as NULL and we check it below if it
                                             * exist and then only use it there
                                             */
                                        }
                                    }
                                }
                            }

                            if (STREQ(valueTypeUtf8, "vrdp")) {
                                vrdpPresent = 1;
                            }

                            data->pFuncs->pfnUtf8Free(valueTypeUtf8);

                        } else {
                            guiPresent = 1;
                        }
                        if (valueDisplayUtf8)
                            data->pFuncs->pfnUtf8Free(valueDisplayUtf8);

                        if (guiPresent) {
                            if (guiDisplay) {
                                sprintf(displayutf8, "DISPLAY=%.24s", guiDisplay);
                                data->pFuncs->pfnUtf8ToUtf16(displayutf8, &env);
                                VIR_FREE(guiDisplay);
                            }

                            data->pFuncs->pfnUtf8ToUtf16("gui", &sessionType);
                        }

                        if (sdlPresent) {
                            if (sdlDisplay) {
                                sprintf(displayutf8, "DISPLAY=%.24s", sdlDisplay);
                                data->pFuncs->pfnUtf8ToUtf16(displayutf8, &env);
                                VIR_FREE(sdlDisplay);
                            }

                            data->pFuncs->pfnUtf8ToUtf16("sdl", &sessionType);
                        }

                        if (vrdpPresent) {
                            data->pFuncs->pfnUtf8ToUtf16("vrdp", &sessionType);
                        }

                        data->vboxObj->vtbl->OpenRemoteSession(data->vboxObj,
                                                               data->vboxSession,
                                                               iid,
                                                               sessionType,
                                                               env,
                                                               &progress );
                        if (NS_FAILED(rc)) {
                            vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
                                      "%s", "openremotesession failed, domain can't be started");
                            ret = -1;
                        } else {
                            PRBool completed = 0;
#if VBOX_API_VERSION == 2002
                            nsresult resultCode;
#else
                            PRInt32  resultCode;
#endif
                            progress->vtbl->WaitForCompletion(progress, -1);
                            rc = progress->vtbl->GetCompleted(progress, &completed);
                            if (NS_FAILED(rc)) {
                                /* error */
                                ret = -1;
                            }
                            progress->vtbl->GetResultCode(progress, &resultCode);
                            if (NS_FAILED(resultCode)) {
                                /* error */
                                ret = -1;
                            } else {
                                /* all ok set the domid */
                                dom->id = i + 1;
                                ret = 0;
                            }
                        }

                        if (progress)
                            progress->vtbl->nsisupports.Release((nsISupports *)progress);

                        data->vboxSession->vtbl->Close(data->vboxSession);

                    } else {
                        vboxError(dom->conn, VIR_ERR_OPERATION_FAILED,
                                  "%s", "machine is not in poweroff|saved|"
                                        "aborted state, so couldn't start it");
                        ret = -1;
                    }
                }
#if VBOX_API_VERSION == 2002
                vboxIIDUnalloc(iid);
#else
                vboxIIDFree(iid);
#endif
                if (ret != -1)
                    break;
            }
        }

        /* Do the cleanup and take care you dont leak any memory */
        for (i = 0; i < machineCnt; ++i) {
            if (machines[i])
                machines[i]->vtbl->nsisupports.Release((nsISupports *)machines[i]);
        }
    }

    data->pFuncs->pfnUtf16Free(env);
    data->pFuncs->pfnUtf16Free(sessionType);

cleanup:
    return ret;
}

static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml) {
    nsresult rc;
    vboxGlobalData *data        = conn->privateData;
    IMachine       *machine     = NULL;
    IBIOSSettings  *bios        = NULL;
    virDomainPtr    dom         = NULL;
    vboxIID        *iid         = NULL;
    vboxIID        *mchiid      = NULL;
    virDomainDefPtr def         = NULL;
    PRUnichar *machineNameUtf16 = NULL;

    if (!(def = virDomainDefParseString(conn, data->caps, xml,
                                        VIR_DOMAIN_XML_INACTIVE))) {
        goto cleanup;
    }

#if VBOX_API_VERSION == 2002
    if (VIR_ALLOC(iid) < 0) {
        virReportOOMError(conn);
        goto cleanup;
    }
#endif

    if (data->vboxObj) {
        data->pFuncs->pfnUtf8ToUtf16(def->name, &machineNameUtf16);
        vboxIIDFromUUID(def->uuid, iid);
        rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                                machineNameUtf16,
                                                NULL,
                                                NULL,
                                                iid,
                                                &machine);
        data->pFuncs->pfnUtf16Free(machineNameUtf16);

        if (NS_FAILED(rc)) {
            vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
                      "could not define a domain",(unsigned)rc);
            goto cleanup;
        }

        rc = machine->vtbl->SetMemorySize(machine, def->memory / 1024);
        if (NS_FAILED(rc)) {
            vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%lu Kb, rc=%08x",
                      "could not set the memory size of the domain to",
                      def->memory, (unsigned)rc);
        }

        rc = machine->vtbl->SetCPUCount(machine, def->vcpus);
        if (NS_FAILED(rc)) {
            vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%lu, rc=%08x",
                      "could not set the number of virtual CPUs to",
                      def->vcpus, (unsigned)rc);
        }

        rc = machine->vtbl->SetPAEEnabled(machine, (def->features) &
                                          (1 << VIR_DOMAIN_FEATURE_PAE));
        if (NS_FAILED(rc)) {
            vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
                      "could not change PAE status to",
                      ((def->features) & (1 << VIR_DOMAIN_FEATURE_PAE))
                      ? "Enabled" : "Disabled", (unsigned)rc);
        }

        machine->vtbl->GetBIOSSettings(machine, &bios);
        if (bios) {
            rc = bios->vtbl->SetACPIEnabled(bios, (def->features) &
                                            (1 << VIR_DOMAIN_FEATURE_ACPI));
            if (NS_FAILED(rc)) {
                vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
                          "could not change ACPI status to",
                          ((def->features) & (1 << VIR_DOMAIN_FEATURE_ACPI))
                          ? "Enabled" : "Disabled", (unsigned)rc);
            }
            rc = bios->vtbl->SetIOAPICEnabled(bios, (def->features) &
                                              (1 << VIR_DOMAIN_FEATURE_APIC));
            if (NS_FAILED(rc)) {
                vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
                          "could not change APIC status to",
                          ((def->features) & (1 << VIR_DOMAIN_FEATURE_APIC))
                          ? "Enabled" : "Disabled", (unsigned)rc);
            }
            bios->vtbl->nsisupports.Release((nsISupports *)bios);
        }

        /* Register the machine before attaching other devices to it */
        rc = data->vboxObj->vtbl->RegisterMachine(data->vboxObj, machine);
        if (NS_FAILED(rc)) {
            vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
                      "could not define a domain",(unsigned)rc);
            goto cleanup;
        }

        /* Get the uuid of the machine, currently it is immutable
         * object so open a session to it and get it back, so that
         * you can make changes to the machine setting
         */
        machine->vtbl->GetId(machine, &mchiid);
        data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, mchiid);
        data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);

        {   /* Started:Block to set the boot device order */
            ISystemProperties *systemProperties = NULL;
            PRUint32 maxBootPosition            = 0;
            int i = 0;

            DEBUG("def->os.type             %s", def->os.type);
            DEBUG("def->os.arch             %s", def->os.arch);
            DEBUG("def->os.machine          %s", def->os.machine);
            DEBUG("def->os.nBootDevs        %d", def->os.nBootDevs);
            DEBUG("def->os.bootDevs[0]      %d", def->os.bootDevs[0]);
            DEBUG("def->os.bootDevs[1]      %d", def->os.bootDevs[1]);
            DEBUG("def->os.bootDevs[2]      %d", def->os.bootDevs[2]);
            DEBUG("def->os.bootDevs[3]      %d", def->os.bootDevs[3]);
            DEBUG("def->os.init             %s", def->os.init);
            DEBUG("def->os.kernel           %s", def->os.kernel);
            DEBUG("def->os.initrd           %s", def->os.initrd);
            DEBUG("def->os.cmdline          %s", def->os.cmdline);
            DEBUG("def->os.root             %s", def->os.root);
            DEBUG("def->os.loader           %s", def->os.loader);
            DEBUG("def->os.bootloader       %s", def->os.bootloader);
            DEBUG("def->os.bootloaderArgs   %s", def->os.bootloaderArgs);

            data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
            if (systemProperties) {
                systemProperties->vtbl->GetMaxBootPosition(systemProperties, &maxBootPosition);
                systemProperties->vtbl->nsisupports.Release((nsISupports *)systemProperties);
                systemProperties = NULL;
            }

            /* Clear the defaults first */
            for (i = 0; i < maxBootPosition; i++) {
                machine->vtbl->SetBootOrder(machine, i+1, DeviceType_Null);
            }

            for (i = 0; (i < def->os.nBootDevs) && (i < maxBootPosition); i++) {
                PRUint32 device = DeviceType_Null;

                if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_FLOPPY) {
                    device = DeviceType_Floppy;
                } else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_CDROM) {
                    device = DeviceType_DVD;
                } else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_DISK) {
                    device = DeviceType_HardDisk;
                } else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_NET) {
                    device = DeviceType_Network;
                }
                machine->vtbl->SetBootOrder(machine, i+1, device);
            }
        }   /* Finished:Block to set the boot device order */

        {   /* Started:Block to attach the CDROM/DVD Drive and HardDisks to the VM */

            if (def->ndisks > 0) {
                int i;

                for (i = 0; i < def->ndisks; i++) {
                    DEBUG("disk(%d) type:       %d", i, def->disks[i]->type);
                    DEBUG("disk(%d) device:     %d", i, def->disks[i]->device);
                    DEBUG("disk(%d) bus:        %d", i, def->disks[i]->bus);
                    DEBUG("disk(%d) src:        %s", i, def->disks[i]->src);
                    DEBUG("disk(%d) dst:        %s", i, def->disks[i]->dst);
                    DEBUG("disk(%d) driverName: %s", i, def->disks[i]->driverName);
                    DEBUG("disk(%d) driverType: %s", i, def->disks[i]->driverType);
                    DEBUG("disk(%d) cachemode:  %d", i, def->disks[i]->cachemode);
                    DEBUG("disk(%d) readonly:   %s", i, def->disks[i]->readonly ? "True" : "False");
                    DEBUG("disk(%d) shared:     %s", i, def->disks[i]->shared ? "True" : "False");

                    if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                        if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE) {
                            IDVDDrive *dvdDrive = NULL;
                            /* Currently CDROM/DVD Drive is always IDE
                             * Secondary Master so neglecting the following
                             * parameters:
                             *      def->disks[i]->bus
                             *      def->disks[i]->dst
                             */

                            machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                            if (dvdDrive) {
                                IDVDImage *dvdImage          = NULL;
                                PRUnichar *dvdfileUtf16      = NULL;
                                vboxIID *dvduuid             = NULL;
#if VBOX_API_VERSION == 2002
                                nsID dvdemptyuuid;

                                memset(&dvdemptyuuid, 0, sizeof(dvdemptyuuid));
#else
                                PRUnichar *dvdemptyuuidUtf16 = NULL;
#endif

                                data->pFuncs->pfnUtf8ToUtf16(def->disks[i]->src, &dvdfileUtf16);

                                data->vboxObj->vtbl->FindDVDImage(data->vboxObj, dvdfileUtf16, &dvdImage);
                                if (!dvdImage) {
#if VBOX_API_VERSION == 2002
                                    data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, &dvdemptyuuid, &dvdImage);
#else
                                    data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, dvdemptyuuidUtf16, &dvdImage);
#endif
                                }
                                if (dvdImage) {
                                    rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage, &dvduuid);
                                    if (NS_FAILED(rc)) {
                                        vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
                                                  "can't get the uuid of the file to be attached to cdrom",
                                                  def->disks[i]->src, (unsigned)rc);
                                    } else {
                                        rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid);
                                        if (NS_FAILED(rc)) {
                                            vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
                                                      "could not attach the file to cdrom",
                                                      def->disks[i]->src, (unsigned)rc);
                                        } else {
#if VBOX_API_VERSION == 2002
                                            DEBUGUUID("CD/DVDImage UUID:", dvduuid);
#else
                                            DEBUGPRUnichar("CD/DVDImage UUID:", dvduuid);
#endif
                                        }
                                    }

                                    dvdImage->vtbl->imedium.nsisupports.Release((nsISupports *)dvdImage);
                                }
#if VBOX_API_VERSION == 2002
                                vboxIIDUnalloc(dvduuid);
#else
                                vboxIIDFree(dvduuid);
#endif
                                data->pFuncs->pfnUtf16Free(dvdfileUtf16);
                                dvdDrive->vtbl->nsisupports.Release((nsISupports *)dvdDrive);
                            }
                        } else if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
                        }
                    } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
                        if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE) {
                            IHardDisk *hardDisk     = NULL;
                            PRUnichar *hddfileUtf16 = NULL;
                            vboxIID *hdduuid        = NULL;
                            /* Current Limitation: Harddisk can't be connected to
                             * Secondary Master as Secondary Master is always used
                             * for CD/DVD Drive, so don't connect the harddisk if it
                             * is requested to be connected to Secondary master
                             */

                            data->pFuncs->pfnUtf8ToUtf16(def->disks[i]->src, &hddfileUtf16);

                            data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddfileUtf16, &hardDisk);

                            if (!hardDisk) {
#if VBOX_API_VERSION == 2002
                                data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                                  hddfileUtf16,
                                                                  AccessMode_ReadWrite,
                                                                  &hardDisk);
#else
                                data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                                  hddfileUtf16,
                                                                  AccessMode_ReadWrite,
                                                                  0,
                                                                  NULL,
                                                                  0,
                                                                  NULL,
                                                                  &hardDisk);
#endif
                            }

                            if (hardDisk) {
                                rc = hardDisk->vtbl->imedium.GetId((IMedium *)hardDisk, &hdduuid);
                                if (NS_FAILED(rc)) {
                                    vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
                                              "can't get the uuid of the file to be attached as harddisk",
                                              def->disks[i]->src, (unsigned)rc);
                                } else {
                                    if (def->disks[i]->readonly) {
                                        hardDisk->vtbl->SetType(hardDisk, HardDiskType_Immutable);
                                        DEBUG0("setting harddisk to readonly");
                                    } else if (!def->disks[i]->readonly) {
                                        hardDisk->vtbl->SetType(hardDisk, HardDiskType_Normal);
                                        DEBUG0("setting harddisk type to normal");
                                    }
                                    if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_IDE) {
                                        if (STREQ(def->disks[i]->dst, "hdc")) {
                                            DEBUG0("Not connecting harddisk to hdc as hdc"
                                                   " is taken by CD/DVD Drive");
                                        } else {
                                            PRInt32 channel          = 0;
                                            PRInt32 device           = 0;
                                            PRUnichar *hddcnameUtf16 = NULL;

                                            char *hddcname = strdup("IDE");
                                            data->pFuncs->pfnUtf8ToUtf16(hddcname, &hddcnameUtf16);
                                            VIR_FREE(hddcname);

                                            if (STREQ(def->disks[i]->dst, "hda")) {
                                                channel = 0;
                                                device  = 0;
                                            } else if (STREQ(def->disks[i]->dst, "hdb")) {
                                                channel = 0;
                                                device  = 1;
                                            } else if (STREQ(def->disks[i]->dst, "hdd")) {
                                                channel = 1;
                                                device  = 1;
                                            }

                                            rc = machine->vtbl->AttachHardDisk(machine,
                                                                               hdduuid,
                                                                               hddcnameUtf16,
                                                                               channel,
                                                                               device);
                                            data->pFuncs->pfnUtf16Free(hddcnameUtf16);

                                            if (NS_FAILED(rc)) {
                                                vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
                                                          "could not attach the file as harddisk",
                                                          def->disks[i]->src, (unsigned)rc);
                                            } else {
#if VBOX_API_VERSION == 2002
                                                DEBUGUUID("Attached HDD with UUID", hdduuid);
#else
                                                DEBUGPRUnichar("Attached HDD with UUID", hdduuid);
#endif
                                            }
                                        }
                                    }
                                }
                                hardDisk->vtbl->imedium.nsisupports.Release((nsISupports *)hardDisk);
                            }
#if VBOX_API_VERSION == 2002
                            vboxIIDUnalloc(hdduuid);
#else
                            vboxIIDFree(hdduuid);
#endif
                            data->pFuncs->pfnUtf16Free(hddfileUtf16);
                        } else if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
                        }
                    } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
                        if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE) {
                            IFloppyDrive *floppyDrive;
                            machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
                            if (floppyDrive) {
                                rc = floppyDrive->vtbl->SetEnabled(floppyDrive, 1);
                                if (NS_SUCCEEDED(rc)) {
                                    IFloppyImage *floppyImage   = NULL;
                                    PRUnichar *fdfileUtf16      = NULL;
                                    vboxIID *fduuid             = NULL;
#if VBOX_API_VERSION == 2002
                                    nsID fdemptyuuid;

                                    memset(&fdemptyuuid, 0, sizeof(fdemptyuuid));
#else
                                    PRUnichar *fdemptyuuidUtf16 = NULL;
#endif

                                    data->pFuncs->pfnUtf8ToUtf16(def->disks[i]->src, &fdfileUtf16);
                                    rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                              fdfileUtf16,
                                                                              &floppyImage);

                                    if (!floppyImage) {
                                        data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                             fdfileUtf16,
#if VBOX_API_VERSION == 2002
                                                                             &fdemptyuuid,
#else
                                                                             fdemptyuuidUtf16,
#endif
                                                                             &floppyImage);
                                    }

                                    if (floppyImage) {
                                        rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage, &fduuid);
                                        if (NS_FAILED(rc)) {
                                            vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
                                                      "can't get the uuid of the file to be attached to floppy drive",
                                                      def->disks[i]->src, (unsigned)rc);
                                        } else {
                                            rc = floppyDrive->vtbl->MountImage(floppyDrive, fduuid);
                                            if (NS_FAILED(rc)) {
                                                vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
                                                          "could not attach the file to floppy drive",
                                                          def->disks[i]->src, (unsigned)rc);
                                            } else {
#if VBOX_API_VERSION == 2002
                                                DEBUGUUID("floppyImage UUID", fduuid);
#else
                                                DEBUGPRUnichar("floppyImage UUID", fduuid);
#endif
                                            }
                                        }
                                        floppyImage->vtbl->imedium.nsisupports.Release((nsISupports *)floppyImage);
                                    }
#if VBOX_API_VERSION == 2002
                                    vboxIIDUnalloc(fduuid);
#else
                                    vboxIIDFree(fduuid);
#endif
                                    data->pFuncs->pfnUtf16Free(fdfileUtf16);
                                }
                                floppyDrive->vtbl->nsisupports.Release((nsISupports *)floppyDrive);
                            }
                        } else if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
                        }
                    }
                }
            }

        }   /* Finished:Block to attach the CDROM/DVD Drive and HardDisks to the VM */

        {   /* Started:Block to attach the Sound Controller to the VM */
            /* Check if def->nsounds is one as VirtualBox currently supports
             * only one sound card
             */
            if (def->nsounds == 1) {
                IAudioAdapter *audioAdapter = NULL;

                machine->vtbl->GetAudioAdapter(machine, &audioAdapter);
                if (audioAdapter) {
                    rc = audioAdapter->vtbl->SetEnabled(audioAdapter, 1);
                    if (NS_SUCCEEDED(rc)) {
                        if (def->sounds[0]->model == VIR_DOMAIN_SOUND_MODEL_SB16) {
                            audioAdapter->vtbl->SetAudioController(audioAdapter, AudioControllerType_SB16);
                        } else if (def->sounds[0]->model == VIR_DOMAIN_SOUND_MODEL_AC97) {
                            audioAdapter->vtbl->SetAudioController(audioAdapter, AudioControllerType_AC97);
                        }
                    }
                    audioAdapter->vtbl->nsisupports.Release((nsISupports *)audioAdapter);
                }
            }
        }   /* Finished:Block to attach the Sound Controller to the VM */

        {   /* Started:Block to attach the Network Card to the VM */
            ISystemProperties *systemProperties = NULL;
            PRUint32 networkAdapterCount        = 0;
            int i = 0;

            data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
            if (systemProperties) {
                systemProperties->vtbl->GetNetworkAdapterCount(systemProperties, &networkAdapterCount);
                systemProperties->vtbl->nsisupports.Release((nsISupports *)systemProperties);
                systemProperties = NULL;
            }

            DEBUG("Number of Network Cards to be connected: %d", def->nnets);
            DEBUG("Number of Network Cards available: %d", networkAdapterCount);

            for (i = 0; (i < def->nnets) && (i < networkAdapterCount); i++) {
                INetworkAdapter *adapter = NULL;
                PRUint32 adapterType     = NetworkAdapterType_Null;
                char macaddr[VIR_MAC_STRING_BUFLEN] = {0};
                char macaddrvbox[VIR_MAC_STRING_BUFLEN - 5] = {0};

                virFormatMacAddr(def->nets[i]->mac, macaddr);
                snprintf(macaddrvbox, VIR_MAC_STRING_BUFLEN - 5,
                         "%02X%02X%02X%02X%02X%02X",
                         def->nets[i]->mac[0],
                         def->nets[i]->mac[1],
                         def->nets[i]->mac[2],
                         def->nets[i]->mac[3],
                         def->nets[i]->mac[4],
                         def->nets[i]->mac[5]);
                macaddrvbox[VIR_MAC_STRING_BUFLEN - 6] = '\0';

                DEBUG("NIC(%d): Type:   %d", i, def->nets[i]->type);
                DEBUG("NIC(%d): Model:  %s", i, def->nets[i]->model);
                DEBUG("NIC(%d): Mac:    %s", i, macaddr);
                DEBUG("NIC(%d): ifname: %s", i, def->nets[i]->ifname);
                if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
                    DEBUG("NIC(%d): name:    %s", i, def->nets[i]->data.network.name);
                } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
                    DEBUG("NIC(%d): name:   %s", i, def->nets[i]->data.internal.name);
                } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
                    DEBUG("NIC(%d): NAT.", i);
                } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
                    DEBUG("NIC(%d): brname: %s", i, def->nets[i]->data.bridge.brname);
                    DEBUG("NIC(%d): script: %s", i, def->nets[i]->data.bridge.script);
                    DEBUG("NIC(%d): ipaddr: %s", i, def->nets[i]->data.bridge.ipaddr);
                }

                machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                if (adapter) {
                    PRUnichar *MACAddress = NULL;

                    adapter->vtbl->SetEnabled(adapter, 1);

                    if (STRCASEEQ(def->nets[i]->model , "Am79C970A")) {
                        adapterType = NetworkAdapterType_Am79C970A;
                    } else if (STRCASEEQ(def->nets[i]->model , "Am79C973")) {
                        adapterType = NetworkAdapterType_Am79C973;
                    } else if (STRCASEEQ(def->nets[i]->model , "82540EM")) {
                        adapterType = NetworkAdapterType_I82540EM;
                    } else if (STRCASEEQ(def->nets[i]->model , "82545EM")) {
                        adapterType = NetworkAdapterType_I82545EM;
                    } else if (STRCASEEQ(def->nets[i]->model , "82543GC")) {
                        adapterType = NetworkAdapterType_I82543GC;
                    }

                    adapter->vtbl->SetAdapterType(adapter, adapterType);

                    if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
                        PRUnichar *hostInterface = NULL;
                        /* Bridged Network */

                        adapter->vtbl->AttachToBridgedInterface(adapter);

                        if (def->nets[i]->data.bridge.brname) {
                            data->pFuncs->pfnUtf8ToUtf16(def->nets[i]->data.bridge.brname, &hostInterface);
                            adapter->vtbl->SetHostInterface(adapter, hostInterface);
                            data->pFuncs->pfnUtf16Free(hostInterface);
                        }
                    } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
                        PRUnichar *internalNetwork = NULL;
                        /* Internal Network */

                        adapter->vtbl->AttachToInternalNetwork(adapter);

                        if (def->nets[i]->data.internal.name) {
                            data->pFuncs->pfnUtf8ToUtf16(def->nets[i]->data.internal.name, &internalNetwork);
                            adapter->vtbl->SetInternalNetwork(adapter, internalNetwork);
                            data->pFuncs->pfnUtf16Free(internalNetwork);
                        }
                    } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
                        PRUnichar *hostInterface = NULL;
                        /* Host Only Networking (currently only vboxnet0 available
                         * on *nix and mac, on windows you can create and configure
                         * as many as you want)
                         */
                        adapter->vtbl->AttachToHostOnlyInterface(adapter);

                        if (def->nets[i]->data.network.name) {
                            data->pFuncs->pfnUtf8ToUtf16(def->nets[i]->data.network.name, &hostInterface);
                            adapter->vtbl->SetHostInterface(adapter, hostInterface);
                            data->pFuncs->pfnUtf16Free(hostInterface);
                        }
                    } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
                        /* NAT */
                        adapter->vtbl->AttachToNAT(adapter);
                    } else {
                        /* else always default to NAT if we don't understand
                         * what option is been passed to us
                         */
                        adapter->vtbl->AttachToNAT(adapter);
                    }

                    data->pFuncs->pfnUtf8ToUtf16(macaddrvbox, &MACAddress);
                    if (def->nets[i]->mac) {
                        adapter->vtbl->SetMACAddress(adapter, MACAddress);
                    }
                    data->pFuncs->pfnUtf16Free(MACAddress);
                }
            }
        }   /* Finished:Block to attach the Network Card to the VM */

        {   /* Started:Block to attach the Serial Port to the VM */
            ISystemProperties *systemProperties = NULL;
            PRUint32 serialPortCount            = 0;
            int i = 0;

            data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
            if (systemProperties) {
                systemProperties->vtbl->GetSerialPortCount(systemProperties, &serialPortCount);
                systemProperties->vtbl->nsisupports.Release((nsISupports *)systemProperties);
                systemProperties = NULL;
            }

            DEBUG("Number of Serial Ports to be connected: %d", def->nserials);
            DEBUG("Number of Serial Ports available: %d", serialPortCount);
            for (i = 0; (i < def->nserials) && (i < serialPortCount); i++) {
                ISerialPort *serialPort = NULL;

                DEBUG("SerialPort(%d): Type: %d", i, def->serials[i]->type);
                DEBUG("SerialPort(%d): dstPort: %d", i, def->serials[i]->dstPort);

                machine->vtbl->GetSerialPort(machine, i, &serialPort);
                if (serialPort) {
                    PRUnichar *pathUtf16 = NULL;

                    serialPort->vtbl->SetEnabled(serialPort, 1);
                    data->pFuncs->pfnUtf8ToUtf16(def->serials[i]->data.file.path, &pathUtf16);

                    /* For now hard code the serial ports to COM1 and COM2,
                     * COM1 (Base Addr: 0x3F8 (decimal: 1016), IRQ: 4)
                     * COM2 (Base Addr: 0x2F8 (decimal:  760), IRQ: 3)
                     * TODO: make this more flexible
                     */
                    /* TODO: to improve the libvirt XMl handling so
                     * that def->serials[i]->dstPort shows real port
                     * and not always start at 0
                     */
                    if (def->serials[i]->type == VIR_DOMAIN_CHR_TYPE_DEV) {
                        serialPort->vtbl->SetPath(serialPort, pathUtf16);
                        if (def->serials[i]->dstPort == 0) {
                            serialPort->vtbl->SetIRQ(serialPort, 4);
                            serialPort->vtbl->SetIOBase(serialPort, 1016);
                            DEBUG(" serialPort-%d irq: %d, iobase 0x%x, path: %s",
                                  i, 4, 1016, def->serials[i]->data.file.path);
                        } else if (def->serials[i]->dstPort == 1) {
                            serialPort->vtbl->SetIRQ(serialPort, 3);
                            serialPort->vtbl->SetIOBase(serialPort, 760);
                            DEBUG(" serialPort-%d irq: %d, iobase 0x%x, path: %s",
                                  i, 3, 760, def->serials[i]->data.file.path);
                        }
                        serialPort->vtbl->SetHostMode(serialPort, PortMode_HostDevice);
                    } else if (def->serials[i]->type == VIR_DOMAIN_CHR_TYPE_PIPE) {
                        serialPort->vtbl->SetPath(serialPort, pathUtf16);
                        if (def->serials[i]->dstPort == 0) {
                            serialPort->vtbl->SetIRQ(serialPort, 4);
                            serialPort->vtbl->SetIOBase(serialPort, 1016);
                            DEBUG(" serialPort-%d irq: %d, iobase 0x%x, path: %s",
                                  i, 4, 1016, def->serials[i]->data.file.path);
                        } else if (def->serials[i]->dstPort == 1) {
                            serialPort->vtbl->SetIRQ(serialPort, 3);
                            serialPort->vtbl->SetIOBase(serialPort, 760);
                            DEBUG(" serialPort-%d irq: %d, iobase 0x%x, path: %s",
                                  i, 3, 760, def->serials[i]->data.file.path);
                        }
                        if (!virFileExists(def->serials[i]->data.file.path)) {
                            serialPort->vtbl->SetServer(serialPort, 1);
                        }
                        serialPort->vtbl->SetHostMode(serialPort, PortMode_HostPipe);
                    } else if (def->serials[i]->type == VIR_DOMAIN_CHR_TYPE_NULL) {
                        serialPort->vtbl->SetHostMode(serialPort, PortMode_Disconnected);
                    }

                    serialPort->vtbl->nsisupports.Release((nsISupports *)serialPort);
                    if (pathUtf16) {
                        data->pFuncs->pfnUtf16Free(pathUtf16);
                        pathUtf16 = NULL;
                    }
                }
            }
        }   /* Finished:Block to attach the Serial Port to the VM */

        {   /* Started:Block to attach the Parallel Port to the VM */
            ISystemProperties *systemProperties = NULL;
            PRUint32 parallelPortCount          = 0;
            int i = 0;

            data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
            if (systemProperties) {
                systemProperties->vtbl->GetParallelPortCount(systemProperties, &parallelPortCount);
                systemProperties->vtbl->nsisupports.Release((nsISupports *)systemProperties);
                systemProperties = NULL;
            }

            DEBUG("Number of Parallel Ports to be connected: %d", def->nparallels);
            DEBUG("Number of Parallel Ports available: %d", parallelPortCount);
            for (i = 0; (i < def->nparallels) && (i < parallelPortCount); i++) {
                IParallelPort *parallelPort = NULL;

                DEBUG("ParallelPort(%d): Type: %d", i, def->parallels[i]->type);
                DEBUG("ParallelPort(%d): dstPort: %d", i, def->parallels[i]->dstPort);

                machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                if (parallelPort) {
                    PRUnichar *pathUtf16 = NULL;

                    data->pFuncs->pfnUtf8ToUtf16(def->parallels[i]->data.file.path, &pathUtf16);

                    /* For now hard code the parallel ports to
                     * LPT1 (Base Addr: 0x378 (decimal: 888), IRQ: 7)
                     * LPT2 (Base Addr: 0x278 (decimal: 632), IRQ: 5)
                     * TODO: make this more flexible
                     */
                    if ((def->parallels[i]->type == VIR_DOMAIN_CHR_TYPE_DEV)  ||
                        (def->parallels[i]->type == VIR_DOMAIN_CHR_TYPE_PTY)  ||
                        (def->parallels[i]->type == VIR_DOMAIN_CHR_TYPE_FILE) ||
                        (def->parallels[i]->type == VIR_DOMAIN_CHR_TYPE_PIPE)) {
                        parallelPort->vtbl->SetPath(parallelPort, pathUtf16);
                        if (i == 0) {
                            parallelPort->vtbl->SetIRQ(parallelPort, 7);
                            parallelPort->vtbl->SetIOBase(parallelPort, 888);
                            DEBUG(" parallePort-%d irq: %d, iobase 0x%x, path: %s",
                                  i, 7, 888, def->parallels[i]->data.file.path);
                        } else if (i == 1) {
                            parallelPort->vtbl->SetIRQ(parallelPort, 5);
                            parallelPort->vtbl->SetIOBase(parallelPort, 632);
                            DEBUG(" parallePort-%d irq: %d, iobase 0x%x, path: %s",
                                  i, 5, 632, def->parallels[i]->data.file.path);
                        }
                    }

                    /* like serial port, parallel port can't be enabled unless
                     * correct IRQ and IOBase values are specified.
                     */
                    parallelPort->vtbl->SetEnabled(parallelPort, 1);

                    parallelPort->vtbl->nsisupports.Release((nsISupports *)parallelPort);
                    if (pathUtf16) {
                        data->pFuncs->pfnUtf16Free(pathUtf16);
                        pathUtf16 = NULL;
                    }
                }
            }
        }   /* Finished:Block to attach the Parallel Port to the VM */

        {   /* Started:Block to attach the Remote Display to VM */
            int vrdpPresent  = 0;
            int sdlPresent   = 0;
            int guiPresent   = 0;
            char *guiDisplay = NULL;
            char *sdlDisplay = NULL;
            int i = 0;

            for (i = 0; i < def->ngraphics; i++) {
                IVRDPServer *VRDPServer = NULL;

                if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP) && (vrdpPresent == 0)) {

                    vrdpPresent = 1;
                    machine->vtbl->GetVRDPServer(machine, &VRDPServer);
                    if (VRDPServer) {
                        VRDPServer->vtbl->SetEnabled(VRDPServer, PR_TRUE);
                        DEBUG0("VRDP Support turned ON on port: 3389");

                        if (def->graphics[i]->data.rdp.port) {
                            VRDPServer->vtbl->SetPort(VRDPServer, def->graphics[i]->data.rdp.port);
                            DEBUG("VRDP Port changed to: %d", def->graphics[i]->data.rdp.port);
                        } else if (def->graphics[i]->data.rdp.autoport) {
                            /* Setting the port to 0 will reset its value to
                             * the default one which is 3389 currently
                             */
                            VRDPServer->vtbl->SetPort(VRDPServer, 0);
                            DEBUG0("VRDP Port changed to default, which is 3389 currently");
                        }

                        if (def->graphics[i]->data.rdp.replaceUser) {
                            VRDPServer->vtbl->SetReuseSingleConnection(VRDPServer, PR_TRUE);
                            DEBUG0("VRDP set to reuse single connection");
                        }

                        if (def->graphics[i]->data.rdp.multiUser) {
                            VRDPServer->vtbl->SetAllowMultiConnection(VRDPServer, PR_TRUE);
                            DEBUG0("VRDP set to allow multiple connection");
                        }

                        if (def->graphics[i]->data.rdp.listenAddr) {
                            PRUnichar *netAddressUtf16 = NULL;

                            data->pFuncs->pfnUtf8ToUtf16(def->graphics[i]->data.rdp.listenAddr, &netAddressUtf16);
                            VRDPServer->vtbl->SetNetAddress(VRDPServer, netAddressUtf16);
                            DEBUG("VRDP listen address is set to: %s", def->graphics[i]->data.rdp.listenAddr);

                            data->pFuncs->pfnUtf16Free(netAddressUtf16);
                        }

                        VRDPServer->vtbl->nsisupports.Release((nsISupports *)VRDPServer);
                    }
                }

                if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) && (guiPresent == 0)) {
                    guiPresent = 1;
                    guiDisplay = strdup(def->graphics[i]->data.desktop.display);
                    if (guiDisplay == NULL) {
                        vboxError(conn, VIR_ERR_SYSTEM_ERROR, "%s", "strdup failed");
                        /* just don't go to cleanup yet as it is ok to have
                         * guiDisplay as NULL and we check it below if it
                         * exist and then only use it there
                         */
                    }
                }

                if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) && (sdlPresent == 0)) {
                    sdlPresent = 1;
                    sdlDisplay = strdup(def->graphics[i]->data.sdl.display);
                    if (sdlDisplay == NULL) {
                        vboxError(conn, VIR_ERR_SYSTEM_ERROR, "%s", "strdup failed");
                        /* just don't go to cleanup yet as it is ok to have
                         * sdlDisplay as NULL and we check it below if it
                         * exist and then only use it there
                         */
                    }
                }
            }

            if ((vrdpPresent == 1) && (guiPresent == 0) && (sdlPresent == 0)) {
                /* store extradata key that frontend is set to vrdp */
                PRUnichar *keyTypeUtf16   = NULL;
                PRUnichar *valueTypeUtf16 = NULL;

                data->pFuncs->pfnUtf8ToUtf16("FRONTEND/Type", &keyTypeUtf16);
                data->pFuncs->pfnUtf8ToUtf16("vrdp", &valueTypeUtf16);

                machine->vtbl->SetExtraData(machine, keyTypeUtf16, valueTypeUtf16);

                data->pFuncs->pfnUtf16Free(keyTypeUtf16);
                data->pFuncs->pfnUtf16Free(valueTypeUtf16);

            } else if ((guiPresent == 0) && (sdlPresent == 1)) {
                /* store extradata key that frontend is set to sdl */
                PRUnichar *keyTypeUtf16      = NULL;
                PRUnichar *valueTypeUtf16    = NULL;
                PRUnichar *keyDislpayUtf16   = NULL;
                PRUnichar *valueDisplayUtf16 = NULL;

                data->pFuncs->pfnUtf8ToUtf16("FRONTEND/Type", &keyTypeUtf16);
                data->pFuncs->pfnUtf8ToUtf16("sdl", &valueTypeUtf16);

                machine->vtbl->SetExtraData(machine, keyTypeUtf16, valueTypeUtf16);

                data->pFuncs->pfnUtf16Free(keyTypeUtf16);
                data->pFuncs->pfnUtf16Free(valueTypeUtf16);

                if (sdlDisplay) {
                    data->pFuncs->pfnUtf8ToUtf16("FRONTEND/Display", &keyDislpayUtf16);
                    data->pFuncs->pfnUtf8ToUtf16(sdlDisplay, &valueDisplayUtf16);

                    machine->vtbl->SetExtraData(machine, keyDislpayUtf16, valueDisplayUtf16);

                    data->pFuncs->pfnUtf16Free(keyDislpayUtf16);
                    data->pFuncs->pfnUtf16Free(valueDisplayUtf16);
                }

            } else {
                /* if all are set then default is gui, with vrdp turned on */
                PRUnichar *keyTypeUtf16      = NULL;
                PRUnichar *valueTypeUtf16    = NULL;
                PRUnichar *keyDislpayUtf16   = NULL;
                PRUnichar *valueDisplayUtf16 = NULL;

                data->pFuncs->pfnUtf8ToUtf16("FRONTEND/Type", &keyTypeUtf16);
                data->pFuncs->pfnUtf8ToUtf16("gui", &valueTypeUtf16);

                machine->vtbl->SetExtraData(machine, keyTypeUtf16, valueTypeUtf16);

                data->pFuncs->pfnUtf16Free(keyTypeUtf16);
                data->pFuncs->pfnUtf16Free(valueTypeUtf16);

                if (guiDisplay) {
                    data->pFuncs->pfnUtf8ToUtf16("FRONTEND/Display", &keyDislpayUtf16);
                    data->pFuncs->pfnUtf8ToUtf16(guiDisplay, &valueDisplayUtf16);

                    machine->vtbl->SetExtraData(machine, keyDislpayUtf16, valueDisplayUtf16);

                    data->pFuncs->pfnUtf16Free(keyDislpayUtf16);
                    data->pFuncs->pfnUtf16Free(valueDisplayUtf16);
                }
            }

            VIR_FREE(guiDisplay);
            VIR_FREE(sdlDisplay);

        }   /* Finished:Block to attach the Remote Display to VM */

        {   /* Started:Block to attach USB Devices to VM */
            if (def->nhostdevs > 0) {
                IUSBController *USBController = NULL;
                int i = 0, isUSB = 0;
                /* Loop through the devices first and see if you
                 * have a USB Device, only if you have one then
                 * start the USB controller else just proceed as
                 * usual
                 */
                for (i = 0; i < def->nhostdevs; i++) {
                    if (def->hostdevs[i]->mode ==
                            VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
                        if (def->hostdevs[i]->source.subsys.type ==
                                VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
                            if (def->hostdevs[i]->source.subsys.u.usb.vendor ||
                                def->hostdevs[i]->source.subsys.u.usb.product) {
                                DEBUG("USB Device detected, VendorId:0x%x, ProductId:0x%x",
                                      def->hostdevs[i]->source.subsys.u.usb.vendor,
                                      def->hostdevs[i]->source.subsys.u.usb.product);
                                isUSB++;
                            }
                        }
                    }
                }

                if (isUSB > 0) {
                    /* First Start the USB Controller and then loop
                     * to attach USB Devices to it
                     */
                    machine->vtbl->GetUSBController(machine, &USBController);
                    if (USBController) {
                        USBController->vtbl->SetEnabled(USBController, 1);
                        USBController->vtbl->SetEnabledEhci(USBController, 1);

                        for (i = 0; i < def->nhostdevs; i++) {
                            if (def->hostdevs[i]->mode ==
                                    VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
                                if (def->hostdevs[i]->source.subsys.type ==
                                        VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {

                                    char filtername[11]        = {0};
                                    PRUnichar *filternameUtf16 = NULL;
                                    IUSBDeviceFilter *filter   = NULL;

                                    /* Assuming can't have more then 9999 devices so
                                     * restricting to %04d
                                     */
                                    sprintf(filtername, "filter%04d", i);
                                    data->pFuncs->pfnUtf8ToUtf16(filtername, &filternameUtf16);

                                    USBController->vtbl->CreateDeviceFilter(USBController,
                                                                            filternameUtf16,
                                                                            &filter);
                                    data->pFuncs->pfnUtf16Free(filternameUtf16);

                                    if (filter &&
                                        (def->hostdevs[i]->source.subsys.u.usb.vendor ||
                                        def->hostdevs[i]->source.subsys.u.usb.product)) {

                                        PRUnichar *vendorIdUtf16  = NULL;
                                        char vendorId[40]         = {0};
                                        PRUnichar *productIdUtf16 = NULL;
                                        char productId[40]        = {0};

                                        if (def->hostdevs[i]->source.subsys.u.usb.vendor) {
                                            sprintf(vendorId, "%x", def->hostdevs[i]->source.subsys.u.usb.vendor);
                                            data->pFuncs->pfnUtf8ToUtf16(vendorId, &vendorIdUtf16);
                                            filter->vtbl->SetVendorId(filter, vendorIdUtf16);
                                            data->pFuncs->pfnUtf16Free(vendorIdUtf16);
                                        }
                                        if (def->hostdevs[i]->source.subsys.u.usb.product) {
                                            sprintf(productId, "%x", def->hostdevs[i]->source.subsys.u.usb.product);
                                            data->pFuncs->pfnUtf8ToUtf16(productId, &productIdUtf16);
                                            filter->vtbl->SetProductId(filter, productIdUtf16);
                                            data->pFuncs->pfnUtf16Free(productIdUtf16);
                                        }
                                        filter->vtbl->SetActive(filter, 1);
                                        USBController->vtbl->InsertDeviceFilter(USBController,
                                                                                i,
                                                                                filter);
                                        filter->vtbl->nsisupports.Release((nsISupports *)filter);
                                    }

                                }
                            }
                        }
                        USBController->vtbl->nsisupports.Release((nsISupports *)USBController);
                    }
                }
            }
        }   /* Finished:Block to attach USB Devices to VM */

        /* Save the machine settings made till now and close the
         * session. also free up the mchiid variable used.
         */
        rc = machine->vtbl->SaveSettings(machine);
        data->vboxSession->vtbl->Close(data->vboxSession);
#if VBOX_API_VERSION == 2002
        vboxIIDUnalloc(mchiid);
#else
        vboxIIDFree(mchiid);
#endif

        dom = virGetDomain(conn, def->name, def->uuid);
        if(machine) {
            machine->vtbl->nsisupports.Release((nsISupports *)machine);
            machine = NULL;
        }
    }

    vboxIIDFree(iid);
    virDomainDefFree(def);

    return dom;

cleanup:
    if(machine)
        machine->vtbl->nsisupports.Release((nsISupports *)machine);
    vboxIIDFree(iid);
    virDomainDefFree(def);
    return NULL;
}

static int vboxDomainUndefine(virDomainPtr dom) {
    nsresult rc;
    vboxGlobalData *data = dom->conn->privateData;
    IMachine *machine    = NULL;
    vboxIID  *iid        = NULL;
    int ret = -1;

#if VBOX_API_VERSION == 2002
    if (VIR_ALLOC(iid) < 0) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }
#endif

    if(data->vboxObj) {
        vboxIIDFromUUID(dom->uuid, iid);

        /* Block for checking if HDD's are attched to VM.
         * considering just IDE bus for now. Also skipped
         * chanel=1 and device=0 (Secondary Master) as currenlty
         * it is allocated to CD/DVD Drive bt default
         */
        {
            PRUnichar *hddcnameUtf16 = NULL;

            char *hddcname = strdup("IDE");
            data->pFuncs->pfnUtf8ToUtf16(hddcname, &hddcnameUtf16);
            VIR_FREE(hddcname);

            /* Open a Session for the machine */
            rc = data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, iid);
            if (NS_SUCCEEDED(rc)) {
                rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
                if (NS_SUCCEEDED(rc) && machine) {

                    /* Disconnect all the drives if present */
                    machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 0, 0);
                    machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 0, 1);
                    machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 1, 1);

                    machine->vtbl->SaveSettings(machine);
                }
                data->vboxSession->vtbl->Close(data->vboxSession);
            }
            data->pFuncs->pfnUtf16Free(hddcnameUtf16);
        }

        rc = data->vboxObj->vtbl->UnregisterMachine(data->vboxObj, iid, &machine);
#if VBOX_API_VERSION == 2002
        DEBUGUUID("UUID of machine being undefined", iid);
#else
        DEBUGPRUnichar("UUID of machine being undefined", iid);
#endif

        if (NS_SUCCEEDED(rc) && machine){
            machine->vtbl->DeleteSettings(machine);
            ret = 0;
        }
    }

#if VBOX_API_VERSION == 2002
cleanup:
#endif
    vboxIIDFree(iid);
    if (machine)
        machine->vtbl->nsisupports.Release((nsISupports *)machine);

    return ret;
}

static int vboxDomainAttachDevice(virDomainPtr dom, const char *xml) {
    nsresult rc;
    vboxGlobalData *data = dom->conn->privateData;
    IMachine *machine    = NULL;
    vboxIID  *iid        = NULL;
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
    int ret = -1;

    if (VIR_ALLOC(def) < 0) {
        virReportOOMError(dom->conn);
        return ret;
    }

    def->os.type = strdup("hvm");

    dev = virDomainDeviceDefParse(dom->conn, data->caps, def, xml,
                                  VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }

#if VBOX_API_VERSION == 2002
    if (VIR_ALLOC(iid) < 0) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }
#endif

    vboxIIDFromUUID(dom->uuid, iid);

    if(data->vboxObj) {
        rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
        if (NS_FAILED(rc)) {
            vboxError(dom->conn, VIR_ERR_INVALID_DOMAIN,"no domain with matching uuid");
            goto cleanup;
        }

        if (machine) {
            machine->vtbl->GetState(machine, &state);

            if ((state == MachineState_Running) ||
                (state == MachineState_Paused)) {
                rc = data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
            } else {
                rc = data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, iid);
            }
            if (NS_SUCCEEDED(rc)) {
                rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
                if (NS_SUCCEEDED(rc) && machine) {
                    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
                        if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                            if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_FILE) {
                                IDVDDrive *dvdDrive = NULL;
                                /* Currently CDROM/DVD Drive is always IDE
                                 * Secondary Master so neglecting the following
                                 * parameter dev->data.disk->bus
                                 */
                                machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                                if (dvdDrive) {
                                    IDVDImage *dvdImage          = NULL;
                                    PRUnichar *dvdfileUtf16      = NULL;
                                    vboxIID   *dvduuid           = NULL;
#if VBOX_API_VERSION == 2002
                                    nsID dvdemptyuuid;

                                    memset(&dvdemptyuuid, 0, sizeof(dvdemptyuuid));
#else
                                    PRUnichar *dvdemptyuuidUtf16 = NULL;
#endif

                                    data->pFuncs->pfnUtf8ToUtf16(dev->data.disk->src, &dvdfileUtf16);

                                    data->vboxObj->vtbl->FindDVDImage(data->vboxObj, dvdfileUtf16, &dvdImage);
                                    if (!dvdImage) {
#if VBOX_API_VERSION == 2002
                                        data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, &dvdemptyuuid, &dvdImage);
#else
                                        data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, dvdemptyuuidUtf16, &dvdImage);
#endif
                                    }
                                    if (dvdImage) {
                                        rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage, &dvduuid);
                                        if (NS_FAILED(rc)) {
                                            vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
                                                      "can't get the uuid of the file to be attached to cdrom",
                                                      dev->data.disk->src, (unsigned)rc);
                                        } else {
                                            /* unmount the previous mounted image */
                                            dvdDrive->vtbl->Unmount(dvdDrive);
                                            rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid);
                                            if (NS_FAILED(rc)) {
                                                vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
                                                          "could not attach the file to cdrom",
                                                          dev->data.disk->src, (unsigned)rc);
                                            } else {
                                                ret = 0;
#if VBOX_API_VERSION == 2002
                                                DEBUGUUID("CD/DVD Image UUID:", dvduuid);
#else
                                                DEBUGPRUnichar("CD/DVD Image UUID:", dvduuid);
#endif
                                            }
                                        }

                                        dvdImage->vtbl->imedium.nsisupports.Release((nsISupports *)dvdImage);
                                    }
#if VBOX_API_VERSION == 2002
                                    vboxIIDUnalloc(dvduuid);
#else
                                    vboxIIDFree(dvduuid);
#endif
                                    data->pFuncs->pfnUtf16Free(dvdfileUtf16);
                                    dvdDrive->vtbl->nsisupports.Release((nsISupports *)dvdDrive);
                                }
                            } else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
                            }
                        } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
                            if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_FILE) {
                                IFloppyDrive *floppyDrive;
                                machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
                                if (floppyDrive) {
                                    rc = floppyDrive->vtbl->SetEnabled(floppyDrive, 1);
                                    if (NS_SUCCEEDED(rc)) {
                                        IFloppyImage *floppyImage   = NULL;
                                        PRUnichar *fdfileUtf16      = NULL;
                                        vboxIID *fduuid             = NULL;
#if VBOX_API_VERSION == 2002
                                        nsID fdemptyuuid;

                                        memset(&fdemptyuuid, 0, sizeof(fdemptyuuid));
#else
                                        PRUnichar *fdemptyuuidUtf16 = NULL;
#endif
                                        data->pFuncs->pfnUtf8ToUtf16(dev->data.disk->src, &fdfileUtf16);
                                        rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                                  fdfileUtf16,
                                                                                  &floppyImage);

                                        if (!floppyImage) {
                                            data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                                 fdfileUtf16,
#if VBOX_API_VERSION == 2002
                                                                                 &fdemptyuuid,
#else
                                                                                 fdemptyuuidUtf16,
#endif
                                                                                 &floppyImage);
                                        }

                                        if (floppyImage) {
                                            rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage, &fduuid);
                                            if (NS_FAILED(rc)) {
                                                vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
                                                          "can't get the uuid of the file to be attached to floppy drive",
                                                          dev->data.disk->src, (unsigned)rc);
                                            } else {
                                                rc = floppyDrive->vtbl->MountImage(floppyDrive, fduuid);
                                                if (NS_FAILED(rc)) {
                                                    vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x",
                                                              "could not attach the file to floppy drive",
                                                              dev->data.disk->src, (unsigned)rc);
                                                } else {
                                                    ret = 0;
#if VBOX_API_VERSION == 2002
                                                    DEBUGUUID("attached floppy, UUID:", fduuid);
#else
                                                    DEBUGPRUnichar("attached floppy, UUID:", fduuid);
#endif
                                                }
                                            }
                                            floppyImage->vtbl->imedium.nsisupports.Release((nsISupports *)floppyImage);
                                        }
#if VBOX_API_VERSION == 2002
                                        vboxIIDUnalloc(fduuid);
#else
                                        vboxIIDFree(fduuid);
#endif
                                        data->pFuncs->pfnUtf16Free(fdfileUtf16);
                                    }
                                    floppyDrive->vtbl->nsisupports.Release((nsISupports *)floppyDrive);
                                }
                            } else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
                            }
                        }
                    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
                    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
                        if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
                            if (dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
                            }
                        }
                    }
                    machine->vtbl->SaveSettings(machine);
                    machine->vtbl->nsisupports.Release((nsISupports *)machine);
                }
                data->vboxSession->vtbl->Close(data->vboxSession);
            }
        }
    }

cleanup:
    vboxIIDFree(iid);
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

static int vboxDomainDetachDevice(virDomainPtr dom, const char *xml) {
    nsresult rc;
    vboxGlobalData *data = dom->conn->privateData;
    IMachine *machine    = NULL;
    vboxIID  *iid        = NULL;
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
    int ret = -1;

    if (VIR_ALLOC(def) < 0) {
        virReportOOMError(dom->conn);
        return ret;
    }

    def->os.type = strdup("hvm");

    dev = virDomainDeviceDefParse(dom->conn, data->caps, def, xml,
                                  VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }

#if VBOX_API_VERSION == 2002
    if (VIR_ALLOC(iid) < 0) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }
#endif

    vboxIIDFromUUID(dom->uuid, iid);

    if(data->vboxObj) {
        rc = data->vboxObj->vtbl->GetMachine(data->vboxObj, iid, &machine);
        if (NS_FAILED(rc)) {
            vboxError(dom->conn, VIR_ERR_INVALID_DOMAIN, "no domain with matching uuid");
            goto cleanup;
        }

        if (machine) {
            machine->vtbl->GetState(machine, &state);

            if ((state == MachineState_Running) ||
                (state == MachineState_Paused)) {
                rc = data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid);
            } else {
                rc = data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, iid);
            }

            if (NS_SUCCEEDED(rc)) {
                rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
                if (NS_SUCCEEDED(rc) && machine) {
                    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
                        if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                            if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_FILE) {
                                IDVDDrive *dvdDrive = NULL;
                                /* Currently CDROM/DVD Drive is always IDE
                                 * Secondary Master so neglecting the following
                                 * parameter dev->data.disk->bus
                                 */
                                machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                                if (dvdDrive) {
                                    rc = dvdDrive->vtbl->Unmount(dvdDrive);
                                    if (NS_FAILED(rc)) {
                                        vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
                                                  "could not de-attach the mounted ISO",
                                                  (unsigned)rc);
                                    } else {
                                        ret = 0;
                                    }
                                    dvdDrive->vtbl->nsisupports.Release((nsISupports *)dvdDrive);
                                }
                            } else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
                            }
                        } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
                            if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_FILE) {
                                IFloppyDrive *floppyDrive;
                                machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
                                if (floppyDrive) {
                                    PRBool enabled = PR_FALSE;

                                    floppyDrive->vtbl->GetEnabled(floppyDrive, &enabled);
                                    if (enabled) {
                                        rc = floppyDrive->vtbl->Unmount(floppyDrive);
                                        if (NS_FAILED(rc)) {
                                            vboxError(dom->conn, VIR_ERR_INTERNAL_ERROR,"%s, rc=%08x",
                                                      "could not attach the file to floppy drive",
                                                      (unsigned)rc);
                                        } else {
                                            ret = 0;
                                        }
                                    } else {
                                        /* If you are here means floppy drive is already unmounted
                                         * so don't flag error, just say everything is fine and quit
                                         */
                                        ret = 0;
                                    }
                                    floppyDrive->vtbl->nsisupports.Release((nsISupports *)floppyDrive);
                                }
                            } else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
                            }
                        }
                    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
                    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
                        if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
                            if (dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
                            }
                        }
                    }
                    machine->vtbl->SaveSettings(machine);
                    machine->vtbl->nsisupports.Release((nsISupports *)machine);
                }
                data->vboxSession->vtbl->Close(data->vboxSession);
            }
        }
    }

cleanup:
    vboxIIDFree(iid);
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

#if VBOX_API_VERSION == 2002
    /* No Callback support for VirtualBox 2.2.* series */
#else /* !(VBOX_API_VERSION == 2002) */

/* Functions needed for Callbacks */
static  nsresult vboxCallbackOnMachineStateChange (IVirtualBoxCallback *pThis,
                                                   PRUnichar * machineId,
                                                   PRUint32 state) {
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    g_pVBoxGlobalData->domainEventDispatching = 1;
    vboxDriverLock(g_pVBoxGlobalData);

    DEBUG("IVirtualBoxCallback: %p, State: %d", pThis, state);
    DEBUGPRUnichar("machineId", machineId);

    if (machineId) {
        char *machineIdUtf8       = NULL;
        unsigned char uuid[VIR_UUID_BUFLEN];

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
        virUUIDParse(machineIdUtf8, uuid);

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
            int i = 0;

            if (state == MachineState_Starting) {
                event  = VIR_DOMAIN_EVENT_STARTED;
                detail = VIR_DOMAIN_EVENT_STARTED_BOOTED;
            } else if (state == MachineState_Restoring) {
                event  = VIR_DOMAIN_EVENT_STARTED;
                detail = VIR_DOMAIN_EVENT_STARTED_RESTORED;
            } else if (state == MachineState_Paused) {
                event  = VIR_DOMAIN_EVENT_SUSPENDED;
                detail = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED;
            } else if (state == MachineState_Running) {
                event  = VIR_DOMAIN_EVENT_RESUMED;
                detail = VIR_DOMAIN_EVENT_RESUMED_UNPAUSED;
            } else if (state == MachineState_PoweredOff) {
                event  = VIR_DOMAIN_EVENT_STOPPED;
                detail = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN;
            } else if (state == MachineState_Stopping) {
                event  = VIR_DOMAIN_EVENT_STOPPED;
                detail = VIR_DOMAIN_EVENT_STOPPED_DESTROYED;
            } else if (state == MachineState_Aborted) {
                event  = VIR_DOMAIN_EVENT_STOPPED;
                detail = VIR_DOMAIN_EVENT_STOPPED_CRASHED;
            } else if (state == MachineState_Saving) {
                event  = VIR_DOMAIN_EVENT_STOPPED;
                detail = VIR_DOMAIN_EVENT_STOPPED_SAVED;
            } else {
                event  = VIR_DOMAIN_EVENT_STOPPED;
                detail = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN;
            }

            for (i = 0; i < g_pVBoxGlobalData->domainEventCallbacks->count; i++) {
                if (g_pVBoxGlobalData->domainEventCallbacks->callbacks[i]->cb) {
                    g_pVBoxGlobalData->domainEventCallbacks->callbacks[i]->cb(g_pVBoxGlobalData->conn,
                                                                              dom,
                                                                              event,
                                                                              detail,
                                                                              NULL);
                }
            }
        }
    }

    virDomainEventCallbackListPurgeMarked(g_pVBoxGlobalData->domainEventCallbacks);

    vboxDriverUnlock(g_pVBoxGlobalData);
    g_pVBoxGlobalData->domainEventDispatching = 0;

    return NS_OK;
}

static nsresult vboxCallbackOnMachineDataChange (IVirtualBoxCallback *pThis,
                                                 PRUnichar * machineId) {
    DEBUG("IVirtualBoxCallback: %p", pThis);
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

static nsresult vboxCallbackOnExtraDataCanChange (IVirtualBoxCallback *pThis,
                                                  PRUnichar * machineId,
                                                  PRUnichar * key,
                                                  PRUnichar * value,
                                                  PRUnichar * * error ATTRIBUTE_UNUSED,
                                                  PRBool * allowChange) {
    DEBUG("IVirtualBoxCallback: %p, allowChange: %s", pThis, *allowChange ? "true" : "false");
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

static nsresult vboxCallbackOnExtraDataChange (IVirtualBoxCallback *pThis,
                                               PRUnichar * machineId,
                                               PRUnichar * key,
                                               PRUnichar * value) {
    DEBUG("IVirtualBoxCallback: %p", pThis);
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

static nsresult vboxCallbackOnMediaRegistered (IVirtualBoxCallback *pThis,
                                               PRUnichar * mediaId,
                                               PRUint32 mediaType,
                                               PRBool registered) {
    DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
    DEBUG("mediaType: %d", mediaType);
    DEBUGPRUnichar("mediaId", mediaId);

    return NS_OK;
}

static nsresult vboxCallbackOnMachineRegistered (IVirtualBoxCallback *pThis,
                                                 PRUnichar * machineId,
                                                 PRBool registered) {
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    g_pVBoxGlobalData->domainEventDispatching = 1;
    vboxDriverLock(g_pVBoxGlobalData);

    DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
    DEBUGPRUnichar("machineId", machineId);

    if (machineId) {
        char *machineIdUtf8       = NULL;
        unsigned char uuid[VIR_UUID_BUFLEN];

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
        virUUIDParse(machineIdUtf8, uuid);

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
            int i = 0;

            /* CURRENT LIMITATION: we never get the VIR_DOMAIN_EVENT_UNDEFINED
             * event becuase the when the machine is de-registered the call
             * to vboxDomainLookupByUUID fails and thus we don't get any
             * dom pointer which is necessary (null dom pointer doesn't work)
             * to show the VIR_DOMAIN_EVENT_UNDEFINED event
             */
            if (registered) {
                event  = VIR_DOMAIN_EVENT_DEFINED;
                detail = VIR_DOMAIN_EVENT_DEFINED_ADDED;
            } else {
                event  = VIR_DOMAIN_EVENT_UNDEFINED;
                detail = VIR_DOMAIN_EVENT_UNDEFINED_REMOVED;
            }

            for (i = 0; i < g_pVBoxGlobalData->domainEventCallbacks->count; i++) {
                if (g_pVBoxGlobalData->domainEventCallbacks->callbacks[i]->cb) {
                    g_pVBoxGlobalData->domainEventCallbacks->callbacks[i]->cb(g_pVBoxGlobalData->conn,
                                                                              dom,
                                                                              event,
                                                                              detail,
                                                                              NULL);
                }
            }
        }
    }

    virDomainEventCallbackListPurgeMarked(g_pVBoxGlobalData->domainEventCallbacks);

    vboxDriverUnlock(g_pVBoxGlobalData);
    g_pVBoxGlobalData->domainEventDispatching = 0;

    return NS_OK;
}

static nsresult vboxCallbackOnSessionStateChange (IVirtualBoxCallback *pThis,
                                                  PRUnichar * machineId,
                                                  PRUint32 state) {
    DEBUG("IVirtualBoxCallback: %p, state: %d", pThis, state);
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

static nsresult vboxCallbackOnSnapshotTaken (IVirtualBoxCallback *pThis,
                                             PRUnichar * machineId,
                                             PRUnichar * snapshotId) {
    DEBUG("IVirtualBoxCallback: %p", pThis);
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

static nsresult vboxCallbackOnSnapshotDiscarded (IVirtualBoxCallback *pThis,
                                                 PRUnichar * machineId,
                                                 PRUnichar * snapshotId) {
    DEBUG("IVirtualBoxCallback: %p", pThis);
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

static nsresult vboxCallbackOnSnapshotChange (IVirtualBoxCallback *pThis,
                                              PRUnichar * machineId,
                                              PRUnichar * snapshotId) {
    DEBUG("IVirtualBoxCallback: %p", pThis);
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

static nsresult vboxCallbackOnGuestPropertyChange (IVirtualBoxCallback *pThis,
                                                   PRUnichar * machineId,
                                                   PRUnichar * name,
                                                   PRUnichar * value,
                                                   PRUnichar * flags) {
    DEBUG("IVirtualBoxCallback: %p", pThis);
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("name", name);
    DEBUGPRUnichar("value", value);
    DEBUGPRUnichar("flags", flags);

    return NS_OK;
}

static nsresult vboxCallbackAddRef(nsISupports *pThis) {
    nsresult c;

    c = ++g_pVBoxGlobalData->vboxCallBackRefCount;

    DEBUG("pThis: %p, vboxCallback AddRef: %d", pThis, c);

    return c;
}

static nsresult vboxCallbackRelease(nsISupports *pThis) {
    nsresult c;

    c = --g_pVBoxGlobalData->vboxCallBackRefCount;
    if (c == 0) {
        /* delete object */
        VIR_FREE(pThis->vtbl);
        VIR_FREE(pThis);
    }

    DEBUG("pThis: %p, vboxCallback Release: %d", pThis, c);

    return c;
}

static nsresult vboxCallbackQueryInterface(nsISupports *pThis, const nsID *iid, void **resultp) {
    IVirtualBoxCallback *that = (IVirtualBoxCallback *)pThis;
    static const nsID ivirtualboxCallbackUUID = IVIRTUALBOXCALLBACK_IID;
    static const nsID isupportIID = NS_ISUPPORTS_IID;

    /* Match UUID for IVirtualBoxCallback class */
    if (    memcmp(iid, &ivirtualboxCallbackUUID, sizeof(nsID)) == 0
        ||  memcmp(iid, &isupportIID, sizeof(nsID)) == 0) {
        g_pVBoxGlobalData->vboxCallBackRefCount++;
        *resultp = that;

        DEBUG("pThis: %p, vboxCallback QueryInterface: %d", pThis, g_pVBoxGlobalData->vboxCallBackRefCount);

        return NS_OK;
    }


    DEBUG("pThis: %p, vboxCallback QueryInterface didn't find a matching interface", pThis);
    DEBUGUUID("The UUID Callback Interface expects", iid);
    DEBUGUUID("The UUID Callback Interface got", &ivirtualboxCallbackUUID);
    return NS_NOINTERFACE;
}


static IVirtualBoxCallback *vboxAllocCallbackObj (virConnectPtr conn) {
    IVirtualBoxCallback *vboxCallback = NULL;

    /* Allocate, Initialize and return a validi
     * IVirtualBoxCallback object here
     */
    if ((VIR_ALLOC(vboxCallback) < 0) || (VIR_ALLOC(vboxCallback->vtbl) < 0)) {
        virReportOOMError(conn);
        return NULL;
    }

    {
        vboxCallback->vtbl->nsisupports.AddRef          = &vboxCallbackAddRef;
        vboxCallback->vtbl->nsisupports.Release         = &vboxCallbackRelease;
        vboxCallback->vtbl->nsisupports.QueryInterface  = &vboxCallbackQueryInterface;
        vboxCallback->vtbl->OnMachineStateChange        = &vboxCallbackOnMachineStateChange;
        vboxCallback->vtbl->OnMachineDataChange         = &vboxCallbackOnMachineDataChange;
        vboxCallback->vtbl->OnExtraDataCanChange        = &vboxCallbackOnExtraDataCanChange;
        vboxCallback->vtbl->OnExtraDataChange           = &vboxCallbackOnExtraDataChange;
        vboxCallback->vtbl->OnMediaRegistered           = &vboxCallbackOnMediaRegistered;
        vboxCallback->vtbl->OnMachineRegistered         = &vboxCallbackOnMachineRegistered;
        vboxCallback->vtbl->OnSessionStateChange        = &vboxCallbackOnSessionStateChange;
        vboxCallback->vtbl->OnSnapshotTaken             = &vboxCallbackOnSnapshotTaken;
        vboxCallback->vtbl->OnSnapshotDiscarded         = &vboxCallbackOnSnapshotDiscarded;
        vboxCallback->vtbl->OnSnapshotChange            = &vboxCallbackOnSnapshotChange;
        vboxCallback->vtbl->OnGuestPropertyChange       = &vboxCallbackOnGuestPropertyChange;
        g_pVBoxGlobalData->vboxCallBackRefCount = 1;

    }

    return vboxCallback;
}

static void vboxReadCallback(int watch ATTRIBUTE_UNUSED,
                             int fd,
                             int events ATTRIBUTE_UNUSED,
                             void *opaque ATTRIBUTE_UNUSED) {
    if (fd >= 0) {
        g_pVBoxGlobalData->vboxQueue->vtbl->ProcessPendingEvents(g_pVBoxGlobalData->vboxQueue);
    } else {
        nsresult rc;
        PLEvent *pEvent = NULL;

        rc = g_pVBoxGlobalData->vboxQueue->vtbl->WaitForEvent(g_pVBoxGlobalData->vboxQueue, &pEvent);
        if (NS_SUCCEEDED(rc))
            g_pVBoxGlobalData->vboxQueue->vtbl->HandleEvent(g_pVBoxGlobalData->vboxQueue, pEvent);
    }
}

static int vboxDomainEventRegister (virConnectPtr conn,
                                    virConnectDomainEventCallback callback,
                                    void *opaque,
                                    virFreeCallback freecb) {
    nsresult rc;
    vboxGlobalData *data = conn->privateData;
    int vboxRet          = -1;
    int ret              = -1;

    /* Locking has to be there as callbacks are not
     * really fully thread safe
     */
    vboxDriverLock(data);

    if(data->vboxObj) {
        if (data->vboxCallback == NULL) {
            data->vboxCallback = vboxAllocCallbackObj(conn);
            if (data->vboxCallback != NULL) {
                rc = data->vboxObj->vtbl->RegisterCallback(data->vboxObj, data->vboxCallback);
                if (NS_SUCCEEDED(rc)) {
                    vboxRet = 0;
                }
            }
        } else {
            vboxRet = 0;
        }

        /* Get the vbox file handle and add a event handle to it
         * so that the events can be passed down to the user
         */
        if (vboxRet == 0) {
            if (data->fdWatch < 0) {
                PRInt32 vboxFileHandle;
                vboxFileHandle = data->vboxQueue->vtbl->GetEventQueueSelectFD(data->vboxQueue);

                data->fdWatch = virEventAddHandle(vboxFileHandle, VIR_EVENT_HANDLE_READABLE, vboxReadCallback, NULL, NULL);
            }

            if (data->fdWatch >= 0) {
                /* Once a callback is registered with virtualbox, use a list
                 * to store the callbacks registered with libvirt so that
                 * later you can iterate over them
                 */

                ret = virDomainEventCallbackListAdd(conn, data->domainEventCallbacks,
                                                    callback, opaque, freecb);
                DEBUG("virDomainEventCallbackListAdd (ret = %d) ( conn: %p, "
                      "data->domainEventCallbacks: %p, callback: %p, opaque: %p, "
                      "freecb: %p )", ret, conn, data->domainEventCallbacks, callback,
                      opaque, freecb);
            }
        }
    }

    vboxDriverUnlock(data);

    if (ret >= 0) {
        return ret;
    } else {
        if (data->vboxObj && data->vboxCallback) {
            data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        }
        return -1;
    }
}

static int vboxDomainEventDeregister (virConnectPtr conn,
                                      virConnectDomainEventCallback callback) {
    vboxGlobalData *data = conn->privateData;
    int ret              = -1;

    /* Locking has to be there as callbacks are not
     * really fully thread safe
     */
    vboxDriverLock(data);

    if (data->domainEventDispatching)
        ret = virDomainEventCallbackListMarkDelete(conn, data->domainEventCallbacks,
                                                   callback);
    else
        ret = virDomainEventCallbackListRemove(conn, data->domainEventCallbacks,
                                               callback);

    if(data->vboxObj && data->vboxCallback) {
        /* check count here of how many times register was called
         * and only on the last de-register do the un-register call
         */
        if (data->domainEventCallbacks && (data->domainEventCallbacks->count <= 0)) {
            int i = 0;

            data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
            data->vboxCallback->vtbl->nsisupports.Release((nsISupports *)data->vboxCallback);

            /* Remove the Event file handle on which we are listening as well */
            virEventRemoveHandle(data->fdWatch);
            data->fdWatch = -1;

            /* iterate and free all the opaque objects using the
             * freecb callback provided in vboxDomainEventRegister()
             */
            for (i = 0; i < data->domainEventCallbacks->count; i++) {
                if (data->domainEventCallbacks->callbacks[i]->freecb) {
                    data->domainEventCallbacks->callbacks[i]->freecb(data->domainEventCallbacks->callbacks[i]->opaque);
                }
            }
        }
    }

    vboxDriverUnlock(data);

    return ret;
}

#endif /* !(VBOX_API_VERSION == 2002) */

/**
 * The Network Functions here on
 */
static virDrvOpenStatus vboxNetworkOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                        int flags ATTRIBUTE_UNUSED) {
    vboxGlobalData *data = conn->privateData;

    if (STRNEQ(conn->driver->name, "VBOX"))
        goto cleanup;

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
        goto cleanup;

    DEBUG0("network intialized");
    /* conn->networkPrivateData = some network specific data */
    return VIR_DRV_OPEN_SUCCESS;

cleanup:
    return VIR_DRV_OPEN_DECLINED;
}

static int vboxNetworkClose(virConnectPtr conn) {
    DEBUG0("network unintialized");
    conn->networkPrivateData = NULL;
    return 0;
}

static int vboxNumOfNetworks(virConnectPtr conn) {
    vboxGlobalData *data = conn->privateData;
    int numActive = 0;

    if (data->vboxObj) {
        IHost *host = NULL;

        data->vboxObj->vtbl->GetHost(data->vboxObj, &host);
        if (host) {
            int i = 0;
            PRUint32 networkInterfacesSize = 0;
            IHostNetworkInterface **networkInterfaces = NULL;

            host->vtbl->GetNetworkInterfaces(host, &networkInterfacesSize, &networkInterfaces);

            for (i = 0; i < networkInterfacesSize; i++) {
                if (networkInterfaces[i]) {
                    PRUint32 interfaceType = 0;

                    networkInterfaces[i]->vtbl->GetInterfaceType(networkInterfaces[i], &interfaceType);
                    if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                        PRUint32 status = HostNetworkInterfaceStatus_Unknown;

                        networkInterfaces[i]->vtbl->GetStatus(networkInterfaces[i], &status);

                        if (status == HostNetworkInterfaceStatus_Up) {
                            numActive++;
                        }
                    }

                    networkInterfaces[i]->vtbl->nsisupports.Release((nsISupports *) networkInterfaces[i]);
                }
            }

            host->vtbl->nsisupports.Release((nsISupports *) host);
        }
    }

    DEBUG("numActive: %d", numActive);
    return numActive;
}

static int vboxListNetworks(virConnectPtr conn, char **const names, int nnames) {
    vboxGlobalData *data = conn->privateData;
    int numActive = 0;

    if (data->vboxObj) {
        IHost *host = NULL;

        data->vboxObj->vtbl->GetHost(data->vboxObj, &host);
        if (host) {
            int i = 0;
            PRUint32 networkInterfacesSize = 0;
            IHostNetworkInterface **networkInterfaces = NULL;

            host->vtbl->GetNetworkInterfaces(host, &networkInterfacesSize, &networkInterfaces);

            for (i = 0; (numActive < nnames) && (i < networkInterfacesSize); i++) {
                if (networkInterfaces[i]) {
                    PRUint32 interfaceType = 0;

                    networkInterfaces[i]->vtbl->GetInterfaceType(networkInterfaces[i], &interfaceType);

                    if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                        PRUint32 status = HostNetworkInterfaceStatus_Unknown;

                        networkInterfaces[i]->vtbl->GetStatus(networkInterfaces[i], &status);

                        if (status == HostNetworkInterfaceStatus_Up) {
                            char *nameUtf8       = NULL;
                            PRUnichar *nameUtf16 = NULL;

                            networkInterfaces[i]->vtbl->GetName(networkInterfaces[i], &nameUtf16);
                            data->pFuncs->pfnUtf16ToUtf8(nameUtf16, &nameUtf8);

                            DEBUG("nnames[%d]: %s", numActive, nameUtf8);
                            names[numActive] = strdup(nameUtf8);
                            if (names[numActive] == NULL) {
                                vboxError(conn, VIR_ERR_SYSTEM_ERROR, "%s", "strdup failed");
                            } else {
                                numActive++;
                            }

                            data->pFuncs->pfnUtf8Free(nameUtf8);
                            data->pFuncs->pfnUtf16Free(nameUtf16);
                        }
                    }
                }
            }

            for (i = 0; i < networkInterfacesSize; i++) {
                if (networkInterfaces[i]) {
                    networkInterfaces[i]->vtbl->nsisupports.Release((nsISupports *) networkInterfaces[i]);
                }
            }

            host->vtbl->nsisupports.Release((nsISupports *) host);
        }
    }

    return numActive;
}

static int vboxNumOfDefinedNetworks(virConnectPtr conn) {
    vboxGlobalData *data = conn->privateData;
    int numActive = 0;

    if (data->vboxObj) {
        IHost *host = NULL;

        data->vboxObj->vtbl->GetHost(data->vboxObj, &host);
        if (host) {
            int i = 0;
            PRUint32 networkInterfacesSize = 0;
            IHostNetworkInterface **networkInterfaces = NULL;

            host->vtbl->GetNetworkInterfaces(host, &networkInterfacesSize, &networkInterfaces);

            for (i = 0; i < networkInterfacesSize; i++) {
                if (networkInterfaces[i]) {
                    PRUint32 interfaceType = 0;

                    networkInterfaces[i]->vtbl->GetInterfaceType(networkInterfaces[i], &interfaceType);
                    if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                        PRUint32 status = HostNetworkInterfaceStatus_Unknown;

                        networkInterfaces[i]->vtbl->GetStatus(networkInterfaces[i], &status);

                        if (status == HostNetworkInterfaceStatus_Down) {
                            numActive++;
                        }
                    }

                    networkInterfaces[i]->vtbl->nsisupports.Release((nsISupports *) networkInterfaces[i]);
                }
            }

            host->vtbl->nsisupports.Release((nsISupports *) host);
        }
    }

    DEBUG("numActive: %d", numActive);
    return numActive;
}

static int vboxListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
    vboxGlobalData *data = conn->privateData;
    int numActive = 0;

    if (data->vboxObj) {
        IHost *host = NULL;

        data->vboxObj->vtbl->GetHost(data->vboxObj, &host);
        if (host) {
            int i = 0;
            PRUint32 networkInterfacesSize = 0;
            IHostNetworkInterface **networkInterfaces = NULL;

            host->vtbl->GetNetworkInterfaces(host, &networkInterfacesSize, &networkInterfaces);

            for (i = 0; (numActive < nnames) && (i < networkInterfacesSize); i++) {
                if (networkInterfaces[i]) {
                    PRUint32 interfaceType = 0;

                    networkInterfaces[i]->vtbl->GetInterfaceType(networkInterfaces[i], &interfaceType);

                    if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                        PRUint32 status = HostNetworkInterfaceStatus_Unknown;

                        networkInterfaces[i]->vtbl->GetStatus(networkInterfaces[i], &status);

                        if (status == HostNetworkInterfaceStatus_Down) {
                            char *nameUtf8       = NULL;
                            PRUnichar *nameUtf16 = NULL;

                            networkInterfaces[i]->vtbl->GetName(networkInterfaces[i], &nameUtf16);
                            data->pFuncs->pfnUtf16ToUtf8(nameUtf16, &nameUtf8);

                            DEBUG("nnames[%d]: %s", numActive, nameUtf8);
                            names[numActive] = strdup(nameUtf8);
                            if (names[numActive] == NULL) {
                                vboxError(conn, VIR_ERR_SYSTEM_ERROR, "%s", "strdup failed");
                            } else {
                                numActive++;
                            }

                            data->pFuncs->pfnUtf8Free(nameUtf8);
                            data->pFuncs->pfnUtf16Free(nameUtf16);
                        }
                    }
                }
            }

            for (i = 0; i < networkInterfacesSize; i++) {
                if (networkInterfaces[i]) {
                    networkInterfaces[i]->vtbl->nsisupports.Release((nsISupports *) networkInterfaces[i]);
                }
            }

            host->vtbl->nsisupports.Release((nsISupports *) host);
        }
    }

    return numActive;
}

static virNetworkPtr vboxNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid) {
    vboxGlobalData *data = conn->privateData;
    virNetworkPtr ret    = NULL;
    vboxIID *iid         = NULL;

#if VBOX_API_VERSION == 2002
    if (VIR_ALLOC(iid) < 0) {
        virReportOOMError(conn);
        goto cleanup;
    }
#endif

    vboxIIDFromUUID(uuid, iid);

    /* TODO: "internal" networks are just strings and
     * thus can't do much with them
     */
    if (data->vboxObj) {
        IHost *host = NULL;

        data->vboxObj->vtbl->GetHost(data->vboxObj, &host);
        if (host) {
            IHostNetworkInterface *networkInterface = NULL;

            host->vtbl->FindHostNetworkInterfaceById(host, iid, &networkInterface);
            if (networkInterface) {
                PRUint32 interfaceType = 0;

                networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);

                if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;

                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
                    data->pFuncs->pfnUtf16ToUtf8(nameUtf16, &nameUtf8);

                    ret = virGetNetwork(conn, nameUtf8, uuid);

                    DEBUG("Network Name: %s", nameUtf8);
#if VBOX_API_VERSION == 2002
                    DEBUGUUID("Network UUID", iid);
#else
                    DEBUGPRUnichar("Network UUID", iid);
#endif

                    data->pFuncs->pfnUtf8Free(nameUtf8);
                    data->pFuncs->pfnUtf16Free(nameUtf16);
                }

                networkInterface->vtbl->nsisupports.Release((nsISupports *) networkInterface);
            }

            host->vtbl->nsisupports.Release((nsISupports *) host);
        }
    }

#if VBOX_API_VERSION == 2002
cleanup:
#endif
    vboxIIDFree(iid);
    return ret;
}

static virNetworkPtr vboxNetworkLookupByName(virConnectPtr conn, const char *name) {
    vboxGlobalData *data = conn->privateData;
    virNetworkPtr ret    = NULL;

    if (data->vboxObj) {
        IHost *host = NULL;

        data->vboxObj->vtbl->GetHost(data->vboxObj, &host);
        if (host) {
            PRUnichar *nameUtf16                    = NULL;
            IHostNetworkInterface *networkInterface = NULL;

            data->pFuncs->pfnUtf8ToUtf16(name, &nameUtf16);

            host->vtbl->FindHostNetworkInterfaceByName(host, nameUtf16, &networkInterface);

            if (networkInterface) {
                PRUint32 interfaceType = 0;

                networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);

                if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                    unsigned char uuid[VIR_UUID_BUFLEN];
                    vboxIID *iid = NULL;

                    networkInterface->vtbl->GetId(networkInterface, &iid);
                    vboxIIDToUUID(uuid, iid);
                    ret = virGetNetwork(conn, name, uuid);
                    DEBUG("Network Name: %s", name);

#if VBOX_API_VERSION == 2002
                    DEBUGUUID("Network UUID", iid);
                    vboxIIDUnalloc(iid);
#else
                    DEBUGPRUnichar("Network UUID", iid);
                    vboxIIDFree(iid);
#endif
                }

                networkInterface->vtbl->nsisupports.Release((nsISupports *) networkInterface);
            }

            data->pFuncs->pfnUtf16Free(nameUtf16);
            host->vtbl->nsisupports.Release((nsISupports *) host);
        }
    }

    return ret;
}

static virNetworkPtr vboxNetworkCreateXML(virConnectPtr conn, const char *xml) {
    vboxGlobalData *data  = conn->privateData;
    virNetworkDefPtr def  = NULL;
    virNetworkPtr ret     = NULL;
    char *networkNameUtf8 = NULL;

    if ((def = virNetworkDefParseString(conn, xml)) == NULL)
        goto cleanup;

    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", def->name) < 0) {
        virReportOOMError(conn);
        goto cleanup;
    }

    if ((data->vboxObj) && (def->forwardType == VIR_NETWORK_FORWARD_NONE)) {
        /* VirtualBox version 2.2.* has only one "hostonly"
         * network called "vboxnet0" for linux
         */
        if (STREQ(def->name, "vboxnet0")) {
            IHost *host = NULL;

            data->vboxObj->vtbl->GetHost(data->vboxObj, &host);
            if (host) {
                PRUnichar *networkInterfaceNameUtf16    = NULL;
                IHostNetworkInterface *networkInterface = NULL;

                data->pFuncs->pfnUtf8ToUtf16(def->name, &networkInterfaceNameUtf16);

                host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);

                if (networkInterface) {
                    PRUint32 interfaceType = 0;

                    networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);

                    if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                        unsigned char uuid[VIR_UUID_BUFLEN];
                        PRUnichar *networkNameUtf16 = NULL;
                        vboxIID *vboxnet0IID        = NULL;

                        networkInterface->vtbl->GetId(networkInterface, &vboxnet0IID);
                        vboxIIDToUUID(uuid, vboxnet0IID);
                        data->pFuncs->pfnUtf8ToUtf16(networkNameUtf8 , &networkNameUtf16);


                        /* Currently support only one dhcp server per network
                         * with contigious address space from start to end
                         */
                        if ((def->nranges >= 1) &&
                            (def->ranges[0].start) &&
                            (def->ranges[0].end)) {
                            IDHCPServer *dhcpServer = NULL;

                            data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                                             networkNameUtf16,
                                                                             &dhcpServer);
                            if (!dhcpServer) {
                                /* create a dhcp server */
                                data->vboxObj->vtbl->CreateDHCPServer(data->vboxObj,
                                                                      networkNameUtf16,
                                                                      &dhcpServer);
                                DEBUG0("couldn't find dhcp server so creating one");
                            }
                            if (dhcpServer) {
                                PRUnichar *ipAddressUtf16     = NULL;
                                PRUnichar *networkMaskUtf16   = NULL;
                                PRUnichar *fromIPAddressUtf16 = NULL;
                                PRUnichar *toIPAddressUtf16   = NULL;
                                PRUnichar *trunkTypeUtf16     = NULL;


                                data->pFuncs->pfnUtf8ToUtf16(def->ipAddress, &ipAddressUtf16);
                                data->pFuncs->pfnUtf8ToUtf16(def->netmask, &networkMaskUtf16);
                                data->pFuncs->pfnUtf8ToUtf16(def->ranges[0].start, &fromIPAddressUtf16);
                                data->pFuncs->pfnUtf8ToUtf16(def->ranges[0].end, &toIPAddressUtf16);
                                data->pFuncs->pfnUtf8ToUtf16("netflt", &trunkTypeUtf16);

                                dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE);

                                dhcpServer->vtbl->SetConfiguration(dhcpServer,
                                                                   ipAddressUtf16,
                                                                   networkMaskUtf16,
                                                                   fromIPAddressUtf16,
                                                                   toIPAddressUtf16);

                                dhcpServer->vtbl->Start(dhcpServer,
                                                        networkNameUtf16,
                                                        networkInterfaceNameUtf16,
                                                        trunkTypeUtf16);

                                data->pFuncs->pfnUtf16Free(ipAddressUtf16);
                                data->pFuncs->pfnUtf16Free(networkMaskUtf16);
                                data->pFuncs->pfnUtf16Free(fromIPAddressUtf16);
                                data->pFuncs->pfnUtf16Free(toIPAddressUtf16);
                                data->pFuncs->pfnUtf16Free(trunkTypeUtf16);
                                dhcpServer->vtbl->nsisupports.Release((nsISupports *) dhcpServer);
                            }
                        }

                        ret = virGetNetwork(conn, def->name, uuid);

#if VBOX_API_VERSION == 2002
                        DEBUGUUID("Real Network UUID", vboxnet0IID);
                        vboxIIDUnalloc(vboxnet0IID);
#else
                        DEBUGPRUnichar("Real Network UUID", vboxnet0IID);
                        vboxIIDFree(vboxnet0IID);
#endif
                        data->pFuncs->pfnUtf16Free(networkNameUtf16);
                    }

                    networkInterface->vtbl->nsisupports.Release((nsISupports *) networkInterface);
                }

                data->pFuncs->pfnUtf16Free(networkInterfaceNameUtf16);
                host->vtbl->nsisupports.Release((nsISupports *) host);
            }
        }
    }

cleanup:
    VIR_FREE(networkNameUtf8);
    virNetworkDefFree(def);
    return ret;
}

static virNetworkPtr vboxNetworkDefineXML(virConnectPtr conn, const char *xml) {
    vboxGlobalData *data  = conn->privateData;
    virNetworkDefPtr def  = NULL;
    virNetworkPtr ret     = NULL;
    char *networkNameUtf8 = NULL;

    /* vboxNetworkDefineXML() is not exactly "network definition"
     * as the network is up and running, only the DHCP server is off,
     * so you can always assign static IP and get the network running.
     */
    if ((def = virNetworkDefParseString(conn, xml)) == NULL)
        goto cleanup;

    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", def->name) < 0) {
        virReportOOMError(conn);
        goto cleanup;
    }

    if ((data->vboxObj) && (def->forwardType == VIR_NETWORK_FORWARD_NONE)) {
        /* VirtualBox version 2.2.* has only one "hostonly"
         * network called "vboxnet0" for linux
         */
        if (STREQ(def->name, "vboxnet0")) {
            IHost *host = NULL;

            data->vboxObj->vtbl->GetHost(data->vboxObj, &host);
            if (host) {
                PRUnichar *networkInterfaceNameUtf16    = NULL;
                IHostNetworkInterface *networkInterface = NULL;

                data->pFuncs->pfnUtf8ToUtf16(def->name, &networkInterfaceNameUtf16);

                host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);

                if (networkInterface) {
                    PRUint32 interfaceType = 0;

                    networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);

                    if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                        unsigned char uuid[VIR_UUID_BUFLEN];
                        PRUnichar *networkNameUtf16 = NULL;
                        vboxIID *vboxnet0IID        = NULL;

                        networkInterface->vtbl->GetId(networkInterface, &vboxnet0IID);
                        vboxIIDToUUID(uuid, vboxnet0IID);
                        data->pFuncs->pfnUtf8ToUtf16(networkNameUtf8 , &networkNameUtf16);

                        /* Currently support only one dhcp server per network
                         * with contigious address space from start to end
                         */
                        if ((def->nranges >= 1) &&
                            (def->ranges[0].start) &&
                            (def->ranges[0].end)) {
                            IDHCPServer *dhcpServer = NULL;

                            data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                                             networkNameUtf16,
                                                                             &dhcpServer);
                            if (!dhcpServer) {
                                /* create a dhcp server */
                                data->vboxObj->vtbl->CreateDHCPServer(data->vboxObj,
                                                                      networkNameUtf16,
                                                                      &dhcpServer);
                                DEBUG0("couldn't find dhcp server so creating one");
                            }
                            if (dhcpServer) {
                                PRUnichar *ipAddressUtf16     = NULL;
                                PRUnichar *networkMaskUtf16   = NULL;
                                PRUnichar *fromIPAddressUtf16 = NULL;
                                PRUnichar *toIPAddressUtf16   = NULL;


                                data->pFuncs->pfnUtf8ToUtf16(def->ipAddress, &ipAddressUtf16);
                                data->pFuncs->pfnUtf8ToUtf16(def->netmask, &networkMaskUtf16);
                                data->pFuncs->pfnUtf8ToUtf16(def->ranges[0].start, &fromIPAddressUtf16);
                                data->pFuncs->pfnUtf8ToUtf16(def->ranges[0].end, &toIPAddressUtf16);

                                dhcpServer->vtbl->SetEnabled(dhcpServer, PR_FALSE);

                                dhcpServer->vtbl->SetConfiguration(dhcpServer,
                                                                   ipAddressUtf16,
                                                                   networkMaskUtf16,
                                                                   fromIPAddressUtf16,
                                                                   toIPAddressUtf16);

                                data->pFuncs->pfnUtf16Free(ipAddressUtf16);
                                data->pFuncs->pfnUtf16Free(networkMaskUtf16);
                                data->pFuncs->pfnUtf16Free(fromIPAddressUtf16);
                                data->pFuncs->pfnUtf16Free(toIPAddressUtf16);
                                dhcpServer->vtbl->nsisupports.Release((nsISupports *) dhcpServer);
                            }
                        }

                        ret = virGetNetwork(conn, def->name, uuid);

#if VBOX_API_VERSION == 2002
                        DEBUGUUID("Real Network UUID", vboxnet0IID);
                        vboxIIDUnalloc(vboxnet0IID);
#else
                        DEBUGPRUnichar("Real Network UUID", vboxnet0IID);
                        vboxIIDFree(vboxnet0IID);
#endif
                        data->pFuncs->pfnUtf16Free(networkNameUtf16);
                    }

                    networkInterface->vtbl->nsisupports.Release((nsISupports *) networkInterface);
                }

                data->pFuncs->pfnUtf16Free(networkInterfaceNameUtf16);
                host->vtbl->nsisupports.Release((nsISupports *) host);
            }
        }
    }

cleanup:
    VIR_FREE(networkNameUtf8);
    virNetworkDefFree(def);
    return ret;
}

static int vboxNetworkUndefine(virNetworkPtr network) {
    vboxGlobalData *data  = network->conn->privateData;
    char *networkNameUtf8 = NULL;
    int ret = -1;

    /* Current limitation of the function for VirtualBox 2.2.* is
     * that you can't delete the default hostonly adaptor namely:
     * vboxnet0 and thus all this functions does is remove the
     * dhcp server configuration, but the network can still be used
     * by giving the machine static IP and also it will still
     * show up in the net-list in virsh
     */

    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0) {
        virReportOOMError(network->conn);
        goto cleanup;
    }

    if (data->vboxObj) {
        IHost *host = NULL;

        data->vboxObj->vtbl->GetHost(data->vboxObj, &host);
        if (host) {
            PRUnichar *networkInterfaceNameUtf16    = NULL;
            IHostNetworkInterface *networkInterface = NULL;

            data->pFuncs->pfnUtf8ToUtf16(network->name, &networkInterfaceNameUtf16);

            host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);

            if (networkInterface) {
                PRUint32 interfaceType = 0;

                networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);

                if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                    PRUnichar *networkNameUtf16 = NULL;
                    IDHCPServer *dhcpServer     = NULL;

                    data->pFuncs->pfnUtf8ToUtf16(networkNameUtf8 , &networkNameUtf16);

                    data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                                     networkNameUtf16,
                                                                     &dhcpServer);
                    if (dhcpServer) {
                        data->vboxObj->vtbl->RemoveDHCPServer(data->vboxObj, dhcpServer);
                        dhcpServer->vtbl->nsisupports.Release((nsISupports *) dhcpServer);
                    }

                    data->pFuncs->pfnUtf16Free(networkNameUtf16);
                }

                networkInterface->vtbl->nsisupports.Release((nsISupports *) networkInterface);
            }

            data->pFuncs->pfnUtf16Free(networkInterfaceNameUtf16);
            host->vtbl->nsisupports.Release((nsISupports *) host);
        }
    }

    ret = 0;

cleanup:
    VIR_FREE(networkNameUtf8);
    return ret;
}

static int vboxNetworkCreate(virNetworkPtr network) {
    vboxGlobalData *data  = network->conn->privateData;
    char *networkNameUtf8 = NULL;
    int ret = -1;

    /* Current limitation of the function for VirtualBox 2.2.* is
     * that the default hostonly network "vboxnet0" is always active
     * and thus all this functions does is start the dhcp server,
     * but the network can still be used without starting the dhcp
     * server by giving the machine static IP
     */

    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0) {
        virReportOOMError(network->conn);
        goto cleanup;
    }

    if (data->vboxObj) {
        IHost *host = NULL;

        data->vboxObj->vtbl->GetHost(data->vboxObj, &host);
        if (host) {
            PRUnichar *networkInterfaceNameUtf16    = NULL;
            IHostNetworkInterface *networkInterface = NULL;

            data->pFuncs->pfnUtf8ToUtf16(network->name, &networkInterfaceNameUtf16);

            host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);

            if (networkInterface) {
                PRUint32 interfaceType = 0;

                networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);

                if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                    PRUnichar *networkNameUtf16 = NULL;
                    IDHCPServer *dhcpServer     = NULL;


                    data->pFuncs->pfnUtf8ToUtf16(networkNameUtf8 , &networkNameUtf16);

                    data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                                     networkNameUtf16,
                                                                     &dhcpServer);
                    if (dhcpServer) {
                        PRUnichar *trunkTypeUtf16 = NULL;

                        dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE);

                        data->pFuncs->pfnUtf8ToUtf16("netflt", &trunkTypeUtf16);

                        dhcpServer->vtbl->Start(dhcpServer,
                                                networkNameUtf16,
                                                networkInterfaceNameUtf16,
                                                trunkTypeUtf16);

                        data->pFuncs->pfnUtf16Free(trunkTypeUtf16);
                        dhcpServer->vtbl->nsisupports.Release((nsISupports *) dhcpServer);
                    }

                    data->pFuncs->pfnUtf16Free(networkNameUtf16);
                }

                networkInterface->vtbl->nsisupports.Release((nsISupports *) networkInterface);
            }

            data->pFuncs->pfnUtf16Free(networkInterfaceNameUtf16);
            host->vtbl->nsisupports.Release((nsISupports *) host);
        }
    }

    ret = 0;

cleanup:
    VIR_FREE(networkNameUtf8);
    return ret;
}

static int vboxNetworkDestroy(virNetworkPtr network) {
    vboxGlobalData *data  = network->conn->privateData;
    char *networkNameUtf8 = NULL;
    int ret = -1;

    /* Current limitation of the function for VirtualBox 2.2.* is
     * that the default hostonly network "vboxnet0" is always active
     * and thus all this functions does is stop the dhcp server,
     * but the network can still be used without the dhcp server
     * by giving the machine static IP
     */

    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0) {
        virReportOOMError(network->conn);
        goto cleanup;
    }

    if (data->vboxObj) {
        IHost *host = NULL;

        data->vboxObj->vtbl->GetHost(data->vboxObj, &host);
        if (host) {
            PRUnichar *networkInterfaceNameUtf16    = NULL;
            IHostNetworkInterface *networkInterface = NULL;

            data->pFuncs->pfnUtf8ToUtf16(network->name, &networkInterfaceNameUtf16);

            host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);

            if (networkInterface) {
                PRUint32 interfaceType = 0;

                networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);

                if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                    PRUnichar *networkNameUtf16 = NULL;
                    IDHCPServer *dhcpServer     = NULL;


                    data->pFuncs->pfnUtf8ToUtf16(networkNameUtf8 , &networkNameUtf16);

                    data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                                     networkNameUtf16,
                                                                     &dhcpServer);
                    if (dhcpServer) {

                        dhcpServer->vtbl->SetEnabled(dhcpServer, PR_FALSE);

                        dhcpServer->vtbl->Stop(dhcpServer);

                        dhcpServer->vtbl->nsisupports.Release((nsISupports *) dhcpServer);
                    }

                    data->pFuncs->pfnUtf16Free(networkNameUtf16);
                }

                networkInterface->vtbl->nsisupports.Release((nsISupports *) networkInterface);
            }

            data->pFuncs->pfnUtf16Free(networkInterfaceNameUtf16);
            host->vtbl->nsisupports.Release((nsISupports *) host);
        }
    }

    ret = 0;

cleanup:
    VIR_FREE(networkNameUtf8);
    return ret;
}

static char *vboxNetworkDumpXML(virNetworkPtr network, int flags ATTRIBUTE_UNUSED) {
    vboxGlobalData *data  = network->conn->privateData;
    virNetworkDefPtr def  = NULL;
    char *ret             = NULL;
    char *networkNameUtf8 = NULL;

    if (VIR_ALLOC(def) < 0) {
        virReportOOMError(network->conn);
        goto cleanup;
    }

    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0) {
        virReportOOMError(network->conn);
        goto cleanup;
    }

    if (data->vboxObj) {
        IHost *host = NULL;

        data->vboxObj->vtbl->GetHost(data->vboxObj, &host);
        if (host) {
            PRUnichar *networkInterfaceNameUtf16    = NULL;
            IHostNetworkInterface *networkInterface = NULL;

            data->pFuncs->pfnUtf8ToUtf16(network->name, &networkInterfaceNameUtf16);

            host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);

            if (networkInterface) {
                PRUint32 interfaceType = 0;

                networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);

                if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                    def->name = strdup(network->name);
                    if (def->name != NULL) {
                        PRUnichar *networkNameUtf16 = NULL;
                        IDHCPServer *dhcpServer     = NULL;
                        vboxIID *vboxnet0IID        = NULL;

                        networkInterface->vtbl->GetId(networkInterface, &vboxnet0IID);
                        vboxIIDToUUID(def->uuid, vboxnet0IID);

                        data->pFuncs->pfnUtf8ToUtf16(networkNameUtf8 , &networkNameUtf16);

                        def->forwardType = VIR_NETWORK_FORWARD_NONE;

                        data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                                         networkNameUtf16,
                                                                         &dhcpServer);
                        if (dhcpServer) {
                            def->nranges = 1;
                            if (VIR_ALLOC_N(def->ranges, def->nranges) >=0 ) {
                                PRUnichar *ipAddressUtf16     = NULL;
                                PRUnichar *networkMaskUtf16   = NULL;
                                PRUnichar *fromIPAddressUtf16 = NULL;
                                PRUnichar *toIPAddressUtf16   = NULL;

                                dhcpServer->vtbl->GetIPAddress(dhcpServer, &ipAddressUtf16);
                                dhcpServer->vtbl->GetNetworkMask(dhcpServer, &networkMaskUtf16);
                                dhcpServer->vtbl->GetLowerIP(dhcpServer, &fromIPAddressUtf16);
                                dhcpServer->vtbl->GetUpperIP(dhcpServer, &toIPAddressUtf16);
                                /* Currently virtualbox supports only one dhcp server per network
                                 * with contigious address space from start to end
                                 */
                                data->pFuncs->pfnUtf16ToUtf8(ipAddressUtf16, &def->ipAddress);
                                data->pFuncs->pfnUtf16ToUtf8(networkMaskUtf16, &def->netmask);
                                data->pFuncs->pfnUtf16ToUtf8(fromIPAddressUtf16, &def->ranges[0].start);
                                data->pFuncs->pfnUtf16ToUtf8(toIPAddressUtf16, &def->ranges[0].end);

                                data->pFuncs->pfnUtf16Free(ipAddressUtf16);
                                data->pFuncs->pfnUtf16Free(networkMaskUtf16);
                                data->pFuncs->pfnUtf16Free(fromIPAddressUtf16);
                                data->pFuncs->pfnUtf16Free(toIPAddressUtf16);
                            } else {
                                def->nranges = 0;
                            }

                            def->nhosts = 1;
                            if (VIR_ALLOC_N(def->hosts, def->nhosts) >=0 ) {
                                def->hosts[0].name = strdup(network->name);
                                if (def->hosts[0].name == NULL) {
                                    VIR_FREE(def->hosts);
                                    def->nhosts = 0;
                                    vboxError(network->conn,
                                              VIR_ERR_SYSTEM_ERROR,
                                              "%s", "strdup failed");
                                } else {
                                    PRUnichar *macAddressUtf16 = NULL;
                                    PRUnichar *ipAddressUtf16  = NULL;

                                    networkInterface->vtbl->GetHardwareAddress(networkInterface, &macAddressUtf16);
                                    networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

                                    data->pFuncs->pfnUtf16ToUtf8(macAddressUtf16, &def->hosts[0].mac);
                                    data->pFuncs->pfnUtf16ToUtf8(ipAddressUtf16, &def->hosts[0].ip);

                                    data->pFuncs->pfnUtf16Free(macAddressUtf16);
                                    data->pFuncs->pfnUtf16Free(ipAddressUtf16);
                                }
                            } else {
                                def->nhosts = 0;
                            }

                            dhcpServer->vtbl->nsisupports.Release((nsISupports *) dhcpServer);
                        } else {
                            PRUnichar *networkMaskUtf16 = NULL;
                            PRUnichar *ipAddressUtf16   = NULL;

                            networkInterface->vtbl->GetNetworkMask(networkInterface, &networkMaskUtf16);
                            networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

                            data->pFuncs->pfnUtf16ToUtf8(networkMaskUtf16, &def->netmask);
                            data->pFuncs->pfnUtf16ToUtf8(ipAddressUtf16, &def->ipAddress);

                            data->pFuncs->pfnUtf16Free(networkMaskUtf16);
                            data->pFuncs->pfnUtf16Free(ipAddressUtf16);
                        }

#if VBOX_API_VERSION == 2002
                        DEBUGUUID("Network UUID", vboxnet0IID);
                        vboxIIDUnalloc(vboxnet0IID);
#else
                        DEBUGPRUnichar("Network UUID", vboxnet0IID);
                        vboxIIDFree(vboxnet0IID);
#endif
                        data->pFuncs->pfnUtf16Free(networkNameUtf16);
                    } else {
                        vboxError(network->conn, VIR_ERR_SYSTEM_ERROR,
                                   "%s", "strdup failed");
                    }
                }

                networkInterface->vtbl->nsisupports.Release((nsISupports *) networkInterface);
            }

            data->pFuncs->pfnUtf16Free(networkInterfaceNameUtf16);
            host->vtbl->nsisupports.Release((nsISupports *) host);
        }
    }

    ret = virNetworkDefFormat(network->conn, def);

cleanup:
    VIR_FREE(networkNameUtf8);
    return ret;
}


/**
 * Function Tables
 */

virDriver NAME(Driver) = {
    VIR_DRV_VBOX,
    "VBOX",
    vboxOpen, /* open */
    vboxClose, /* close */
    NULL, /* supports_feature */
    NULL, /* type */
    vboxGetVersion, /* version */
    vboxGetHostname, /* getHostname */
    vboxGetMaxVcpus, /* getMaxVcpus */
    nodeGetInfo, /* nodeGetInfo */
    vboxGetCapabilities, /* getCapabilities */
    vboxListDomains, /* listDomains */
    vboxNumOfDomains, /* numOfDomains */
    vboxDomainCreateXML, /* domainCreateXML */
    vboxDomainLookupByID, /* domainLookupByID */
    vboxDomainLookupByUUID, /* domainLookupByUUID */
    vboxDomainLookupByName, /* domainLookupByName */
    vboxDomainSuspend, /* domainSuspend */
    vboxDomainResume, /* domainResume */
    vboxDomainShutdown, /* domainShutdown */
    vboxDomainReboot, /* domainReboot */
    vboxDomainDestroy, /* domainDestroy */
    vboxDomainGetOSType, /* domainGetOSType */
    NULL, /* domainGetMaxMemory */
    NULL, /* domainSetMaxMemory */
    vboxDomainSetMemory, /* domainSetMemory */
    vboxDomainGetInfo, /* domainGetInfo */
    vboxDomainSave, /* domainSave */
    NULL, /* domainRestore */
    NULL, /* domainCoreDump */
    NULL, /* domainSetVcpus */
    NULL, /* domainPinVcpu */
    NULL, /* domainGetVcpus */
    NULL, /* domainGetMaxVcpus */
    NULL, /* domainGetSecurityLabel */
    NULL, /* nodeGetSecurityModel */
    vboxDomainDumpXML, /* domainDumpXML */
    NULL, /* domainXmlFromNative */
    NULL, /* domainXmlToNative */
    vboxListDefinedDomains, /* listDefinedDomains */
    vboxNumOfDefinedDomains, /* numOfDefinedDomains */
    vboxDomainCreate, /* domainCreate */
    vboxDomainDefineXML, /* domainDefineXML */
    vboxDomainUndefine, /* domainUndefine */
    vboxDomainAttachDevice, /* domainAttachDevice */
    vboxDomainDetachDevice, /* domainDetachDevice */
    NULL, /* domainGetAutostart */
    NULL, /* domainSetAutostart */
    NULL, /* domainGetSchedulerType */
    NULL, /* domainGetSchedulerParameters */
    NULL, /* domainSetSchedulerParameters */
    NULL, /* domainMigratePrepare */
    NULL, /* domainMigratePerform */
    NULL, /* domainMigrateFinish */
    NULL, /* domainBlockStats */
    NULL, /* domainInterfaceStats */
    NULL, /* domainBlockPeek */
    NULL, /* domainMemoryPeek */
    nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
    nodeGetFreeMemory,  /* getFreeMemory */
#if VBOX_API_VERSION == 2002
    NULL, /* domainEventRegister */
    NULL, /* domainEventDeregister */
#else
    vboxDomainEventRegister, /* domainEventRegister */
    vboxDomainEventDeregister, /* domainEventDeregister */
#endif
    NULL, /* domainMigratePrepare2 */
    NULL, /* domainMigrateFinish2 */
    NULL, /* nodeDeviceDettach */
    NULL, /* nodeDeviceReAttach */
    NULL, /* nodeDeviceReset */

};

virNetworkDriver NAME(NetworkDriver) = {
    "VBOX",
    .open                   = vboxNetworkOpen,
    .close                  = vboxNetworkClose,
    .numOfNetworks          = vboxNumOfNetworks,
    .listNetworks           = vboxListNetworks,
    .numOfDefinedNetworks   = vboxNumOfDefinedNetworks,
    .listDefinedNetworks    = vboxListDefinedNetworks,
    .networkLookupByUUID    = vboxNetworkLookupByUUID,
    .networkLookupByName    = vboxNetworkLookupByName,
    .networkCreateXML       = vboxNetworkCreateXML,
    .networkDefineXML       = vboxNetworkDefineXML,
    .networkUndefine        = vboxNetworkUndefine,
    .networkCreate          = vboxNetworkCreate,
    .networkDestroy         = vboxNetworkDestroy,
    .networkDumpXML         = vboxNetworkDumpXML,
    .networkGetBridgeName   = NULL,
    .networkGetAutostart    = NULL,
    .networkSetAutostart    = NULL
};
