
#include "precomp.h"

/* update NUM_SETTINGS in precomp.h */
LPWSTR lpSettings[NUM_SETTINGS] =
{
    L"desktopwidth",
    L"desktopheight",
    L"session bpp",
    L"full address",
    L"username",
    L"screen mode id",
};

VOID
SaveAllSettings(PINFO pInfo)
{
    INT ret;
    WCHAR szValue[MAXVALUE];

    /* server */
    if (GetDlgItemText(pInfo->hGeneralPage,
                       IDC_SERVERCOMBO,
                       szValue,
                       MAXVALUE))
    {
        SetStringToSettings(pInfo->pRdpSettings,
                            L"full address",
                            szValue);
    }

    /* resolution and fullscreen*/
    ret = SendDlgItemMessage(pInfo->hDisplayPage,
                             IDC_GEOSLIDER,
                             TBM_GETPOS,
                             0,
                             0);
    if (ret != -1)
    {
        SetIntegerToSettings(pInfo->pRdpSettings,
                             L"screen mode id",
                             (ret == SendDlgItemMessageW(pInfo->hDisplayPage, IDC_GEOSLIDER, TBM_GETRANGEMAX, 0, 0)) ? 2 : 1);
        SetIntegerToSettings(pInfo->pRdpSettings,
                             L"desktopwidth",
                             pInfo->DisplayDeviceList->Resolutions[ret].dmPelsWidth);
        SetIntegerToSettings(pInfo->pRdpSettings,
                             L"desktopheight",
                             pInfo->DisplayDeviceList->Resolutions[ret].dmPelsHeight);
    }

    /* bpp */
    ret = SendDlgItemMessage(pInfo->hDisplayPage,
                             IDC_BPPCOMBO,
                             CB_GETCURSEL,
                             0,
                             0);
    if (ret != CB_ERR)
    {
        ret = SendDlgItemMessage(pInfo->hDisplayPage,
                                 IDC_BPPCOMBO,
                                 CB_GETITEMDATA,
                                 ret,
                                 0);
        if (ret != CB_ERR)
        {
            SetIntegerToSettings(pInfo->pRdpSettings,
                                 L"session bpp",
                                 ret);
        }
    }

    /* user name */
    if (GetDlgItemText(pInfo->hGeneralPage,
                       IDC_NAMEEDIT,
                       szValue,
                       MAXVALUE))
    {
        SetStringToSettings(pInfo->pRdpSettings,
                            L"username",
                            szValue);
    }
}


BOOL
SetIntegerToSettings(PRDPSETTINGS pRdpSettings,
                     LPWSTR lpKey,
                     INT Value)
{
    BOOL bRet = FALSE;

    if (pRdpSettings)
    {
        INT i;

        for (i = 0; i < pRdpSettings->NumSettings; i++)
        {
            if (wcscmp(pRdpSettings->pSettings[i].Key, lpKey) == 0)
            {
                if (pRdpSettings->pSettings[i].Type == 0)
                    pRdpSettings->pSettings[i].Type = L'i';

                pRdpSettings->pSettings[i].Value.i = Value;
                bRet = TRUE;
                break;
            }
        }
    }

    return bRet;
}


BOOL
SetStringToSettings(PRDPSETTINGS pRdpSettings,
                    LPWSTR lpKey,
                    LPWSTR lpValue)
{
    BOOL bRet = FALSE;

    if (pRdpSettings)
    {
        INT i;

        for (i = 0; i < pRdpSettings->NumSettings; i++)
        {
            if (wcscmp(pRdpSettings->pSettings[i].Key, lpKey) == 0)
            {
                if (pRdpSettings->pSettings[i].Type == 0)
                    pRdpSettings->pSettings[i].Type = L's';

                wcscpy(pRdpSettings->pSettings[i].Value.s, lpValue);
                bRet = TRUE;
                break;
            }
        }
    }

    return bRet;
}


INT
GetIntegerFromSettings(PRDPSETTINGS pRdpSettings,
                       LPWSTR lpKey)
{
    INT Value = -1;

    if (pRdpSettings)
    {
        INT i;

        for (i = 0; i < pRdpSettings->NumSettings; i++)
        {
            if (wcscmp(pRdpSettings->pSettings[i].Key, lpKey) == 0)
            {
                if (pRdpSettings->pSettings[i].Type == L'i')
                {
                    Value = pRdpSettings->pSettings[i].Value.i;
                    break;
                }
            }
        }
    }

    return Value;
}


