//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1993.
//
//  File:       dlgnew.cxx
//
//  Contents:   "New Share" dialog
//
//  History:    21-Feb-95 BruceFo Created
//
//--------------------------------------------------------------------------

#include "headers.hxx"
#pragma hdrstop

#include "resource.h"
#include "helpids.h"
#include "cache.hxx"
#include "dlgnew.hxx"
#include "acl.hxx"
#include "util.hxx"
#include "shrinfo.hxx"

////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////


//+-------------------------------------------------------------------------
//
//  Member:     CDlgNewShare::SizeWndProc, public
//
//  Synopsis:   "allow" edit window subclass proc to disallow non-numeric
//              characters.
//
//  History:    5-Apr-95 BruceFo  Created
//
//--------------------------------------------------------------------------

LRESULT CALLBACK
CDlgNewShare::SizeWndProc(
    IN HWND hwnd,
    IN UINT wMsg,
    IN WPARAM wParam,
    IN LPARAM lParam
    )
{
    switch (wMsg)
    {
    case WM_CHAR:
    {
        WCHAR chCharCode = (WCHAR)wParam;
        if (   (chCharCode == TEXT('\t'))
            || (chCharCode == TEXT('\b'))
            || (chCharCode == TEXT('\n'))
            )
        {
            break;
        }

        if (chCharCode < TEXT('0') || chCharCode > TEXT('9'))
        {
            // bad key: ignore it
            MessageBeep(0xffffffff);    // let user know it's an illegal char
            return FALSE;
        }

        break;
    }
    } // end of switch

    CDlgNewShare* pThis = (CDlgNewShare*)GetWindowLongPtr(GetParent(hwnd),GWLP_USERDATA);
    appAssert(NULL != pThis);
    return CallWindowProc(pThis->_pfnAllowProc, hwnd, wMsg, wParam, lParam);
}


//+-------------------------------------------------------------------------
//
//  Method:     CDlgNewShare::CDlgNewShare, private
//
//  Synopsis:   constructor
//
//--------------------------------------------------------------------------
CDlgNewShare::CDlgNewShare(
    IN HWND hwndParent
    )
    :
    CDialog(hwndParent, MAKEINTRESOURCE(IDD_NEW_SHARE)),
    _bShareNameChanged(FALSE),
    _bCommentChanged(FALSE),
    _wMaxUsers(DEFAULT_MAX_USERS),
    _fSecDescModified(FALSE),
    _pStoredSecDesc(NULL),
    _pfnAllowProc(NULL)
{
    INIT_SIG(CDlgNewShare);
}

//+-------------------------------------------------------------------------
//
//  Method:     CDlgNewShare::~CDlgNewShare, private
//
//  Synopsis:   destructor
//
//--------------------------------------------------------------------------
CDlgNewShare::~CDlgNewShare()
{
    CHECK_SIG(CDlgNewShare);
}

