/**
 * 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_FAILURE(rc))
        Log(("VBoxTray: 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))
        {
#if 0
            /* Check for a fixed/virtual auto-mount share. */
            if (VbglR3SharedFolderExists(u32ClientId, "vbsfAutoMount"))
            {
                Log(("VBoxTray: Hosts supports auto-mount root\n"));
            }
            else
            {
#endif
                Log(("VBoxTray: 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)
                    {
                        Log(("VBoxTray: 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(("VBoxTray: Shared folder \"%s\" was mounted to drive \"%s\"\n", pszName, szCurDrive));
                                    break;
                                }
                                else
                                {
                                    LogRel(("VBoxTray: 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(("VBoxTray: Error while mounting shared folder \"%s\" to \"%s\", error = %ld\n",
                                                    pszName, szCurDrive, dwErr));
                                            break;
                                    }
                                }
                            } while (chDrive <= 'Z');

                            if (chDrive > 'Z')
                            {
                                LogRel(("VBoxTray: 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
                        Log(("VBoxTray: Error while getting the shared folder name for root node = %u, rc = %Rrc\n",
                             paMappings[i].u32Root, rc));
                }
#if 0
            }
#endif
            RTMemFree(paMappings);
        }
        else
            Log(("VBoxTray: Error while getting the shared folder mappings, rc = %Rrc\n", rc));
        VbglR3SharedFolderDisconnect(u32ClientId);
    }
    return rc;
}
int VBoxSharedFoldersAutoUnmount(void)
{
    uint32_t u32ClientId;
    int rc = VbglR3SharedFolderConnect(&u32ClientId);
    if (!RT_SUCCESS(rc))
        Log(("VBoxTray: 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)
                {
                    Log(("VBoxTray: 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(("VBoxTray: Share \"%s\" was disconnected\n", pszShareName));
                            RTStrFree(pszShareName);
                            RTStrFree(pszName);
                            break;
                        }

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

                        switch (dwErr)
                        {
                            case ERROR_NOT_CONNECTED:
                                break;

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

                        RTStrFree(pszShareName);
                    }
                    else
                        rc = VERR_NO_MEMORY;
                    RTStrFree(pszName);
                }
                else
                    Log(("VBoxTray: Error while getting the shared folder name for root node = %u, rc = %Rrc\n",
                         paMappings[i].u32Root, rc));
            }
            RTMemFree(paMappings);
        }
        else
            Log(("VBoxTray: Error while getting the shared folder mappings, rc = %Rrc\n", rc));
        VbglR3SharedFolderDisconnect(u32ClientId);
    }
    return rc;
}
static int VBoxServiceAutoMountProcessMappings(PVBGLR3SHAREDFOLDERMAPPING paMappings, uint32_t cMappings,
                                               const char *pszMountDir, const char *pszSharePrefix, uint32_t uClientID)
{
    if (cMappings == 0)
        return VINF_SUCCESS;
    AssertPtrReturn(paMappings, VERR_INVALID_PARAMETER);
    AssertPtrReturn(pszMountDir, VERR_INVALID_PARAMETER);
    AssertPtrReturn(pszSharePrefix, VERR_INVALID_PARAMETER);
    AssertReturn(uClientID > 0, VERR_INVALID_PARAMETER);

    int rc = VINF_SUCCESS;
    for (uint32_t i = 0; i < cMappings && RT_SUCCESS(rc); i++)
    {
        char *pszShareName = NULL;
        rc = VbglR3SharedFolderGetName(uClientID, paMappings[i].u32Root, &pszShareName);
        if (   RT_SUCCESS(rc)
            && *pszShareName)
        {
            VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Connecting share %u (%s) ...\n", i+1, pszShareName);

            char *pszShareNameFull = NULL;
            if (RTStrAPrintf(&pszShareNameFull, "%s%s", pszSharePrefix, pszShareName) > 0)
            {
                char szMountPoint[RTPATH_MAX];
                rc = RTPathJoin(szMountPoint, sizeof(szMountPoint), pszMountDir, pszShareNameFull);
                if (RT_SUCCESS(rc))
                {
                    VBoxServiceVerbose(4, "VBoxServiceAutoMountWorker: Processing mount point \"%s\"\n", szMountPoint);

                    struct group *grp_vboxsf = getgrnam("vboxsf");
                    if (grp_vboxsf)
                    {
                        struct vbsf_mount_opts mount_opts =
                        {
                            0,                     /* uid */
                            (int)grp_vboxsf->gr_gid, /* gid */
                            0,                     /* ttl */
                            0770,                  /* dmode, owner and group "vboxsf" have full access */
                            0770,                  /* fmode, owner and group "vboxsf" have full access */
                            0,                     /* dmask */
                            0,                     /* fmask */
                            0,                     /* ronly */
                            0,                     /* noexec */
                            0,                     /* nodev */
                            0,                     /* nosuid */
                            0,                     /* remount */
                            "\0",                  /* nls_name */
                            NULL,                  /* convertcp */
                        };

                        rc = VBoxServiceAutoMountSharedFolder(pszShareName, szMountPoint, &mount_opts);
                    }
                    else
                        VBoxServiceError("VBoxServiceAutoMountWorker: Group \"vboxsf\" does not exist\n");
                }
                else
                    VBoxServiceError("VBoxServiceAutoMountWorker: Unable to join mount point/prefix/shrae, rc = %Rrc\n", rc);
                RTStrFree(pszShareNameFull);
            }
            else
                VBoxServiceError("VBoxServiceAutoMountWorker: Unable to allocate full share name\n");
            RTStrFree(pszShareName);
        }
        else
            VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder name for root node = %u, rc = %Rrc\n",
                             paMappings[i].u32Root, rc);
    } /* for cMappings. */
    return rc;
}