LPWSTR
GetStringFromSettings(PRDPSETTINGS pRdpSettings,
                      LPWSTR lpKey)
{
    LPWSTR lpValue = NULL;

    if (pRdpSettings)
    {
        INT i;

        for (i = 0; i < pRdpSettings->NumSettings; i++)
        {
            if (wcscmp(pRdpSettings->pSettings[i].Key, lpKey) == 0)
            {
                if (pRdpSettings->pSettings[i].Type == L's')
                {
                    lpValue = pRdpSettings->pSettings[i].Value.s;
                    break;
                }
            }
        }
    }

    return lpValue;
}


static BOOL
WriteRdpFile(HANDLE hFile,
             PRDPSETTINGS pRdpSettings)
{
    WCHAR line[MAXKEY + MAXVALUE + 4];
    SIZE_T BytesToWrite;
    ULONG BytesWritten;
    BOOL bRet;
    INT i, k;

    for (i = 0; i < pRdpSettings->NumSettings; i++)
    {
        /* only write out values in the lpSettings struct */
        for (k = 0; k < NUM_SETTINGS; k++)
        {
            if (wcscmp(lpSettings[k], pRdpSettings->pSettings[i].Key) == 0)
            {
                if (pRdpSettings->pSettings[i].Type == L'i')
                {
                    _snwprintf(line, MAXKEY + MAXVALUE + 4, L"%s:i:%d\r\n",
                               pRdpSettings->pSettings[i].Key,
                               pRdpSettings->pSettings[i].Value.i);
                }
                else
                {
                    _snwprintf(line, MAXKEY + MAXVALUE + 4, L"%s:s:%s\r\n",
                               pRdpSettings->pSettings[i].Key,
                               pRdpSettings->pSettings[i].Value.s);
                }

                BytesToWrite = wcslen(line) * sizeof(WCHAR);

                bRet = WriteFile(hFile,
                                 line,
                                 BytesToWrite,
                                 &BytesWritten,
                                 NULL);
                if (!bRet || BytesWritten == 0)
                    return FALSE;
            }
        }
    }

    return TRUE;
}


static VOID
ParseSettings(PRDPSETTINGS pRdpSettings,
              LPWSTR lpBuffer)
{
    LPWSTR lpStr = lpBuffer;
    WCHAR szSeps[] = L":\r\n";
    WCHAR szNewline[] = L"\r\n";
    LPWSTR lpToken;
    BOOL bFound;
    INT i;

    /* move past unicode byte order */
    if (lpStr[0] == 0xFEFF || lpStr[0] == 0xFFFE)
        lpStr += 1;

    lpToken = wcstok(lpStr, szSeps);
    while (lpToken)
    {
        bFound = FALSE;

        for (i = 0; i < pRdpSettings->NumSettings && !bFound; i++)
        {
            if (wcscmp(lpToken, pRdpSettings->pSettings[i].Key) == 0)
            {
                lpToken = wcstok(NULL, szSeps);
                if (lpToken[0] == L'i')
                {
                    pRdpSettings->pSettings[i].Type = lpToken[0];
                    lpToken = wcstok(NULL, szSeps);
                    if (lpToken != NULL)
                        pRdpSettings->pSettings[i].Value.i = _wtoi(lpToken);
                }
                else if (lpToken[0] == L's')
                {
                    pRdpSettings->pSettings[i].Type = lpToken[0];
                    if (lpToken[2] == 13 || lpToken[2] == 10 || lpToken[2] == 0)
                        lpToken[0] = 0; // terminate string
                    else
                        lpToken = wcstok(NULL, szNewline);
                    if (lpToken != NULL)
                        wcscpy(pRdpSettings->pSettings[i].Value.s, lpToken);
                }
                bFound = TRUE;
            }
        }

        /* move past the type and value */
        if (!bFound)
            lpToken = wcstok(NULL, szNewline);

        /* move to next key */
        lpToken = wcstok(NULL, szSeps);
    }
}