//+-------------------------------------------------------------------------
//
//  Method:     CDlgNewShare::DlgProc, private
//
//  Synopsis:   Dialog Procedure for this object
//
//--------------------------------------------------------------------------
INT_PTR
CDlgNewShare::DlgProc(
    IN HWND hwnd,
    IN UINT msg,
    IN WPARAM wParam,
    IN LPARAM lParam
    )
{
    CHECK_SIG(CDlgNewShare);

    static DWORD aHelpIds[] =
    {
        IDOK,                       HC_OK,
        IDCANCEL,                   HC_CANCEL,
        IDC_SHARE_SHARENAME,        HC_SHARE_SHARENAME,
        IDC_SHARE_SHARENAME_TEXT,   HC_SHARE_SHARENAME,
        IDC_SHARE_COMMENT,          HC_SHARE_COMMENT,
        IDC_SHARE_COMMENT_TEXT,     HC_SHARE_COMMENT,
        IDC_SHARE_MAXIMUM,          HC_SHARE_MAXIMUM,
        IDC_SHARE_ALLOW,            HC_SHARE_ALLOW,
        IDC_SHARE_ALLOW_VALUE,      HC_SHARE_ALLOW_VALUE,
        IDC_SHARE_ALLOW_SPIN,       -1L, // 257807 by request of JillZ
        IDC_SHARE_PERMISSIONS,      HC_SHARE_PERMISSIONS,
        IDC_SHARE_LIMIT,            HC_SHARE_LIMIT,
        0,0
    };

    switch (msg)
    {
    case WM_INITDIALOG:
        return _OnInitDialog(hwnd);

    case WM_COMMAND:
        return _OnCommand(hwnd, HIWORD(wParam), LOWORD(wParam), (HWND)lParam);

    case WM_VSCROLL:
        // The up/down control changed the edit control: select it again
        SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_VALUE, EM_SETSEL, 0, (LPARAM)-1);
        return TRUE;

    case WM_HELP:
    {
        LPHELPINFO lphi = (LPHELPINFO)lParam;

        if (lphi->iContextType == HELPINFO_WINDOW)  // a control
        {
            WCHAR szHelp[50];
            LoadString(g_hInstance, IDS_HELPFILENAME, szHelp, ARRAYLEN(szHelp));
            WinHelp(
                (HWND)lphi->hItemHandle,
                szHelp,
                HELP_WM_HELP,
                (DWORD_PTR)aHelpIds);
        }
        break;
    }

    case WM_CONTEXTMENU:
    {
        WCHAR szHelp[50];
        LoadString(g_hInstance, IDS_HELPFILENAME, szHelp, ARRAYLEN(szHelp));
        WinHelp(
            (HWND)wParam,
            szHelp,
            HELP_CONTEXTMENU,
            (DWORD_PTR)aHelpIds);
        break;
    }

    case WM_DESTROY:
    {
        // restore original subclass to window.
        appAssert(NULL != GetDlgItem(hwnd,IDC_SHARE_ALLOW_VALUE));
        SetWindowLongPtr(GetDlgItem(hwnd,IDC_SHARE_ALLOW_VALUE), GWLP_WNDPROC, (LONG_PTR)_pfnAllowProc);
        return FALSE;
    }

    } // end of switch

    return FALSE;
}


//+-------------------------------------------------------------------------
//
//  Method:     CDlgNewShare::_OnInitDialog, private
//
//  Synopsis:   WM_INITDIALOG handler
//
//--------------------------------------------------------------------------

BOOL
CDlgNewShare::_OnInitDialog(
    IN HWND hwnd
    )
{
    CHECK_SIG(CDlgNewShare);

    // Subclass allow edit control to disallow non-positive numbers
    _pfnAllowProc = (WNDPROC)SetWindowLongPtr(
                                    GetDlgItem(hwnd, IDC_SHARE_ALLOW_VALUE),
                                    GWLP_WNDPROC,
                                    (LONG_PTR)&SizeWndProc);

    // use LanMan API constants to set maximum share name & comment lengths
    SendDlgItemMessage(hwnd, IDC_SHARE_SHARENAME, EM_LIMITTEXT, NNLEN, 0L);
    SendDlgItemMessage(hwnd, IDC_SHARE_COMMENT,   EM_LIMITTEXT, MAXCOMMENTSZ, 0L);

    CheckRadioButton(
            hwnd,
            IDC_SHARE_MAXIMUM,
            IDC_SHARE_ALLOW,
            IDC_SHARE_MAXIMUM);

    SetDlgItemText(hwnd, IDC_SHARE_ALLOW_VALUE, L"");

    // set the spin control range: 1 <--> large number
    SendDlgItemMessage(
            hwnd,
            IDC_SHARE_ALLOW_SPIN,
            UDM_SETRANGE,
            0,
            MAKELONG(g_uiMaxUsers, 1));

    SetFocus(GetDlgItem(hwnd, IDC_SHARE_SHARENAME));

    return FALSE;
}


//+-------------------------------------------------------------------------
//
//  Member:     CDlgNewShare::_OnCommand, private
//
//  Synopsis:   WM_COMMAND handler
//
//  History:    21-Apr-95 BruceFo  Created
//
//--------------------------------------------------------------------------

