/**
 * Writes the properties that won't change while the service is running.
 *
 * Errors are ignored.
 */
static void vboxserviceVMInfoWriteFixedProperties(void)
{
    /*
     * First get OS information that won't change.
     */
    char szInfo[256];
    int rc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szInfo, sizeof(szInfo));
    VBoxServiceWritePropF(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/Product",
                          "%s", RT_FAILURE(rc) ? "" : szInfo);

    rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szInfo, sizeof(szInfo));
    VBoxServiceWritePropF(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/Release",
                          "%s", RT_FAILURE(rc) ? "" : szInfo);

    rc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szInfo, sizeof(szInfo));
    VBoxServiceWritePropF(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/Version",
                          "%s", RT_FAILURE(rc) ? "" : szInfo);

    rc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szInfo, sizeof(szInfo));
    VBoxServiceWritePropF(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/ServicePack",
                          "%s", RT_FAILURE(rc) ? "" : szInfo);

    /*
     * Retrieve version information about Guest Additions and installed files (components).
     */
    char *pszAddVer;
    char *pszAddVerExt;
    char *pszAddRev;
    rc = VbglR3GetAdditionsVersion(&pszAddVer, &pszAddVerExt, &pszAddRev);
    VBoxServiceWritePropF(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestAdd/Version",
                          "%s", RT_FAILURE(rc) ? "" : pszAddVer);
    VBoxServiceWritePropF(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestAdd/VersionExt",
                          "%s", RT_FAILURE(rc) ? "" : pszAddVerExt);
    VBoxServiceWritePropF(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestAdd/Revision",
                          "%s", RT_FAILURE(rc) ? "" : pszAddRev);
    if (RT_SUCCESS(rc))
    {
        RTStrFree(pszAddVer);
        RTStrFree(pszAddVerExt);
        RTStrFree(pszAddRev);
    }

#ifdef RT_OS_WINDOWS
    /*
     * Do windows specific properties.
     */
    char *pszInstDir;
    rc = VbglR3GetAdditionsInstallationPath(&pszInstDir);
    VBoxServiceWritePropF(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestAdd/InstallDir",
                          "%s", RT_FAILURE(rc) ? "" :  pszInstDir);
    if (RT_SUCCESS(rc))
        RTStrFree(pszInstDir);

    VBoxServiceWinGetComponentVersions(g_uVMInfoGuestPropSvcClientID);
#endif
}
/**
 * Checks for a Guest Additions update by comparing the installed version on the
 * guest and the reported host version.
 *
 * @returns VBox status code
 *
 * @param   u32ClientId         The client id returned by
 *                              VbglR3InfoSvcConnect().
 * @param   pfUpdate            Receives pointer to boolean flag indicating
 *                              whether an update was found or not.
 * @param   ppszHostVersion     Receives pointer of allocated version string.
 *                              The returned pointer must be freed using
 *                              VbglR3GuestPropReadValueFree().  Always set to
 *                              NULL.
 * @param   ppszGuestVersion    Receives pointer of allocated revision string.
 *                              The returned pointer must be freed using
 *                              VbglR3GuestPropReadValueFree().  Always set to
 *                              NULL.
 */
VBGLR3DECL(int) VbglR3HostVersionCheckForUpdate(uint32_t u32ClientId, bool *pfUpdate, char **ppszHostVersion, char **ppszGuestVersion)
{
    Assert(u32ClientId > 0);
    AssertPtr(pfUpdate);
    AssertPtr(ppszHostVersion);
    AssertPtr(ppszGuestVersion);

    *ppszHostVersion = NULL;
    *ppszGuestVersion = NULL;

    /* We assume we have an update initially.
       Every block down below is allowed to veto */
    *pfUpdate = true;

    /* Do we need to do all this stuff? */
    char *pszCheckHostVersion;
    int rc = VbglR3GuestPropReadValueAlloc(u32ClientId, "/VirtualBox/GuestAdd/CheckHostVersion", &pszCheckHostVersion);
    if (RT_FAILURE(rc))
    {
        if (rc == VERR_NOT_FOUND)
            rc = VINF_SUCCESS; /* If we don't find the value above we do the check by default */
        else
            LogFlow(("Could not read check host version flag! rc = %Rrc\n", rc));
    }
    else
    {
        /* Only don't do the check if we have a valid "0" in it */
        if (!strcmp(pszCheckHostVersion, "0"))
        {
            LogRel(("No host version update check performed (disabled).\n"));
            *pfUpdate = false;
        }
        VbglR3GuestPropReadValueFree(pszCheckHostVersion);
    }

    /* Collect all needed information */
    /* Make sure we only notify the user once by comparing the host version with
     * the last checked host version (if any) */
    if (RT_SUCCESS(rc) && *pfUpdate)
    {
        /* Look up host version */
        rc = VbglR3GuestPropReadValueAlloc(u32ClientId, "/VirtualBox/HostInfo/VBoxVer", ppszHostVersion);
        if (RT_FAILURE(rc))
        {
            LogFlow(("Could not read VBox host version! rc = %Rrc\n", rc));
        }
        else
        {
            LogFlow(("Host version: %s\n", *ppszHostVersion));

            /* Get last checked host version */
            char *pszLastCheckedHostVersion;
            rc = VbglR3HostVersionLastCheckedLoad(u32ClientId, &pszLastCheckedHostVersion);
            if (RT_SUCCESS(rc))
            {
                LogFlow(("Last checked host version: %s\n", pszLastCheckedHostVersion));
                if (strcmp(*ppszHostVersion, pszLastCheckedHostVersion) == 0)
                    *pfUpdate = false; /* We already notified this version, skip */
                VbglR3GuestPropReadValueFree(pszLastCheckedHostVersion);
            }
            else if (rc == VERR_NOT_FOUND) /* Never wrote a last checked host version before */
            {
                LogFlow(("Never checked a host version before.\n"));
                rc = VINF_SUCCESS;
            }
        }

        /* Look up guest version */
        if (RT_SUCCESS(rc))
        {
            rc = VbglR3GetAdditionsVersion(ppszGuestVersion, NULL /* Extended version not needed here */,
                                           NULL /* Revision not needed here */);
            if (RT_FAILURE(rc))
                LogFlow(("Could not read VBox guest version! rc = %Rrc\n", rc));
        }
    }

    /* Do the actual version comparison (if needed, see block(s) above) */
    if (RT_SUCCESS(rc) && *pfUpdate)
    {
        if (RTStrVersionCompare(*ppszHostVersion, *ppszGuestVersion) > 0) /* Is host version greater than guest add version? */
        {
            /* Yay, we have an update! */
            LogRel(("Guest Additions update found! Please upgrade this machine to the latest Guest Additions.\n"));
        }
        else
        {
            /* How sad ... */
            *pfUpdate = false;
        }
    }

    /* Cleanup on failure */
    if (RT_FAILURE(rc))
    {
        if (*ppszHostVersion)
        {
            VbglR3GuestPropReadValueFree(*ppszHostVersion);
            *ppszHostVersion = NULL;
        }
        if (*ppszGuestVersion)
        {
            VbglR3GuestPropReadValueFree(*ppszGuestVersion);
            *ppszGuestVersion = NULL;
        }
    }
    return rc;
}