/**
 * Checks whether a shared folder share exists or not.
 *
 * @returns True if shared folder exists, false if not.
 * @param   u32ClientId     The client id returned by VbglR3InfoSvcConnect().
 * @param   pszShareName    Shared folder name to check.
 */
VBGLR3DECL(bool) VbglR3SharedFolderExists(uint32_t u32ClientId, const char *pszShareName)
{
    AssertPtr(pszShareName);

    uint32_t cMappings;
    VBGLR3SHAREDFOLDERMAPPING *paMappings;

    /** @todo Use some caching here? */
    bool fFound = false;
    int rc = VbglR3SharedFolderGetMappings(u32ClientId, true /* Only process auto-mounted folders */,
                                           &paMappings, &cMappings);
    if (RT_SUCCESS(rc))
    {
        for (uint32_t i = 0; i < cMappings && !fFound; i++)
        {
            char *pszName = NULL;
            rc = VbglR3SharedFolderGetName(u32ClientId, paMappings[i].u32Root, &pszName);
            if (   RT_SUCCESS(rc)
                && *pszName)
            {
                if (RTStrICmp(pszName, pszShareName) == 0)
                    fFound = true;
                RTStrFree(pszName);
            }
        }
        VbglR3SharedFolderFreeMappings(paMappings);
    }
    return fFound;
}
int VBoxSharedFoldersAutoMount(void)
{
    uint32_t u32ClientId;
    int rc = VbglR3SharedFolderConnect(&u32ClientId);
    if (RT_SUCCESS(rc))
    {
        uint32_t cMappings;
        VBGLR3SHAREDFOLDERMAPPING *paMappings;

        rc = VbglR3SharedFolderGetMappings(u32ClientId, true /* Only process auto-mounted folders */,
                                           &paMappings, &cMappings);
        if (RT_SUCCESS(rc))
        {
#if 0
            /* Check for a fixed/virtual auto-mount share. */
            if (VbglR3SharedFolderExists(u32ClientId, "vbsfAutoMount"))
            {
                LogFlowFunc(("Hosts supports auto-mount root\n"));
            }
            else
            {
#endif
                LogFlowFunc(("Got %u shared folder mappings\n", cMappings));
                for (uint32_t i = 0; i < cMappings && RT_SUCCESS(rc); i++)
                {
                    char *pszName = NULL;
                    rc = VbglR3SharedFolderGetName(u32ClientId, paMappings[i].u32Root, &pszName);
                    if (   RT_SUCCESS(rc)
                        && *pszName)
                    {
                        LogFlowFunc(("Connecting share %u (%s) ...\n", i+1, pszName));

                        char *pszShareName;
                        if (RTStrAPrintf(&pszShareName, "\\\\vboxsrv\\%s", pszName) >= 0)
                        {
                            char chDrive = 'D'; /* Start probing whether drive D: is free to use. */
                            do
                            {
                                char szCurDrive[3];
                                RTStrPrintf(szCurDrive, sizeof(szCurDrive), "%c:", chDrive++);

                                NETRESOURCE resource;
                                RT_ZERO(resource);
                                resource.dwType = RESOURCETYPE_ANY;
                                resource.lpLocalName = TEXT(szCurDrive);
                                resource.lpRemoteName = TEXT(pszShareName);
                                /* Go straight to our network provider in order to get maximum lookup speed. */
                                resource.lpProvider = TEXT("VirtualBox Shared Folders");

                                /** @todo Figure out how to map the drives in a block (F,G,H, ...).
                                          Save the mapping for later use. */
                                DWORD dwErr = WNetAddConnection2A(&resource, NULL, NULL, 0);
                                if (dwErr == NO_ERROR)
                                {
                                    LogRel(("Shared folder \"%s\" was mounted to drive \"%s\"\n", pszName, szCurDrive));
                                    break;
                                }
                                else
                                {
                                    LogRel(("Mounting \"%s\" to \"%s\" resulted in dwErr = %ld\n", pszName, szCurDrive, dwErr));

                                    switch (dwErr)
                                    {
                                        /*
                                         * The local device specified by the lpLocalName member is already
                                         * connected to a network resource.  Try next drive ...
                                         */
                                        case ERROR_ALREADY_ASSIGNED:
                                            break;

                                        default:
                                            LogRel(("Error while mounting shared folder \"%s\" to \"%s\", error = %ld\n",
                                                    pszName, szCurDrive, dwErr));
                                            break;
                                    }
                                }
                            } while (chDrive <= 'Z');

                            if (chDrive > 'Z')
                            {
                                LogRel(("No free driver letter found to assign shared folder \"%s\", aborting\n", pszName));
                                break;
                            }

                            RTStrFree(pszShareName);
                        }
                        else
                            rc = VERR_NO_STR_MEMORY;
                        RTStrFree(pszName);
                    }
                    else
                        LogFlowFunc(("Error while getting the shared folder name for root node = %u, rc = %Rrc\n",
                             paMappings[i].u32Root, rc));
                }
#if 0
            }
#endif
            VbglR3SharedFolderFreeMappings(paMappings);
        }
        else
            LogFlowFunc(("Error while getting the shared folder mappings, rc = %Rrc\n", rc));
        VbglR3SharedFolderDisconnect(u32ClientId);
    }
    else
    {
        LogFlowFunc(("Failed to connect to the shared folder service, error %Rrc\n", rc));
        /* return success, otherwise VBoxTray will not start! */
        rc = VINF_SUCCESS;
    }
    return rc;
}
/** @copydoc VBOXSERVICE::pfnWorker */
DECLCALLBACK(int) VBoxServiceAutoMountWorker(bool volatile *pfShutdown)
{
    /*
     * Tell the control thread that it can continue
     * spawning services.
     */
    RTThreadUserSignal(RTThreadSelf());

    uint32_t cMappings;
    PVBGLR3SHAREDFOLDERMAPPING paMappings;
    int rc = VbglR3SharedFolderGetMappings(g_SharedFoldersSvcClientID, true /* Only process auto-mounted folders */,
                                           &paMappings, &cMappings);
    if (   RT_SUCCESS(rc)
        && cMappings)
    {
        char *pszMountDir;
        rc = VbglR3SharedFolderGetMountDir(&pszMountDir);
        if (rc == VERR_NOT_FOUND)
            rc = RTStrDupEx(&pszMountDir, VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR);
        if (RT_SUCCESS(rc))
        {
            VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder mount dir set to \"%s\"\n", pszMountDir);

            char *pszSharePrefix;
            rc = VbglR3SharedFolderGetMountPrefix(&pszSharePrefix);
            if (RT_SUCCESS(rc))
            {
                VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder mount prefix set to \"%s\"\n", pszSharePrefix);
#ifdef USE_VIRTUAL_SHARES
                /* Check for a fixed/virtual auto-mount share. */
                if (VbglR3SharedFolderExists(g_SharedFoldersSvcClientID, "vbsfAutoMount"))
                {
                    VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Host supports auto-mount root\n");
                }
                else
                {
#endif
                    VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Got %u shared folder mappings\n", cMappings);
                    rc = VBoxServiceAutoMountProcessMappings(paMappings, cMappings, pszMountDir, pszSharePrefix, g_SharedFoldersSvcClientID);
#ifdef USE_VIRTUAL_SHARES
                }
#endif
                RTStrFree(pszSharePrefix);
            } /* Mount share prefix. */
            else
                VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder mount prefix, rc = %Rrc\n", rc);
            RTStrFree(pszMountDir);
        }
        else
            VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder directory, rc = %Rrc\n", rc);
        VbglR3SharedFolderFreeMappings(paMappings);
    }
    else if (RT_FAILURE(rc))
        VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder mappings, rc = %Rrc\n", rc);
    else
        VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: No shared folder mappings found\n");

    /*
     * Because this thread is a one-timer at the moment we don't want to break/change
     * the semantics of the main thread's start/stop sub-threads handling.
     *
     * This thread exits so fast while doing its own startup in VBoxServiceStartServices()
     * that this->fShutdown flag is set to true in VBoxServiceThread() before we have the
     * chance to check for a service failure in VBoxServiceStartServices() to indicate
     * a VBoxService startup error.
     *
     * Therefore *no* service threads are allowed to quit themselves and need to wait
     * for the pfShutdown flag to be set by the main thread.
     */
    for (;;)
    {
        /* Do we need to shutdown? */
        if (*pfShutdown)
            break;

        /* Let's sleep for a bit and let others run ... */
        RTThreadSleep(500);
    }

    RTSemEventMultiDestroy(g_AutoMountEvent);
    g_AutoMountEvent = NIL_RTSEMEVENTMULTI;

    VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Finished with rc=%Rrc\n", rc);
    return VINF_SUCCESS;
}
int VBoxSharedFoldersAutoUnmount(void)
{
    uint32_t u32ClientId;
    int rc = VbglR3SharedFolderConnect(&u32ClientId);
    if (!RT_SUCCESS(rc))
        LogFlowFunc(("Failed to connect to the shared folder service, error %Rrc\n", rc));
    else
    {
        uint32_t cMappings;
        VBGLR3SHAREDFOLDERMAPPING *paMappings;

        rc = VbglR3SharedFolderGetMappings(u32ClientId, true /* Only process auto-mounted folders */,
                                           &paMappings, &cMappings);
        if (RT_SUCCESS(rc))
        {
            for (uint32_t i = 0; i < cMappings && RT_SUCCESS(rc); i++)
            {
                char *pszName = NULL;
                rc = VbglR3SharedFolderGetName(u32ClientId, paMappings[i].u32Root, &pszName);
                if (   RT_SUCCESS(rc)
                    && *pszName)
                {
                    LogFlowFunc(("Disconnecting share %u (%s) ...\n", i+1, pszName));

                    char *pszShareName;
                    if (RTStrAPrintf(&pszShareName, "\\\\vboxsrv\\%s", pszName) >= 0)
                    {
                        DWORD dwErr = WNetCancelConnection2(pszShareName, 0, FALSE /* Force disconnect */);
                        if (dwErr == NO_ERROR)
                        {
                            LogRel(("Share \"%s\" was disconnected\n", pszShareName));
                            RTStrFree(pszShareName);
                            RTStrFree(pszName);
                            break;
                        }

                        LogRel(("Disconnecting \"%s\" failed, dwErr = %ld\n", pszShareName, dwErr));

                        switch (dwErr)
                        {
                            case ERROR_NOT_CONNECTED:
                                break;

                            default:
                                LogRel(("Error while disconnecting shared folder \"%s\", error = %ld\n",
                                        pszShareName, dwErr));
                                break;
                        }

                        RTStrFree(pszShareName);
                    }
                    else
                        rc = VERR_NO_MEMORY;
                    RTStrFree(pszName);
                }
                else
                    LogFlowFunc(("Error while getting the shared folder name for root node = %u, rc = %Rrc\n",
                         paMappings[i].u32Root, rc));
            }
            VbglR3SharedFolderFreeMappings(paMappings);
        }
        else
            LogFlowFunc(("Error while getting the shared folder mappings, rc = %Rrc\n", rc));
        VbglR3SharedFolderDisconnect(u32ClientId);
    }
    return rc;
}