BOOL
CDlgNewShare::_OnCommand(
    IN HWND hwnd,
    IN WORD wNotifyCode,
    IN WORD wID,
    IN HWND hwndCtl
    )
{
    CHECK_SIG(CDlgNewShare);

    switch (wID)
    {

//
// Notifications
//

    case IDC_SHARE_MAXIMUM:
        if (BN_CLICKED == wNotifyCode)
        {
            // Take away WS_TABSTOP from the "allow users" edit control
            HWND hwndEdit = GetDlgItem(hwnd, IDC_SHARE_ALLOW_VALUE);
            SetWindowLong(hwndEdit, GWL_STYLE, GetWindowLong(hwndEdit, GWL_STYLE) & ~WS_TABSTOP);

            _CacheMaxUses(hwnd);
            SetDlgItemText(hwnd, IDC_SHARE_ALLOW_VALUE, L"");
        }
        return TRUE;

    case IDC_SHARE_ALLOW:
        if (BN_CLICKED == wNotifyCode)
        {
            // Give WS_TABSTOP to the "allow users" edit control
            HWND hwndEdit = GetDlgItem(hwnd, IDC_SHARE_ALLOW_VALUE);
            SetWindowLong(hwndEdit, GWL_STYLE, GetWindowLong(hwndEdit, GWL_STYLE) | WS_TABSTOP);

            // let the spin control set the edit control
            SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_SPIN, UDM_SETPOS, 0, MAKELONG(_wMaxUsers, 0));
            SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_VALUE, EM_SETSEL, 0, (LPARAM)-1);
        }
        return TRUE;

    case IDC_SHARE_ALLOW_VALUE:
    {
        if (EN_SETFOCUS == wNotifyCode)
        {
            if (1 != IsDlgButtonChecked(hwnd, IDC_SHARE_ALLOW))
            {
                CheckRadioButton(
                    hwnd,
                    IDC_SHARE_MAXIMUM,
                    IDC_SHARE_ALLOW,
                    IDC_SHARE_ALLOW);
            }

            // let the spin control set the edit control
            SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_SPIN, UDM_SETPOS, 0, MAKELONG(_wMaxUsers, 0));
            SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_VALUE, EM_SETSEL, 0, (LPARAM)-1);
        }
        if (EN_KILLFOCUS == wNotifyCode)
        {
            _CacheMaxUses(hwnd);
        }

        return TRUE;
    }

    case IDC_SHARE_ALLOW_SPIN:
        if (UDN_DELTAPOS == wNotifyCode)
        {
            if (1 != IsDlgButtonChecked(hwnd, IDC_SHARE_ALLOW))
            {
                CheckRadioButton(
                    hwnd,
                    IDC_SHARE_MAXIMUM,
                    IDC_SHARE_ALLOW,
                    IDC_SHARE_ALLOW);
            }
        }
        return TRUE;

    case IDC_SHARE_SHARENAME:
    {
        if (wNotifyCode == EN_CHANGE)
        {
            _bShareNameChanged = TRUE;
        }
        return TRUE;
    }

    case IDC_SHARE_COMMENT:
    {
        if (wNotifyCode == EN_CHANGE)
        {
            _bCommentChanged = TRUE;
        }
        return TRUE;
    }


//
// Commands
//

    case IDOK:
        return _OnOK(hwnd);

    case IDCANCEL:
        EndDialog(hwnd, FALSE);
        return TRUE;

    case IDC_SHARE_PERMISSIONS:
        return _OnPermissions(hwnd);

    } // end of switch (wID)

    return FALSE;
}


//+-------------------------------------------------------------------------
//
//  Method:     CDlgNewShare::_OnOK, private
//
//  Synopsis:
//
//--------------------------------------------------------------------------

