/**
 * List extension packs.
 *
 * @returns See produceList.
 * @param   pVirtualBox         Reference to the IVirtualBox smart pointer.
 */
static HRESULT listExtensionPacks(const ComPtr<IVirtualBox> &pVirtualBox)
{
    ComObjPtr<IExtPackManager> ptrExtPackMgr;
    CHECK_ERROR2_RET(pVirtualBox, COMGETTER(ExtensionPackManager)(ptrExtPackMgr.asOutParam()), hrcCheck);

    SafeIfaceArray<IExtPack> extPacks;
    CHECK_ERROR2_RET(ptrExtPackMgr, COMGETTER(InstalledExtPacks)(ComSafeArrayAsOutParam(extPacks)), hrcCheck);
    RTPrintf("Extension Packs: %u\n", extPacks.size());

    HRESULT hrc = S_OK;
    for (size_t i = 0; i < extPacks.size(); i++)
    {
        /* Read all the properties. */
        Bstr bstrName;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(Name)(bstrName.asOutParam()),          hrc = hrcCheck; bstrName.setNull());
        Bstr bstrDesc;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(Description)(bstrDesc.asOutParam()),   hrc = hrcCheck; bstrDesc.setNull());
        Bstr bstrVersion;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(Version)(bstrVersion.asOutParam()),    hrc = hrcCheck; bstrVersion.setNull());
        ULONG uRevision;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(Revision)(&uRevision),                 hrc = hrcCheck; uRevision = 0);
        Bstr bstrEdition;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(Edition)(bstrEdition.asOutParam()),    hrc = hrcCheck; bstrEdition.setNull());
        Bstr bstrVrdeModule;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(VRDEModule)(bstrVrdeModule.asOutParam()),hrc=hrcCheck; bstrVrdeModule.setNull());
        BOOL fUsable;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(Usable)(&fUsable),                     hrc = hrcCheck; fUsable = FALSE);
        Bstr bstrWhy;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(WhyUnusable)(bstrWhy.asOutParam()),    hrc = hrcCheck; bstrWhy.setNull());

        /* Display them. */
        if (i)
            RTPrintf("\n");
        RTPrintf("Pack no.%2zu:   %ls\n"
                 "Version:      %ls\n"
                 "Revision:     %u\n"
                 "Edition:      %ls\n"
                 "Description:  %ls\n"
                 "VRDE Module:  %ls\n"
                 "Usable:       %RTbool\n"
                 "Why unusable: %ls\n",
                 i, bstrName.raw(),
                 bstrVersion.raw(),
                 uRevision,
                 bstrEdition.raw(),
                 bstrDesc.raw(),
                 bstrVrdeModule.raw(),
                 fUsable != FALSE,
                 bstrWhy.raw());

        /* Query plugins and display them. */
    }
    return hrc;
}
int handleExtPack(HandlerArg *a)
{
    if (a->argc < 1)
        return errorSyntax(USAGE_EXTPACK, "Incorrect number of parameters");

    ComObjPtr<IExtPackManager> ptrExtPackMgr;
    CHECK_ERROR2_RET(a->virtualBox, COMGETTER(ExtensionPackManager)(ptrExtPackMgr.asOutParam()), RTEXITCODE_FAILURE);

    RTGETOPTSTATE   GetState;
    RTGETOPTUNION   ValueUnion;
    int             ch;
    HRESULT         hrc = S_OK;

    if (!strcmp(a->argv[0], "install"))
    {
        const char *pszName  = NULL;
        bool        fReplace = false;

        static const RTGETOPTDEF s_aInstallOptions[] =
        {
            { "--replace",  'r', RTGETOPT_REQ_NOTHING },
        };

        RTGetOptInit(&GetState, a->argc, a->argv, s_aInstallOptions, RT_ELEMENTS(s_aInstallOptions), 1, 0 /*fFlags*/);
        while ((ch = RTGetOpt(&GetState, &ValueUnion)))
        {
            switch (ch)
            {
                case 'r':
                    fReplace = true;
                    break;

                case VINF_GETOPT_NOT_OPTION:
                    if (pszName)
                        return errorSyntax(USAGE_EXTPACK, "Too many extension pack names given to \"extpack uninstall\"");
                    pszName = ValueUnion.psz;
                    break;

                default:
                    return errorGetOpt(USAGE_EXTPACK, ch, &ValueUnion);
            }
        }
        if (!pszName)
            return errorSyntax(USAGE_EXTPACK, "No extension pack name was given to \"extpack install\"");

        char szPath[RTPATH_MAX];
        int vrc = RTPathAbs(pszName, szPath, sizeof(szPath));
        if (RT_FAILURE(vrc))
            return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs(%s,,) failed with rc=%Rrc", pszName, vrc);

        Bstr bstrTarball(szPath);
        Bstr bstrName;
        ComPtr<IExtPackFile> ptrExtPackFile;
        CHECK_ERROR2_RET(ptrExtPackMgr, OpenExtPackFile(bstrTarball.raw(), ptrExtPackFile.asOutParam()), RTEXITCODE_FAILURE);
        CHECK_ERROR2_RET(ptrExtPackFile, COMGETTER(Name)(bstrName.asOutParam()), RTEXITCODE_FAILURE);
        ComPtr<IProgress> ptrProgress;
        CHECK_ERROR2_RET(ptrExtPackFile, Install(fReplace, NULL, ptrProgress.asOutParam()), RTEXITCODE_FAILURE);
        hrc = showProgress(ptrProgress);
        CHECK_PROGRESS_ERROR_RET(ptrProgress, ("Failed to install \"%s\"", szPath), RTEXITCODE_FAILURE);

        RTPrintf("Successfully installed \"%ls\".\n", bstrName.raw());
    }
    else if (!strcmp(a->argv[0], "uninstall"))
    {
        const char *pszName = NULL;
        bool        fForced = false;

        static const RTGETOPTDEF s_aUninstallOptions[] =
        {
            { "--force",  'f', RTGETOPT_REQ_NOTHING },
        };

        RTGetOptInit(&GetState, a->argc, a->argv, s_aUninstallOptions, RT_ELEMENTS(s_aUninstallOptions), 1, 0);
        while ((ch = RTGetOpt(&GetState, &ValueUnion)))
        {
            switch (ch)
            {
                case 'f':
                    fForced = true;
                    break;

                case VINF_GETOPT_NOT_OPTION:
                    if (pszName)
                        return errorSyntax(USAGE_EXTPACK, "Too many extension pack names given to \"extpack uninstall\"");
                    pszName = ValueUnion.psz;
                    break;

                default:
                    return errorGetOpt(USAGE_EXTPACK, ch, &ValueUnion);
            }
        }
        if (!pszName)
            return errorSyntax(USAGE_EXTPACK, "No extension pack name was given to \"extpack uninstall\"");

        Bstr bstrName(pszName);
        ComPtr<IProgress> ptrProgress;
        CHECK_ERROR2_RET(ptrExtPackMgr, Uninstall(bstrName.raw(), fForced, NULL, ptrProgress.asOutParam()), RTEXITCODE_FAILURE);
        hrc = showProgress(ptrProgress);
        CHECK_PROGRESS_ERROR_RET(ptrProgress, ("Failed to uninstall \"%s\"", pszName), RTEXITCODE_FAILURE);

        RTPrintf("Successfully uninstalled \"%s\".\n", pszName);
    }
    else if (!strcmp(a->argv[0], "cleanup"))
    {
        if (a->argc > 1)
            return errorSyntax(USAGE_EXTPACK, "Too many parameters given to \"extpack cleanup\"");

        CHECK_ERROR2_RET(ptrExtPackMgr, Cleanup(), RTEXITCODE_FAILURE);
        RTPrintf("Successfully performed extension pack cleanup\n");
    }
    else
        return errorSyntax(USAGE_EXTPACK, "Unknown command \"%s\"", a->argv[0]);

    return RTEXITCODE_SUCCESS;
}