static LPWSTR
ReadRdpFile(HANDLE hFile)
{
    LPWSTR lpBuffer = NULL;
    DWORD BytesToRead, BytesRead;
    BOOL bRes;

    if (hFile)
    {
        BytesToRead = GetFileSize(hFile, NULL);
        if (BytesToRead)
        {
            lpBuffer = HeapAlloc(GetProcessHeap(),
                                 0,
                                 BytesToRead + 2);
            if (lpBuffer)
            {
                bRes = ReadFile(hFile,
                                lpBuffer,
                                BytesToRead,
                                &BytesRead,
                                NULL);
                if (bRes)
                {
                    lpBuffer[BytesRead / 2] = 0;
                }
                else
                {
                    HeapFree(GetProcessHeap(),
                             0,
                             lpBuffer);

                    lpBuffer = NULL;
                }
            }
        }
    }

    return lpBuffer;
}


static HANDLE
OpenRdpFile(LPWSTR path, BOOL bWrite)
{
    HANDLE hFile = NULL;

    if (path)
    {
        hFile = CreateFileW(path,
                            bWrite ? GENERIC_WRITE : GENERIC_READ,
                            0,
                            NULL,
                            bWrite ? CREATE_ALWAYS : OPEN_EXISTING,
                            FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_HIDDEN,
                            NULL);
    }

    return hFile;
}


static VOID
CloseRdpFile(HANDLE hFile)
{
    if (hFile)
        CloseHandle(hFile);
}


BOOL
SaveRdpSettingsToFile(LPWSTR lpFile,
                      PRDPSETTINGS pRdpSettings)
{
    WCHAR pszPath[MAX_PATH];
    HANDLE hFile;
    BOOL bRet = FALSE;

    /* use default file */
    if (lpFile == NULL)
    {
        HRESULT hr;
        LPITEMIDLIST lpidl= NULL;

        hr = SHGetFolderLocation(NULL,
                                 CSIDL_PERSONAL,
                                 NULL,
                                 0,
                                 &lpidl);
        if (hr == S_OK)
        {
            if (SHGetPathFromIDListW(lpidl, pszPath))
            {
                wcscat(pszPath, L"\\Default.rdp");
                lpFile = pszPath;
                CoTaskMemFree(lpidl);
            }
        }
    }

    if (lpFile)
    {
        hFile = OpenRdpFile(lpFile, TRUE);
        if (hFile)
        {
            if (WriteRdpFile(hFile, pRdpSettings))
            {
                bRet = TRUE;
            }

            CloseRdpFile(hFile);
        }
    }

    return bRet;
}


BOOL
LoadRdpSettingsFromFile(PRDPSETTINGS pRdpSettings,
                        LPWSTR lpFile)
{
    WCHAR pszPath[MAX_PATH];
    HANDLE hFile;
    BOOL bRet = FALSE;

    /* use default file */
    if (lpFile == NULL)
    {
        HRESULT hr;
        LPITEMIDLIST lpidl= NULL;

        hr = SHGetFolderLocation(NULL,
                                 CSIDL_PERSONAL,
                                 NULL,
                                 0,
                                 &lpidl);
        if (hr == S_OK)
        {
            if (SHGetPathFromIDListW(lpidl, pszPath))
            {
                wcscat(pszPath, L"\\Default.rdp");
                lpFile = pszPath;
                CoTaskMemFree(lpidl);
            }
        }
    }

    if (lpFile)
    {
        LPWSTR lpBuffer = NULL;

        hFile = OpenRdpFile(lpFile, FALSE);
        if (hFile)
        {
            lpBuffer = ReadRdpFile(hFile);
            if (lpBuffer)
            {
                ParseSettings(pRdpSettings, lpBuffer);

                HeapFree(GetProcessHeap(),
                         0,
                         lpBuffer);
                
                bRet = TRUE;
            }

            CloseRdpFile(hFile);
        }
    }

    return bRet;
}


BOOL
InitRdpSettings(PRDPSETTINGS pRdpSettings)
{
    BOOL bRet = FALSE;

    pRdpSettings->pSettings = HeapAlloc(GetProcessHeap(),
                                        0,
                                        sizeof(SETTINGS) * NUM_SETTINGS);
    if (pRdpSettings->pSettings)
    {
        INT i;

        for (i = 0; i < NUM_SETTINGS; i++)
        {
            wcscpy(pRdpSettings->pSettings[i].Key, lpSettings[i]);
            pRdpSettings->pSettings[i].Type = (WCHAR)0;
            pRdpSettings->pSettings[i].Value.i = 0;
        }

        pRdpSettings->NumSettings = NUM_SETTINGS;

        bRet = TRUE;
    }

    return bRet;
}