BOOL
CDlgNewShare::_OnOK(
    IN HWND hwnd
    )
{
    CHECK_SIG(CDlgNewShare);

    HRESULT hr;

    // Validate the share

    WCHAR szShareName[NNLEN + 1];

    if (0 == GetDlgItemText(hwnd, IDC_SHARE_SHARENAME, szShareName, ARRAYLEN(szShareName)))
    {
        MyErrorDialog(hwnd, IERR_BlankShareName);
        SetErrorFocus(hwnd, IDC_SHARE_SHARENAME);
        return TRUE;
    }

	TrimLeadingAndTrailingSpaces(szShareName);

    HRESULT uTemp;
    if (!IsValidShareName(szShareName, &uTemp))
    {
        MyErrorDialog(hwnd, uTemp);
        SetErrorFocus(hwnd, IDC_SHARE_SHARENAME);
        return TRUE;
    }

    // Trying to create a reserved share?
    if (0 == _wcsicmp(g_szIpcShare, szShareName))
    {
        MyErrorDialog(hwnd, IERR_SpecialShare);
        SetErrorFocus(hwnd, IDC_SHARE_SHARENAME);
        return TRUE;
    }

    if (0 == _wcsicmp(g_szAdminShare, szShareName))
    {
        // We will let the admin create the admin$ share if they create
        // it in the directory specified by GetWindowsDirectory().
        WCHAR szWindowsDir[MAX_PATH];
        UINT err = GetWindowsDirectory(szWindowsDir, ARRAYLEN(szWindowsDir));
        if (err == 0)
        {
            // oh well, give them this error
            MyErrorDialog(hwnd, IERR_SpecialShare);
            SetErrorFocus(hwnd, IDC_SHARE_SHARENAME);
            return FALSE;
        }

        if (0 != _wcsicmp(m_pShareInfo->GetPath(), szWindowsDir))
        {
            MyErrorDialog(hwnd, IERR_SpecialShare);
            SetErrorFocus(hwnd, IDC_SHARE_SHARENAME);
            return FALSE;
        }

        // otherwise, it is the right directory. Let them create it.
    }

    // Check to see that the same share doesn't already exist. We don't allow
    // the user to create a share with the same name as a marked-for-delete
    // share, because it's easier!
    for (CShareInfo* p = (CShareInfo*) m_pInfoList->Next();
         p != m_pInfoList;
         p = (CShareInfo*) p->Next())
    {
        if (0 == _wcsicmp(p->GetNetname(), szShareName))
        {
            MyErrorDialog(hwnd, IERR_AlreadyExists, szShareName);
            SetErrorFocus(hwnd, IDC_SHARE_SHARENAME);
            return TRUE;
        }
    }

    /* removed JonN 10/5/98
    // Check for downlevel accessibility
    // we should really get rid of this at some point -- JonN 7/18/97
    ULONG nType;
    if (NERR_Success != NetpPathType(NULL, szShareName, &nType, INPT_FLAGS_OLDPATHS))
    {
        DWORD id = MyConfirmationDialog(
                        hwnd,
                        IERR_InaccessibleByDos,
                        MB_YESNO | MB_ICONEXCLAMATION,
                        szShareName);
        if (id == IDNO)
        {
            SetErrorFocus(hwnd, IDC_SHARE_SHARENAME);
            return TRUE;
        }
    }
    */

    WCHAR szOldPath[PATHLEN + 1];

    if (g_ShareCache.IsExistingShare(szShareName, m_pShareInfo->GetPath(), szOldPath))
    {
        DWORD id = ConfirmReplaceShare(hwnd, szShareName, szOldPath, m_pShareInfo->GetPath());
        if (id != IDYES)
        {
            SetErrorFocus(hwnd, IDC_SHARE_SHARENAME);
            return TRUE;
        }

        // User said to replace the old share. We need to add
        // a "delete" record for the old share.

        CShareInfo* pNewInfo = new CShareInfo();
        if (NULL == pNewInfo)
        {
            return FALSE;
        }

        hr = pNewInfo->InitInstance();
        CHECK_HRESULT(hr);
        if (FAILED(hr))
        {
            delete pNewInfo;
            return FALSE;
        }

        hr = pNewInfo->SetNetname(szShareName);
        CHECK_HRESULT(hr);
        if (FAILED(hr))
        {
            delete pNewInfo;
            return FALSE;
        }

        hr = pNewInfo->SetPath(szOldPath);
        CHECK_HRESULT(hr);
        if (FAILED(hr))
        {
            delete pNewInfo;
            return FALSE;
        }

        NET_API_STATUS    ret = pNewInfo->ReadCacheFlags ();
        if ( NERR_Success != ret )
        {
            delete pNewInfo;
            return HRESULT_FROM_WIN32 (ret);
        }

        pNewInfo->SetDirtyFlag(SHARE_FLAG_REMOVE);
        pNewInfo->InsertBefore(m_pReplaceList); // add to end of replace list
    }

    // Everything OK, save away the data

    if (_bShareNameChanged)
    {
        hr = m_pShareInfo->SetNetname(szShareName);
        CHECK_HRESULT(hr);
    }

    if (_bCommentChanged)
    {
        WCHAR szComment[MAXCOMMENTSZ + 1];
        GetDlgItemText(hwnd, IDC_SHARE_COMMENT, szComment, ARRAYLEN(szComment));
        hr = m_pShareInfo->SetRemark(szComment);
        CHECK_HRESULT(hr);
    }

    if (1 == IsDlgButtonChecked(hwnd, IDC_SHARE_MAXIMUM))
    {
        hr = m_pShareInfo->SetMaxUses(SHI_USES_UNLIMITED);
        CHECK_HRESULT(hr);
    }
    else if (1 == IsDlgButtonChecked(hwnd, IDC_SHARE_ALLOW))
    {
        _CacheMaxUses(hwnd);
        hr = m_pShareInfo->SetMaxUses(_wMaxUsers);
        CHECK_HRESULT(hr);
    }

    EndDialog(hwnd, TRUE);
    return TRUE;
}


