//+-------------------------------------------------------------------------
//
//  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 "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,
    IN PWSTR pszMachine
    )
    :
    CDialog(hwndParent, MAKEINTRESOURCE(IDD_NEW_SHARE)),
    _pszMachine(pszMachine),
    _bShareNameChanged(FALSE),
    _bPathChanged(FALSE),
    _bCommentChanged(FALSE),
    _wMaxUsers(DEFAULT_MAX_USERS),
    _fSecDescModified(FALSE),
    _pfnAllowProc(NULL),
    _pShareInfo(NULL)
{
    INIT_SIG(CDlgNewShare);
}

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

    delete _pShareInfo;
    _pShareInfo = NULL;
}

//+-------------------------------------------------------------------------
//
//  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_PATH,         HC_SHARE_PATH,
        IDC_SHARE_COMMENT,      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_PERMISSIONS,  HC_SHARE_PERMISSIONS,
        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);

    HRESULT hr;

    // for some reason, this dialog comes up on the bottom!
//  SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
//  SetActiveWindow(hwnd);
    SetForegroundWindow(hwnd);

    // Use a trick from the property sheet code to properly place the dialog.
    // Basically, we want it to go wherever a new window would have gone, not
    // always in the upper-left corner of the screen. This avoids the problem
    // of multiple dialogs showing up in the same place on the screen,
    // overlapping each other.

    const TCHAR c_szStatic[] = TEXT("Static");

    HWND hwndT = CreateWindowEx(0, c_szStatic, NULL,
                    WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT,
                    0, 0, NULL, NULL, g_hInstance, NULL);
    if (hwndT)
    {
        RECT rc;
        GetWindowRect(hwndT, &rc);
        DestroyWindow(hwndT);
        SetWindowPos(hwnd, NULL, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
    }

    SetDialogIconBig(hwnd, IDI_SHARESFLD);
    SetDialogIconSmall(hwnd, IDI_SHARESFLD);

    // storage for security descriptor

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

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

    // 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_PATH,      EM_LIMITTEXT, MAX_PATH-1, 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_PATH:
    {
        if (wNotifyCode == EN_CHANGE)
        {
            _bPathChanged = 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;
    HRESULT uTemp;
    BOOL    fSpecial = FALSE;   // IPC$ or ADMIN$

    // 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);

    WCHAR szPath[MAX_PATH];
    GetDlgItemText(hwnd, IDC_SHARE_PATH, szPath, ARRAYLEN(szPath));

    // Trying to create a reserved share?
    if (   (0 == _wcsicmp(g_szIpcShare,   szShareName))
        || (0 == _wcsicmp(g_szAdminShare, szShareName)))
    {
        // We will let you add IPC$ and ADMIN$ as long as there is no
        // path specified.
        if (szPath[0] != TEXT('\0'))
        {
            MyErrorDialog(hwnd, MSG_ADDSPECIAL);
            SetErrorFocus(hwnd, IDC_SHARE_PATH);
            return TRUE;
        }

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

    // If the user entered some ACL, warn them that we're going to nuke
    // it and let the system use its default (since special shares can't
    // have their security set).
    if (fSpecial || DriveLetterShare(szShareName))
    {
        if (_fSecDescModified)
        {
            DWORD id = MyConfirmationDialog(
                            hwnd,
                            MSG_NOSECURITYONSPECIAL,
                            MB_YESNO | MB_ICONEXCLAMATION);
            if (id == IDNO)
            {
                SetErrorFocus(hwnd, IDC_SHARE_SHARENAME);
                return TRUE;
            }
            _pShareInfo->TransferSecurityDescriptor(NULL);
        }
    }

    // Check to see that the same share isn't already used, for either the
    // same path or for another path.

    SHARE_INFO_2* info2;
    NET_API_STATUS ret = NetShareGetInfo(_pszMachine, szShareName, 2, (LPBYTE*)&info2);
    if (ret == NERR_Success)
    {
        // It is already shared. Trying to re-share IPC$ or ADMIN$?

        if (fSpecial)
        {
            MyErrorDialog(hwnd, IERR_AlreadyExistsSpecial, szShareName);
            SetErrorFocus(hwnd, IDC_SHARE_SHARENAME);
            NetApiBufferFree(info2);
            return TRUE;
        }

        // Is it already shared for the same path?
        if (0 == _wcsicmp(info2->shi2_path, szPath))
        {
            MyErrorDialog(hwnd, IERR_AlreadyExists, szShareName);
            SetErrorFocus(hwnd, IDC_SHARE_SHARENAME);
            NetApiBufferFree(info2);
            return TRUE;
        }

        // Shared for a different path. Ask the user if they wish to delete
        // the old share and create the new one using the name.

        DWORD id = ConfirmReplaceShare(hwnd, szShareName, info2->shi2_path, szPath);
        if (id == IDNO)
        {
            SetErrorFocus(hwnd, IDC_SHARE_SHARENAME);
            NetApiBufferFree(info2);
            return TRUE;
        }
        else if (id == IDCANCEL)
        {
            EndDialog(hwnd, FALSE);
            NetApiBufferFree(info2);
            return TRUE;
        }

        // User said to replace the old share. Do it.
        ret = NetShareDel(_pszMachine, szShareName, 0);
        if (ret != NERR_Success)
        {
            DisplayError(hwnd, IERR_CANT_DEL_SHARE, ret, szShareName);
            NetApiBufferFree(info2);
            return FALSE;
        }
        else
        {
            SHChangeNotify(SHCNE_NETUNSHARE, SHCNF_PATH, info2->shi2_path, NULL);
        }

        NetApiBufferFree(info2);
    }

    if (!fSpecial)
    {
        // Check for downlevel accessibility
        // CODEWORK 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;
            }
        }
    }

    // Everything OK, save away the data

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

    if (_bPathChanged)
    {
        hr = _pShareInfo->SetPath(szPath);
        CHECK_HRESULT(hr);
    }

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

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

    _pShareInfo->SetDirtyFlag(SHARE_FLAG_ADDED);
    ret = _pShareInfo->Commit(_pszMachine);
    if (ret != NERR_Success)
    {
        DisplayError(hwnd, IERR_CANT_ADD_SHARE, ret, _pShareInfo->GetNetname());
    }

    if (fSpecial)
    {
        // IPC$ doesn't have a path. ADMIN$ does, but we need to get it: we
        // create the share passing in no path, as required by the API, but
        // then we ask the server what it decided to share it as.

        if (0 == _wcsicmp(g_szAdminShare, szShareName))
        {
            SHARE_INFO_2* info2;
            NET_API_STATUS ret = NetShareGetInfo(_pszMachine, szShareName, 2, (LPBYTE*)&info2);
            if (ret == NERR_Success)
            {
                SHChangeNotify(SHCNE_NETSHARE, SHCNF_PATH, info2->shi2_path, NULL);
                NetApiBufferFree(info2);
            }
            // else... oh well. No notification to the shell.
        }
    }
    else
    {
        SHChangeNotify(SHCNE_NETSHARE, SHCNF_PATH, _pShareInfo->GetPath(), NULL);
    }

    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 = _pShareInfo->GetSecurityDescriptor();
    appAssert(NULL == pSecDesc || IsValidSecurityDescriptor(pSecDesc));

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

    if (bSecDescChanged)
    {
        _fSecDescModified = TRUE;

        appAssert(IsValidSecurityDescriptor(pNewSecDesc));
        _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);
    }
}