//+-------------------------------------------------------------------------
//
//  Method:     CDlgNewShare::_OnPermissions, private
//
//  Synopsis:
//
//--------------------------------------------------------------------------
BOOL
CDlgNewShare::_OnPermissions(
    IN HWND hwnd
    )
{
    CHECK_SIG(CDlgNewShare);

    WCHAR szShareName[NNLEN + 1];
    GetDlgItemText(hwnd, IDC_SHARE_SHARENAME, szShareName, ARRAYLEN(szShareName));
    // don't trim spaces, this might be an existing share with spaces in its name

    PSECURITY_DESCRIPTOR pNewSecDesc = NULL;
    PSECURITY_DESCRIPTOR pSecDesc = m_pShareInfo->GetSecurityDescriptor();
    appAssert(NULL == pSecDesc || IsValidSecurityDescriptor(pSecDesc));

    BOOL bSecDescChanged;
    LONG err = EditShareAcl(
                        hwnd,
                        NULL,
                        szShareName,
                        pSecDesc,
                        &bSecDescChanged,
                        &pNewSecDesc);

    if (bSecDescChanged)
    {
        _fSecDescModified = TRUE;

        appAssert(IsValidSecurityDescriptor(pNewSecDesc));
        m_pShareInfo->TransferSecurityDescriptor(pNewSecDesc);
    }

    return TRUE;
}


//+-------------------------------------------------------------------------
//
//  Method:     CDlgNewShare::_CacheMaxUses, private
//
//  Synopsis:
//
//--------------------------------------------------------------------------
VOID
CDlgNewShare::_CacheMaxUses(
    IN HWND hwnd
    )
{
    DWORD dwRet = (DWORD)SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_SPIN, UDM_GETPOS, 0, 0);
    if (HIWORD(dwRet) != 0)
    {
        _wMaxUsers = DEFAULT_MAX_USERS;

        // Reset the edit control to the new value
        SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_SPIN, UDM_SETPOS, 0, MAKELONG(_wMaxUsers, 0));
        SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_VALUE, EM_SETSEL, 0, (LPARAM)-1);
    }
    else
    {
        _wMaxUsers = LOWORD(dwRet);
    }
}
