2219 lines
62 KiB
C++
2219 lines
62 KiB
C++
// Copyright (c) 1998, Microsoft Corporation, all rights reserved
|
||
//
|
||
// sadlg.c
|
||
// Remote Access Common Dialog APIs
|
||
// Shared Access Settings property sheet
|
||
//
|
||
// 10/20/1998 Abolade Gbadegesin
|
||
//
|
||
|
||
//#include "pch.h"
|
||
#pragma hdrstop
|
||
|
||
#include "sautil.h"
|
||
|
||
#include <winsock2.h>
|
||
#include "sainfo.h"
|
||
#include "ipnat.h"
|
||
#include "fwpages.h"
|
||
|
||
// extern(s)
|
||
// replaced global atom with "HNETCFG_SADLG"
|
||
|
||
// Loopback address (127.0.0.1) in network and host byte order
|
||
//
|
||
#define LOOPBACK_ADDR 0x0100007f
|
||
#define LOOPBACK_ADDR_HOST_ORDER 0x7f000001
|
||
|
||
// 'Shared Access Settings' common block
|
||
//
|
||
typedef struct
|
||
_SADLG
|
||
{
|
||
HWND hwndOwner;
|
||
HWND hwndDlg;
|
||
HWND hwndSrv;
|
||
|
||
HWND hwndServers;
|
||
|
||
IHNetCfgMgr *pHNetCfgMgr;
|
||
IHNetConnection *pHNetConn;
|
||
LIST_ENTRY PortMappings;
|
||
BOOL fModified;
|
||
TCHAR *ComputerName;
|
||
|
||
IUPnPService * pUPS; // iff downlevel
|
||
}
|
||
SADLG;
|
||
|
||
// Info block for port mapping entries
|
||
//
|
||
typedef struct
|
||
_SAPM
|
||
{
|
||
LIST_ENTRY Link;
|
||
IHNetPortMappingProtocol *pProtocol;
|
||
IHNetPortMappingBinding *pBinding;
|
||
BOOL fProtocolModified;
|
||
BOOL fBindingModified;
|
||
BOOL fNewEntry;
|
||
BOOL fDeleted;
|
||
|
||
TCHAR *Title;
|
||
BOOL Enabled;
|
||
BOOL BuiltIn;
|
||
|
||
UCHAR Protocol;
|
||
USHORT ExternalPort;
|
||
USHORT InternalPort;
|
||
|
||
TCHAR *InternalName;
|
||
|
||
IStaticPortMapping * pSPM;
|
||
}
|
||
SAPM;
|
||
|
||
#define HTONS(s) ((UCHAR)((s) >> 8) | ((UCHAR)(s) << 8))
|
||
#define HTONL(l) ((HTONS(l) << 16) | HTONS((l) >> 16))
|
||
#define NTOHS(s) HTONS(s)
|
||
#define NTOHL(l) HTONL(l)
|
||
|
||
#define SAPAGE_Servers 0
|
||
#define SAPAGE_Applications 1
|
||
#define SAPAGE_FirewallLogging 2
|
||
#define SAPAGE_ICMPSettings 3
|
||
#define SAPAGE_PageCount 4
|
||
|
||
inline SADLG * SasContext(HWND hwnd)
|
||
{
|
||
return (SADLG*)GetProp(GetParent(hwnd), _T("HNETCFG_SADLG"));
|
||
}
|
||
#define SasErrorDlg(h,o,e,a) \
|
||
ErrorDlgUtil(h,o,e,a,g_hinstDll,SID_SharedAccessSettings,SID_FMT_ErrorMsg)
|
||
|
||
const TCHAR c_szEmpty[] = TEXT("");
|
||
|
||
static DWORD g_adwSrvHelp[] =
|
||
{
|
||
CID_SS_LV_Services, HID_SS_LV_Services,
|
||
CID_SS_PB_Add, HID_SS_PB_Add,
|
||
CID_SS_PB_Edit, HID_SS_PB_Edit,
|
||
CID_SS_PB_Delete, HID_SS_PB_Delete,
|
||
0, 0
|
||
};
|
||
|
||
static DWORD g_adwSspHelp[] =
|
||
{
|
||
CID_SS_EB_Service, HID_SS_EB_Service,
|
||
CID_SS_EB_ExternalPort, -1,
|
||
CID_SS_EB_InternalPort, HID_SS_EB_Port,
|
||
CID_SS_PB_Tcp, HID_SS_PB_Tcp,
|
||
CID_SS_PB_Udp, HID_SS_PB_Udp,
|
||
CID_SS_EB_Address, HID_SS_EB_Address,
|
||
0, 0
|
||
};
|
||
|
||
// FORWARD DECLARATIONS
|
||
//
|
||
HRESULT
|
||
DeleteRemotePortMappingEntry(
|
||
SADLG *pDlg,
|
||
SAPM * pPortMapping
|
||
);
|
||
|
||
VOID
|
||
FreePortMappingEntry(
|
||
SAPM *pPortMapping );
|
||
|
||
VOID
|
||
FreeSharingAndFirewallSettings(
|
||
SADLG* pDlg );
|
||
|
||
HRESULT
|
||
LoadPortMappingEntry(
|
||
IHNetPortMappingBinding *pBinding,
|
||
SADLG* pDlg,
|
||
SAPM **ppPortMapping );
|
||
|
||
HRESULT
|
||
LoadRemotePortMappingEntry (
|
||
IDispatch * pDisp,
|
||
/* SADLG* pDlg, */
|
||
SAPM **ppPortMapping );
|
||
|
||
HRESULT
|
||
LoadSharingAndFirewallSettings(
|
||
SADLG* pDlg );
|
||
|
||
VOID
|
||
SasApply(
|
||
SADLG* pDlg );
|
||
|
||
LVXDRAWINFO*
|
||
SasLvxCallback(
|
||
HWND hwndLv,
|
||
DWORD dwItem );
|
||
|
||
INT_PTR CALLBACK
|
||
SasSrvDlgProc(
|
||
HWND hwnd,
|
||
UINT unMsg,
|
||
WPARAM wparam,
|
||
LPARAM lparam );
|
||
|
||
HRESULT
|
||
SavePortMappingEntry(
|
||
SADLG *pDlg,
|
||
SAPM *pPortMapping );
|
||
|
||
BOOL
|
||
SharedAccessPortMappingDlg(
|
||
IN HWND hwndOwner,
|
||
IN OUT SAPM** PortMapping );
|
||
|
||
INT_PTR CALLBACK
|
||
SspDlgProc(
|
||
IN HWND hwnd,
|
||
IN UINT unMsg,
|
||
IN WPARAM wparam,
|
||
IN LPARAM lparam );
|
||
|
||
VOID
|
||
SrvAddOrEditEntry(
|
||
SADLG* pDlg,
|
||
LONG iItem,
|
||
SAPM* PortMapping );
|
||
|
||
BOOL
|
||
SrvCommand(
|
||
IN SADLG* pDlg,
|
||
IN WORD wNotification,
|
||
IN WORD wId,
|
||
IN HWND hwndCtrl );
|
||
|
||
BOOL
|
||
SrvConflictDetected(
|
||
SADLG* pDlg,
|
||
SAPM* PortMapping );
|
||
|
||
BOOL
|
||
SrvInit(
|
||
HWND hwndPage,
|
||
SADLG* pDlg );
|
||
|
||
#define WM_PRIVATE_CANCEL 0x8000
|
||
|
||
VOID
|
||
SrvUpdateButtons(
|
||
SADLG* pDlg,
|
||
BOOL fAddDelete,
|
||
LONG iSetCheckItem );
|
||
|
||
|
||
|
||
void DisplayError (HWND hwnd, int idError, int idTitle)
|
||
{
|
||
TCHAR* pszError = PszFromId (g_hinstDll, idError);
|
||
if (pszError) {
|
||
TCHAR* pszTitle = PszFromId (g_hinstDll, idTitle);
|
||
if (pszTitle) {
|
||
MessageBox (hwnd,
|
||
pszError, pszTitle,
|
||
MB_OK | MB_ICONERROR | MB_APPLMODAL);
|
||
Free (pszTitle);
|
||
}
|
||
Free (pszError);
|
||
}
|
||
}
|
||
|
||
BOOL APIENTRY
|
||
HNetSharedAccessSettingsDlg(
|
||
BOOL fSharedAccessMode,
|
||
HWND hwndOwner )
|
||
|
||
// Displays the shared access settings property-sheet.
|
||
// On input, 'hwndOwner' indicates the window of the caller,
|
||
// with respect to which we offset the displayed property-sheet.
|
||
//
|
||
{
|
||
HRESULT hr;
|
||
IHNetCfgMgr *pHNetCfgMgr;
|
||
BOOL fComInitialized = FALSE;
|
||
BOOL fModified = FALSE;
|
||
|
||
TRACE("HNetSharedAccessSettingsDlg");
|
||
|
||
//
|
||
// Make sure COM is initialized on this thread
|
||
//
|
||
|
||
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
fComInitialized = TRUE;
|
||
}
|
||
else if (RPC_E_CHANGED_MODE == hr)
|
||
{
|
||
hr = S_OK;
|
||
}
|
||
|
||
//
|
||
// Create the HNetCfgMgr
|
||
//
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = CoCreateInstance(
|
||
CLSID_HNetCfgMgr,
|
||
NULL,
|
||
CLSCTX_ALL,
|
||
IID_IHNetCfgMgr,
|
||
(VOID**) &pHNetCfgMgr
|
||
);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
fModified = HNetSharingAndFirewallSettingsDlg(
|
||
hwndOwner,
|
||
pHNetCfgMgr,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
|
||
pHNetCfgMgr->Release();
|
||
}
|
||
}
|
||
|
||
if (TRUE == fComInitialized)
|
||
{
|
||
CoUninitialize();
|
||
}
|
||
|
||
return fModified;
|
||
}
|
||
|
||
int CALLBACK
|
||
UnHelpCallbackFunc(
|
||
IN HWND hwndDlg,
|
||
IN UINT unMsg,
|
||
IN LPARAM lparam )
|
||
|
||
// A standard Win32 commctrl PropSheetProc. See MSDN documentation.
|
||
//
|
||
// Returns 0 always.
|
||
//
|
||
{
|
||
TRACE2( "UnHelpCallbackFunc(m=%d,l=%08x)",unMsg, lparam );
|
||
|
||
if (unMsg == PSCB_PRECREATE)
|
||
{
|
||
extern BOOL g_fNoWinHelp;
|
||
|
||
// Turn off context help button if WinHelp won't work. See
|
||
// common\uiutil\ui.c.
|
||
//
|
||
if (g_fNoWinHelp)
|
||
{
|
||
DLGTEMPLATE* pDlg = (DLGTEMPLATE* )lparam;
|
||
pDlg->style &= ~(DS_CONTEXTHELP);
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
HRESULT APIENTRY HNetGetSharingServicesPage (IUPnPService * pUPS, PROPSHEETPAGE * psp)
|
||
{
|
||
// _asm int 3
|
||
|
||
if (!pUPS) return E_INVALIDARG;
|
||
if (!psp) return E_INVALIDARG;
|
||
|
||
// psp->dwSize muust be filled out by caller!
|
||
if (psp->dwSize == 0)
|
||
return E_INVALIDARG;
|
||
|
||
SADLG* pDlg = (SADLG*)Malloc(sizeof(*pDlg));
|
||
if (!pDlg)
|
||
return E_OUTOFMEMORY;
|
||
|
||
ZeroMemory(pDlg, sizeof(*pDlg));
|
||
pDlg->hwndOwner = (HWND)psp->lParam; // double-secret place to hang the owning window
|
||
pDlg->pUPS = pUPS;
|
||
pUPS->AddRef();
|
||
InitializeListHead(&pDlg->PortMappings);
|
||
|
||
HRESULT hr = LoadSharingAndFirewallSettings(pDlg);
|
||
if (SUCCEEDED(hr)) {
|
||
// use the size we're given
|
||
DWORD dwSize = psp->dwSize;
|
||
ZeroMemory (psp, dwSize); // double-secret place gets wiped here
|
||
psp->dwSize = dwSize;
|
||
|
||
psp->hInstance = g_hinstDll;
|
||
psp->pszTemplate = MAKEINTRESOURCE(PID_SS_SharedAccessServices);
|
||
psp->pfnDlgProc = SasSrvDlgProc;
|
||
psp->lParam = (LPARAM)pDlg;
|
||
} else {
|
||
FreeSharingAndFirewallSettings(pDlg);
|
||
Free(pDlg);
|
||
}
|
||
return hr;
|
||
}
|
||
|
||
HRESULT APIENTRY HNetFreeSharingServicesPage (PROPSHEETPAGE * psp)
|
||
{ // this must be called if and only if the psp has not been displayed
|
||
|
||
// NOTE: these tests are not definitive!!!
|
||
if (IsBadReadPtr ((void*)psp->lParam, sizeof(SADLG)))
|
||
return E_UNEXPECTED;
|
||
|
||
SADLG * pDlg = (SADLG *)psp->lParam;
|
||
if (pDlg->pUPS == NULL)
|
||
return E_UNEXPECTED;
|
||
|
||
// TODO: should I walk the heap?
|
||
|
||
FreeSharingAndFirewallSettings(pDlg);
|
||
Free(pDlg);
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
BOOL
|
||
APIENTRY
|
||
HNetSharingAndFirewallSettingsDlg(
|
||
IN HWND hwndOwner,
|
||
IN IHNetCfgMgr *pHNetCfgMgr,
|
||
IN BOOL fShowFwOnlySettings,
|
||
IN OPTIONAL IHNetConnection *pHNetConn )
|
||
|
||
// Displays the shared access settings property-sheet.
|
||
// On input, 'hwndOwner' indicates the window of the caller,
|
||
// with respect to which we offset the displayed property-sheet.
|
||
//
|
||
{
|
||
// _asm int 3
|
||
|
||
DWORD dwErr;
|
||
BOOL fModified = FALSE;
|
||
SADLG* pDlg;
|
||
PROPSHEETHEADER psh;
|
||
PROPSHEETPAGE psp[SAPAGE_PageCount];
|
||
TCHAR* pszCaption;
|
||
CFirewallLoggingDialog FirewallLoggingDialog = {0};
|
||
CICMPSettingsDialog ICMPSettingsDialog = {0};
|
||
HRESULT hr;
|
||
HRESULT hFirewallLoggingResult = E_FAIL;
|
||
HRESULT hICMPSettingsResult = E_FAIL;
|
||
|
||
TRACE("HNetSharingAndFirewallSettingsDlg");
|
||
|
||
// Allocate and initialize the property-sheet's context block,
|
||
// and read into it the current shared access settings.
|
||
//
|
||
pDlg = (SADLG*)Malloc(sizeof(*pDlg));
|
||
if (!pDlg) { return FALSE; }
|
||
|
||
ZeroMemory(pDlg, sizeof(*pDlg));
|
||
pDlg->hwndOwner = hwndOwner;
|
||
pDlg->pHNetCfgMgr = pHNetCfgMgr;
|
||
pDlg->pHNetConn = pHNetConn;
|
||
InitializeListHead(&pDlg->PortMappings);
|
||
|
||
hr = LoadSharingAndFirewallSettings(pDlg);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
// Construct the property sheet.
|
||
// We use a single DlgProc for both our pages, and distinguish the pages
|
||
// by setting the applications page's 'lParam' to contain the shared
|
||
// context-block.
|
||
// (See the 'WM_INITDIALOG' handling in 'SasDlgProc'.)
|
||
//
|
||
int nPages = 0;
|
||
ZeroMemory(psp, sizeof(psp));
|
||
ZeroMemory(&psh, sizeof(psh));
|
||
|
||
if(NULL != pHNetConn && fShowFwOnlySettings)
|
||
{
|
||
hFirewallLoggingResult = CFirewallLoggingDialog_Init(&FirewallLoggingDialog, pHNetCfgMgr);
|
||
hICMPSettingsResult = CICMPSettingsDialog_Init(&ICMPSettingsDialog, pHNetConn);
|
||
}
|
||
|
||
if(NULL != pHNetConn)
|
||
{
|
||
psp[nPages].dwSize = sizeof(PROPSHEETPAGE);
|
||
psp[nPages].hInstance = g_hinstDll;
|
||
psp[nPages].pszTemplate =
|
||
MAKEINTRESOURCE(PID_SS_SharedAccessServices);
|
||
psp[nPages].pfnDlgProc = SasSrvDlgProc;
|
||
psp[nPages].lParam = (LPARAM)pDlg;
|
||
nPages++;
|
||
}
|
||
|
||
if(SUCCEEDED(hFirewallLoggingResult))
|
||
{
|
||
psp[nPages].dwSize = sizeof(PROPSHEETPAGE);
|
||
psp[nPages].hInstance = g_hinstDll;
|
||
psp[nPages].pszTemplate =
|
||
MAKEINTRESOURCE(PID_FW_FirewallLogging);
|
||
psp[nPages].pfnDlgProc = CFirewallLoggingDialog_StaticDlgProc;
|
||
psp[nPages].lParam = (LPARAM)&FirewallLoggingDialog;
|
||
nPages++;
|
||
}
|
||
|
||
if(SUCCEEDED(hICMPSettingsResult))
|
||
{
|
||
psp[nPages].dwSize = sizeof(PROPSHEETPAGE);
|
||
psp[nPages].hInstance = g_hinstDll;
|
||
psp[nPages].pszTemplate =
|
||
MAKEINTRESOURCE(PID_FW_ICMP);
|
||
psp[nPages].pfnDlgProc = CICMPSettingsDialog_StaticDlgProc;
|
||
psp[nPages].lParam = (LPARAM)&ICMPSettingsDialog;
|
||
nPages++;
|
||
}
|
||
|
||
psh.dwSize = sizeof(PROPSHEETHEADER);
|
||
psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW | PSH_USECALLBACK;
|
||
psh.hInstance = g_hinstDll;
|
||
psh.nPages = nPages;
|
||
psh.hwndParent = hwndOwner;
|
||
psh.ppsp = (LPCPROPSHEETPAGE)psp;
|
||
pszCaption = pHNetConn
|
||
? PszFromId(g_hinstDll, SID_SharedAccessSettings)
|
||
: PszFromId(g_hinstDll, SID_NetworkApplicationSettings);
|
||
psh.pszCaption = (pszCaption ? pszCaption : c_szEmpty);
|
||
psh.pfnCallback = UnHelpCallbackFunc;
|
||
|
||
if (PropertySheet(&psh) == -1)
|
||
{
|
||
dwErr = GetLastError();
|
||
TRACE1("SharedAccessSettingsDlg: PropertySheet=%d", dwErr);
|
||
SasErrorDlg(hwndOwner, SID_OP_LoadDlg, dwErr, NULL);
|
||
}
|
||
fModified = pDlg->fModified;
|
||
Free0(pszCaption); // REVIEW is this right
|
||
|
||
if(SUCCEEDED(hICMPSettingsResult))
|
||
{
|
||
CICMPSettingsDialog_FinalRelease(&ICMPSettingsDialog);
|
||
}
|
||
|
||
if(SUCCEEDED(hFirewallLoggingResult))
|
||
{
|
||
CFirewallLoggingDialog_FinalRelease(&FirewallLoggingDialog);
|
||
}
|
||
|
||
FreeSharingAndFirewallSettings(pDlg);
|
||
}
|
||
Free(pDlg);
|
||
return fModified;
|
||
}
|
||
|
||
VOID
|
||
FreePortMappingEntry(
|
||
SAPM *pPortMapping )
|
||
|
||
{
|
||
ASSERT(NULL != pPortMapping);
|
||
|
||
if (NULL != pPortMapping->pProtocol)
|
||
{
|
||
pPortMapping->pProtocol->Release();
|
||
}
|
||
|
||
if (NULL != pPortMapping->pBinding)
|
||
{
|
||
pPortMapping->pBinding->Release();
|
||
}
|
||
|
||
if (pPortMapping->pSPM)
|
||
pPortMapping->pSPM->Release();
|
||
|
||
Free0(pPortMapping->Title);
|
||
Free0(pPortMapping->InternalName);
|
||
|
||
Free(pPortMapping);
|
||
}
|
||
|
||
VOID
|
||
FreeSharingAndFirewallSettings(
|
||
SADLG* pDlg )
|
||
|
||
// Frees all sharing and firewall settings
|
||
//
|
||
|
||
{
|
||
PLIST_ENTRY pLink;
|
||
SAPM *pPortMapping;
|
||
|
||
ASSERT(pDlg);
|
||
|
||
//
|
||
// Free port-mapping entries
|
||
//
|
||
|
||
while (!IsListEmpty(&pDlg->PortMappings))
|
||
{
|
||
pLink = RemoveHeadList(&pDlg->PortMappings);
|
||
pPortMapping = CONTAINING_RECORD(pLink, SAPM, Link);
|
||
ASSERT(pPortMapping);
|
||
|
||
FreePortMappingEntry(pPortMapping);
|
||
}
|
||
|
||
//
|
||
// Free computer name
|
||
//
|
||
|
||
Free0(pDlg->ComputerName);
|
||
|
||
if (pDlg->pUPS) {
|
||
pDlg->pUPS->Release();
|
||
pDlg->pUPS = NULL;
|
||
}
|
||
}
|
||
|
||
#define NAT_API_ENTER
|
||
#define NAT_API_LEAVE
|
||
#include "natutils.h"
|
||
#include "sprtmapc.h"
|
||
HRESULT GetCollectionFromService (IUPnPService * pUPS, IStaticPortMappingCollection ** ppSPMC)
|
||
{
|
||
CComObject<CStaticPortMappingCollection> * pC = NULL;
|
||
HRESULT hr = CComObject<CStaticPortMappingCollection>::CreateInstance (&pC);
|
||
if (pC) {
|
||
pC->AddRef();
|
||
// init
|
||
hr = pC->Initialize (pUPS);
|
||
if (SUCCEEDED(hr))
|
||
hr = pC->QueryInterface (__uuidof(IStaticPortMappingCollection), (void**)ppSPMC);
|
||
pC->Release();
|
||
}
|
||
return hr;
|
||
}
|
||
|
||
HRESULT GetStaticPortMappingCollection (
|
||
SADLG* pDlg,
|
||
IStaticPortMappingCollection ** ppSPMC)
|
||
{
|
||
_ASSERT (pDlg);
|
||
_ASSERT (pDlg->pUPS);
|
||
_ASSERT (ppSPMC);
|
||
|
||
*ppSPMC = NULL;
|
||
|
||
return GetCollectionFromService (pDlg->pUPS, ppSPMC);
|
||
}
|
||
|
||
HRESULT
|
||
LoadRemotePortMappingEntry (IDispatch * pDisp, /* SADLG* pDlg, */ SAPM **ppPortMapping )
|
||
{ // NOTE: may need pDlg to get computer name if loopback
|
||
|
||
*ppPortMapping = NULL;
|
||
|
||
SAPM *pMapping = (SAPM*)Malloc(sizeof(*pMapping));
|
||
if (!pMapping)
|
||
return E_OUTOFMEMORY;
|
||
|
||
ZeroMemory(pMapping, sizeof(*pMapping));
|
||
InitializeListHead(&pMapping->Link);
|
||
|
||
HRESULT hr = pDisp->QueryInterface (__uuidof(IStaticPortMapping),
|
||
(void**)&pMapping->pSPM);
|
||
if (SUCCEEDED(hr)) {
|
||
// get title (description)
|
||
CComBSTR cbDescription;
|
||
hr = pMapping->pSPM->get_Description (&cbDescription);
|
||
if (SUCCEEDED(hr)) {
|
||
// immediately figure out if it's "built-in"
|
||
#define BUILTIN_KEY L" [MICROSOFT]"
|
||
OLECHAR * tmp = wcsstr (cbDescription.m_str, BUILTIN_KEY);
|
||
if (tmp && (tmp[wcslen(BUILTIN_KEY)] == 0)) {
|
||
// if the key exists and is at the end, then it's a built-in mapping
|
||
pMapping->BuiltIn = TRUE;
|
||
*tmp = 0;
|
||
}
|
||
|
||
pMapping->Title = StrDupTFromW (cbDescription);
|
||
if (NULL == pMapping->Title)
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
|
||
if (SUCCEEDED(hr)) {
|
||
// get protocol
|
||
CComBSTR cbProtocol;
|
||
hr = pMapping->pSPM->get_Protocol (&cbProtocol);
|
||
if (SUCCEEDED(hr)) {
|
||
if (!_wcsicmp (L"tcp", cbProtocol))
|
||
pMapping->Protocol = NAT_PROTOCOL_TCP;
|
||
else
|
||
if (!_wcsicmp (L"udp", cbProtocol))
|
||
pMapping->Protocol = NAT_PROTOCOL_UDP;
|
||
else {
|
||
_ASSERT (0 && "bad protocol!?");
|
||
hr = E_UNEXPECTED;
|
||
}
|
||
|
||
if (SUCCEEDED(hr)) {
|
||
// get external port
|
||
long lExternalPort = 0;
|
||
hr = pMapping->pSPM->get_ExternalPort (&lExternalPort);
|
||
if (SUCCEEDED(hr)) {
|
||
_ASSERT (lExternalPort > 0);
|
||
_ASSERT (lExternalPort < 65536);
|
||
pMapping->ExternalPort = ntohs ((USHORT)lExternalPort);
|
||
|
||
// get internal port
|
||
long lInternalPort = 0;
|
||
hr = pMapping->pSPM->get_InternalPort (&lInternalPort);
|
||
if (SUCCEEDED(hr)) {
|
||
_ASSERT (lInternalPort > 0);
|
||
_ASSERT (lInternalPort < 65536);
|
||
pMapping->InternalPort = ntohs ((USHORT)lInternalPort);
|
||
|
||
// get Enabled
|
||
VARIANT_BOOL vb;
|
||
hr = pMapping->pSPM->get_Enabled (&vb);
|
||
if (SUCCEEDED(hr)) {
|
||
pMapping->Enabled = vb == VARIANT_TRUE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (SUCCEEDED(hr)) {
|
||
// lastly, get private IP or host name (hard one)
|
||
// TODO: check for loopback, etc., like in LoadPortMappingEntry code below
|
||
CComBSTR cbInternalClient;
|
||
hr = pMapping->pSPM->get_InternalClient (&cbInternalClient);
|
||
if (SUCCEEDED(hr)) {
|
||
if (!(cbInternalClient == L"0.0.0.0")) {
|
||
pMapping->InternalName = StrDupTFromW (cbInternalClient);
|
||
if (!pMapping->InternalName)
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
*ppPortMapping = pMapping;
|
||
else
|
||
FreePortMappingEntry (pMapping);
|
||
|
||
return hr;
|
||
}
|
||
|
||
HRESULT
|
||
LoadPortMappingEntry(
|
||
IHNetPortMappingBinding *pBinding,
|
||
SADLG* pDlg,
|
||
SAPM **ppPortMapping )
|
||
|
||
{
|
||
HRESULT hr = S_OK;
|
||
IHNetPortMappingProtocol *pProtocol = NULL;
|
||
SAPM *pMapping;
|
||
BOOLEAN fTemp;
|
||
OLECHAR *pwsz;
|
||
|
||
ASSERT(NULL != pBinding);
|
||
ASSERT(NULL != ppPortMapping);
|
||
|
||
pMapping = (SAPM*) Malloc(sizeof(*pMapping));
|
||
|
||
if (NULL != pMapping)
|
||
{
|
||
ZeroMemory(pMapping, sizeof(*pMapping));
|
||
InitializeListHead(&pMapping->Link);
|
||
|
||
hr = pBinding->GetProtocol (&pProtocol);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = pProtocol->GetName (&pwsz);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
pMapping->Title = StrDupTFromW(pwsz);
|
||
if (NULL == pMapping->Title)
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
CoTaskMemFree(pwsz);
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = pProtocol->GetBuiltIn (&fTemp);
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
pMapping->BuiltIn = !!fTemp;
|
||
|
||
hr = pProtocol->GetIPProtocol (&pMapping->Protocol);
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = pProtocol->GetPort (&pMapping->ExternalPort);
|
||
}
|
||
|
||
pMapping->pProtocol = pProtocol;
|
||
pMapping->pProtocol->AddRef();
|
||
pProtocol->Release();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = pBinding->GetTargetPort (&pMapping->InternalPort);
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = pBinding->GetEnabled (&fTemp);
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
pMapping->Enabled = !!fTemp;
|
||
|
||
hr = pBinding->GetCurrentMethod (&fTemp);
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
if (fTemp)
|
||
{
|
||
hr = pBinding->GetTargetComputerName (&pwsz);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
pMapping->InternalName = StrDupTFromW(pwsz);
|
||
if (NULL == pMapping->InternalName)
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
CoTaskMemFree(pwsz);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ULONG ulAddress;
|
||
|
||
hr = pBinding->GetTargetComputerAddress (&ulAddress);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
if (LOOPBACK_ADDR == ulAddress)
|
||
{
|
||
//
|
||
// The mapping is directed at this machine, so
|
||
// replace the loopback address with our
|
||
// machine name
|
||
//
|
||
|
||
pMapping->InternalName = _StrDup(pDlg->ComputerName);
|
||
if (NULL == pMapping->InternalName)
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
}
|
||
else if (0 != ulAddress)
|
||
{
|
||
pMapping->InternalName =
|
||
(LPTSTR) Malloc(16 * sizeof(TCHAR));
|
||
|
||
if (NULL != pMapping->InternalName)
|
||
{
|
||
IpHostAddrToPsz(
|
||
NTOHL(ulAddress),
|
||
pMapping->InternalName
|
||
);
|
||
}
|
||
else
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = S_OK;
|
||
pMapping->pBinding = pBinding;
|
||
pMapping->pBinding->AddRef();
|
||
*ppPortMapping = pMapping;
|
||
}
|
||
else if (NULL != pMapping)
|
||
{
|
||
FreePortMappingEntry(pMapping);
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
class CWaitDialog
|
||
{
|
||
public:
|
||
struct SWaitDialog
|
||
{
|
||
HWND hwndOwner;
|
||
private:
|
||
CComAutoCriticalSection m_acs;
|
||
HWND m_hwndDlg;
|
||
public:
|
||
SWaitDialog (HWND hwnd)
|
||
{
|
||
hwndOwner = hwnd;
|
||
m_hwndDlg = NULL;
|
||
}
|
||
void SetWindow (HWND hwnd)
|
||
{
|
||
m_acs.Lock();
|
||
if (m_hwndDlg == NULL)
|
||
m_hwndDlg = hwnd;
|
||
m_acs.Unlock();
|
||
}
|
||
HWND GetWindow () { return m_hwndDlg; }
|
||
};
|
||
private:
|
||
SWaitDialog * m_pwd;
|
||
public:
|
||
CWaitDialog (HWND hwndOwner)
|
||
{
|
||
m_pwd = new SWaitDialog (hwndOwner);
|
||
if (m_pwd) {
|
||
// create thread
|
||
DWORD ThreadId = NULL;
|
||
CloseHandle (CreateThread (NULL, 0,
|
||
CWaitDialog::ThreadProc,
|
||
(void*)m_pwd,
|
||
0, &ThreadId));
|
||
}
|
||
}
|
||
~CWaitDialog ()
|
||
{
|
||
if (m_pwd) {
|
||
HWND hwnd = m_pwd->GetWindow();
|
||
m_pwd->SetWindow ((HWND)INVALID_HANDLE_VALUE);
|
||
if (hwnd != NULL)
|
||
EndDialog (hwnd, 1);
|
||
}
|
||
}
|
||
static DWORD WINAPI ThreadProc (VOID *pVoid)
|
||
{
|
||
SWaitDialog * pWD = (SWaitDialog *)pVoid;
|
||
EnableWindow (pWD->hwndOwner, FALSE);
|
||
DialogBoxParam (g_hinstDll,
|
||
MAKEINTRESOURCE(PID_SS_PleaseWait),
|
||
pWD->hwndOwner,
|
||
CWaitDialog::DlgProc,
|
||
(LPARAM)pWD);
|
||
EnableWindow (pWD->hwndOwner, TRUE);
|
||
delete pWD;
|
||
return 1;
|
||
}
|
||
static INT_PTR CALLBACK DlgProc (HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam)
|
||
{
|
||
switch (uMsg) {
|
||
case WM_INITDIALOG:
|
||
{
|
||
// hang onto my data
|
||
SWaitDialog * pWD = (SWaitDialog *)lparam;
|
||
SetWindowLongPtr (hwnd, DWLP_USER, (LONG_PTR)pWD);
|
||
|
||
// center window on owner
|
||
CenterWindow (hwnd, pWD->hwndOwner);
|
||
|
||
// fill out dlg's hwnd
|
||
pWD->SetWindow (hwnd);
|
||
if (pWD->GetWindow() == INVALID_HANDLE_VALUE) // already destructed!
|
||
PostMessage (hwnd, 0x8000, 0, 0L);
|
||
return TRUE;
|
||
}
|
||
case WM_PAINT:
|
||
{
|
||
SWaitDialog * pWD = (SWaitDialog *)GetWindowLongPtr (hwnd, DWLP_USER);
|
||
if (pWD->GetWindow() == INVALID_HANDLE_VALUE) // already destructed!
|
||
PostMessage (hwnd, 0x8000, 0, 0L);
|
||
break;
|
||
}
|
||
case 0x8000:
|
||
EndDialog (hwnd, 1);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
};
|
||
|
||
HRESULT
|
||
LoadSharingAndFirewallSettings(
|
||
SADLG* pDlg )
|
||
|
||
{
|
||
CWaitDialog wd(pDlg->hwndOwner); // may be NULL
|
||
|
||
HRESULT hr = S_OK;
|
||
IHNetProtocolSettings *pProtSettings;
|
||
ULONG ulCount;
|
||
DWORD dwError;
|
||
|
||
ASSERT(pDlg);
|
||
|
||
//
|
||
// Load the name of the computer
|
||
//
|
||
|
||
#ifndef DOWNLEVEL_CLIENT // downlevel client doesn't have this call
|
||
ulCount = 0;
|
||
if (!GetComputerNameEx(ComputerNameDnsHostname, NULL, &ulCount))
|
||
{
|
||
dwError = GetLastError();
|
||
|
||
if (ERROR_MORE_DATA == dwError)
|
||
{
|
||
pDlg->ComputerName = (TCHAR*) Malloc(ulCount * sizeof(TCHAR));
|
||
if (NULL != pDlg->ComputerName)
|
||
{
|
||
if (!GetComputerNameEx(
|
||
ComputerNameDnsHostname,
|
||
pDlg->ComputerName,
|
||
&ulCount
|
||
))
|
||
{
|
||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
}
|
||
}
|
||
else
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
hr = HRESULT_FROM_WIN32(dwError);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Since we didn't pass in a buffer, this should never happen.
|
||
//
|
||
|
||
ASSERT(FALSE);
|
||
hr = E_UNEXPECTED;
|
||
}
|
||
if (FAILED(hr))
|
||
return hr;
|
||
#else
|
||
// downlevel client version
|
||
TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1];
|
||
DWORD dwSize = MAX_COMPUTERNAME_LENGTH+1;
|
||
if (!GetComputerName (szComputerName, &dwSize))
|
||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
else {
|
||
pDlg->ComputerName = _StrDup (szComputerName);
|
||
if (!pDlg->ComputerName)
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
#endif
|
||
|
||
// do downlevel and remote case here
|
||
if (pDlg->pUPS) {
|
||
CComPtr<IStaticPortMappingCollection> spSPMC = NULL;
|
||
hr = GetCollectionFromService (pDlg->pUPS, &spSPMC);
|
||
if (spSPMC) {
|
||
CComPtr<IEnumVARIANT> spEV = NULL;
|
||
|
||
CComPtr<IUnknown> spunk = NULL;
|
||
hr = spSPMC->get__NewEnum (&spunk);
|
||
if (spunk)
|
||
hr = spunk->QueryInterface (
|
||
__uuidof(IEnumVARIANT),
|
||
(void**)&spEV);
|
||
if (spEV) {
|
||
CComVariant cv;
|
||
while (S_OK == spEV->Next (1, &cv, NULL)) {
|
||
if (V_VT (&cv) == VT_DISPATCH) {
|
||
SAPM *pSAPortMap = NULL;
|
||
hr = LoadRemotePortMappingEntry (V_DISPATCH (&cv), /* pDlg, */ &pSAPortMap);
|
||
if (SUCCEEDED(hr))
|
||
InsertTailList(&pDlg->PortMappings, &pSAPortMap->Link);
|
||
}
|
||
cv.Clear();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// do stuff below iff not remote
|
||
if (NULL != pDlg->pHNetConn)
|
||
{
|
||
IEnumHNetPortMappingBindings *pEnumBindings = NULL;
|
||
|
||
//
|
||
// Load port-mapping settings
|
||
//
|
||
|
||
hr = pDlg->pHNetConn->EnumPortMappings (FALSE, &pEnumBindings);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
IHNetPortMappingBinding *pBinding;
|
||
|
||
do
|
||
{
|
||
hr = pEnumBindings->Next (1, &pBinding, &ulCount);
|
||
|
||
if (SUCCEEDED(hr) && 1 == ulCount)
|
||
{
|
||
SAPM *pSAPortMap;
|
||
|
||
hr = LoadPortMappingEntry(pBinding, pDlg, &pSAPortMap);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
InsertTailList(&pDlg->PortMappings, &pSAPortMap->Link);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Even though an error occured for this entry we'll
|
||
// keep on going -- this allows the UI to show up.
|
||
//
|
||
|
||
hr = S_OK;
|
||
}
|
||
|
||
pBinding->Release();
|
||
}
|
||
|
||
} while (SUCCEEDED(hr) && 1 == ulCount);
|
||
|
||
pEnumBindings->Release();
|
||
}
|
||
}
|
||
return hr;
|
||
}
|
||
|
||
extern BOOL IsICSHost (); // in upnpnat.cpp
|
||
VOID
|
||
SasApply(
|
||
SADLG* pDlg )
|
||
|
||
// Called to save all changes made in the property sheet.
|
||
//
|
||
{
|
||
if (!pDlg->fModified)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (pDlg->hwndServers)
|
||
{
|
||
SAPM* pPortMapping;
|
||
#if DBG
|
||
LONG i = -1;
|
||
while ((i = ListView_GetNextItem(pDlg->hwndServers, i, LVNI_ALL))
|
||
>= 0)
|
||
{
|
||
pPortMapping = (SAPM*)ListView_GetParamPtr(pDlg->hwndServers, i);
|
||
ASSERT(pPortMapping->Enabled == ListView_GetCheck(pDlg->hwndServers, i));
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Commit modified port-mapping entries. Since entries marked
|
||
// for deletion were placed at the front of the port-mapping
|
||
// list there's no chance of having a new or modified entry
|
||
// conflicting with a deleted entry.
|
||
//
|
||
|
||
HRESULT hr = S_OK;
|
||
|
||
PLIST_ENTRY Link;
|
||
for (Link = pDlg->PortMappings.Flink;
|
||
Link != &pDlg->PortMappings; Link = Link->Flink)
|
||
{
|
||
pPortMapping = CONTAINING_RECORD(Link, SAPM, Link);
|
||
|
||
if (pPortMapping->fDeleted)
|
||
{
|
||
Link = Link->Blink;
|
||
RemoveEntryList(&pPortMapping->Link);
|
||
|
||
if(NULL != pPortMapping->pProtocol)
|
||
{
|
||
pPortMapping->pProtocol->Delete();
|
||
}
|
||
else if (pPortMapping->pSPM)
|
||
{
|
||
HRESULT hr = DeleteRemotePortMappingEntry (pDlg, pPortMapping);
|
||
if (FAILED(hr)) {
|
||
// TODO: should I pop up some UI?
|
||
}
|
||
}
|
||
|
||
FreePortMappingEntry(pPortMapping);
|
||
}
|
||
else if (pPortMapping->fProtocolModified
|
||
|| pPortMapping->fBindingModified
|
||
|| pPortMapping->fNewEntry)
|
||
{
|
||
HRESULT hr2 = SavePortMappingEntry(pDlg, pPortMapping);
|
||
if (SUCCEEDED(hr2))
|
||
{
|
||
pPortMapping->fProtocolModified = FALSE;
|
||
pPortMapping->fBindingModified = FALSE;
|
||
pPortMapping->fNewEntry = FALSE;
|
||
} else {
|
||
if (SUCCEEDED(hr))
|
||
hr = hr2; // grab first error
|
||
}
|
||
}
|
||
}
|
||
if (FAILED(hr)) {
|
||
if (pDlg->pUPS && !IsICSHost ())
|
||
DisplayError (pDlg->hwndDlg,
|
||
SID_OP_TheirGatewayError,
|
||
SID_PopupTitle);
|
||
else
|
||
DisplayError (pDlg->hwndDlg,
|
||
SID_OP_GenericPortMappingError,
|
||
SID_PopupTitle);
|
||
}
|
||
}
|
||
}
|
||
|
||
INT_PTR CALLBACK
|
||
SasSrvDlgProc(
|
||
HWND hwnd,
|
||
UINT unMsg,
|
||
WPARAM wparam,
|
||
LPARAM lparam )
|
||
|
||
// Called to handle messages for the 'Services' pages.
|
||
//
|
||
{
|
||
// Give the extended list-control a chance to look at all messages first.
|
||
//
|
||
if (ListView_OwnerHandler(hwnd, unMsg, wparam, lparam, SasLvxCallback))
|
||
{
|
||
return TRUE;
|
||
}
|
||
switch (unMsg)
|
||
{
|
||
case WM_INITDIALOG:
|
||
{
|
||
SADLG* pDlg = (SADLG*)((PROPSHEETPAGE*)lparam)->lParam;
|
||
return SrvInit(hwnd, pDlg);
|
||
}
|
||
case WM_PRIVATE_CANCEL:
|
||
{
|
||
SADLG* pDlg = SasContext(hwnd);
|
||
PostMessage (pDlg->hwndDlg, PSM_PRESSBUTTON, PSBTN_CANCEL, 0L);
|
||
return TRUE;
|
||
}
|
||
|
||
case WM_HELP:
|
||
case WM_CONTEXTMENU:
|
||
{
|
||
SADLG* pDlg = SasContext(hwnd);
|
||
ContextHelp(g_adwSrvHelp, hwnd, unMsg, wparam, lparam);
|
||
break;
|
||
}
|
||
|
||
case WM_COMMAND:
|
||
{
|
||
SADLG* pDlg = SasContext(hwnd);
|
||
return SrvCommand(
|
||
pDlg, HIWORD(wparam), LOWORD(wparam), (HWND)lparam);
|
||
}
|
||
|
||
case WM_NOTIFY:
|
||
{
|
||
SADLG* pDlg = SasContext(hwnd);
|
||
switch (((NMHDR*)lparam)->code)
|
||
{
|
||
case PSN_APPLY:
|
||
{
|
||
SasApply(pDlg);
|
||
return TRUE;
|
||
}
|
||
|
||
case NM_DBLCLK:
|
||
{
|
||
SendMessage(
|
||
GetDlgItem(hwnd, CID_SS_PB_Edit), BM_CLICK, 0, 0);
|
||
return TRUE;
|
||
}
|
||
|
||
case LVXN_SETCHECK:
|
||
{
|
||
pDlg->fModified = TRUE;
|
||
SrvUpdateButtons(
|
||
pDlg, FALSE, ((NM_LISTVIEW*)lparam)->iItem);
|
||
return TRUE;
|
||
}
|
||
|
||
case LVN_ITEMCHANGED:
|
||
{
|
||
if ((((NM_LISTVIEW*)lparam)->uNewState & LVIS_SELECTED)
|
||
!= (((NM_LISTVIEW*)lparam)->uOldState & LVIS_SELECTED))
|
||
{
|
||
SrvUpdateButtons(
|
||
pDlg, FALSE, ((NM_LISTVIEW*)lparam)->iItem);
|
||
}
|
||
return TRUE;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL
|
||
SasInit(
|
||
HWND hwndPage,
|
||
SADLG* pDlg )
|
||
|
||
// Called to initialize the settings property sheet.
|
||
// Sets the window-property in which the shared context-block is stored,
|
||
// and records the dialog's window-handle.
|
||
//
|
||
{
|
||
HWND hwndDlg = GetParent(hwndPage);
|
||
if (!SetProp(hwndDlg, _T("HNETCFG_SADLG"), pDlg))
|
||
{
|
||
return FALSE;
|
||
}
|
||
pDlg->hwndDlg = hwndDlg;
|
||
return TRUE;
|
||
}
|
||
|
||
LVXDRAWINFO*
|
||
SasLvxCallback(
|
||
HWND hwndLv,
|
||
DWORD dwItem )
|
||
|
||
// Callback for extended list-controls on the 'Applications' and 'Services'
|
||
// pages.
|
||
//
|
||
{
|
||
static LVXDRAWINFO info = { 1, 0, LVXDI_DxFill, { LVXDIA_Static } };
|
||
return &info;
|
||
}
|
||
|
||
HRESULT DeleteRemotePortMappingEntry (SADLG *pDlg, SAPM * pPortMapping)
|
||
{
|
||
_ASSERT (pPortMapping);
|
||
_ASSERT (!pPortMapping->pProtocol);
|
||
_ASSERT (!pPortMapping->pBinding);
|
||
_ASSERT (pPortMapping->pSPM);
|
||
|
||
// don't use value in pPortMapping struct: they could have been edited.
|
||
long lExternalPort = 0;
|
||
HRESULT hr = pPortMapping->pSPM->get_ExternalPort (&lExternalPort);
|
||
if (SUCCEEDED(hr)) {
|
||
CComBSTR cbProtocol;
|
||
hr = pPortMapping->pSPM->get_Protocol (&cbProtocol);
|
||
if (SUCCEEDED(hr)) {
|
||
|
||
// get IStaticPortMappings interface (collection has Remove method)
|
||
CComPtr<IStaticPortMappingCollection> spSPMC = NULL;
|
||
hr = GetStaticPortMappingCollection (pDlg, &spSPMC);
|
||
if (spSPMC)
|
||
hr = spSPMC->Remove (lExternalPort, cbProtocol);
|
||
}
|
||
}
|
||
return hr;
|
||
}
|
||
|
||
HRESULT
|
||
SaveRemotePortMappingEntry(
|
||
SADLG *pDlg,
|
||
SAPM *pPortMapping )
|
||
{
|
||
_ASSERT (pPortMapping);
|
||
_ASSERT (!pPortMapping->pProtocol);
|
||
_ASSERT (!pPortMapping->pBinding);
|
||
_ASSERT (pDlg->pUPS); // either remote or downlevel
|
||
|
||
USES_CONVERSION;
|
||
|
||
HRESULT hr = S_OK;
|
||
|
||
// common params
|
||
long lExternalPort = htons (pPortMapping->ExternalPort);
|
||
long lInternalPort = htons (pPortMapping->InternalPort);
|
||
CComBSTR cbClientIPorDNS = T2OLE(pPortMapping->InternalName);
|
||
CComBSTR cbDescription = T2OLE(pPortMapping->Title);
|
||
CComBSTR cbProtocol;
|
||
if (pPortMapping->Protocol == NAT_PROTOCOL_TCP)
|
||
cbProtocol = L"TCP";
|
||
else
|
||
cbProtocol = L"UDP";
|
||
|
||
if (NULL == pPortMapping->pSPM) {
|
||
// brand-new entry:
|
||
// delete dup if any
|
||
// add new entry
|
||
|
||
CComPtr<IStaticPortMappingCollection> spSPMC = NULL;
|
||
hr = GetStaticPortMappingCollection (pDlg, &spSPMC);
|
||
if (spSPMC) {
|
||
spSPMC->Remove (lExternalPort, cbProtocol); // just in case
|
||
hr = spSPMC->Add (lExternalPort,
|
||
cbProtocol,
|
||
lInternalPort,
|
||
cbClientIPorDNS,
|
||
pPortMapping->Enabled ? VARIANT_TRUE : VARIANT_FALSE,
|
||
cbDescription,
|
||
&pPortMapping->pSPM);
|
||
}
|
||
return hr;
|
||
}
|
||
|
||
// edited case: check what changed.
|
||
|
||
// if ports or protocol changed,...
|
||
long lOldExternalPort = 0;
|
||
pPortMapping->pSPM->get_ExternalPort (&lOldExternalPort);
|
||
CComBSTR cbOldProtocol;
|
||
pPortMapping->pSPM->get_Protocol (&cbOldProtocol);
|
||
if ((lOldExternalPort != lExternalPort) ||
|
||
(!(cbOldProtocol == cbProtocol))) {
|
||
// ... delete old entry and create new entry
|
||
|
||
CComPtr<IStaticPortMappingCollection> spSPMC = NULL;
|
||
hr = GetStaticPortMappingCollection (pDlg, &spSPMC);
|
||
if (spSPMC)
|
||
hr = spSPMC->Remove (lOldExternalPort, cbOldProtocol);
|
||
|
||
if (SUCCEEDED(hr)) {
|
||
pPortMapping->pSPM->Release();
|
||
pPortMapping->pSPM = NULL;
|
||
|
||
hr = spSPMC->Add (lExternalPort,
|
||
cbProtocol,
|
||
lInternalPort,
|
||
cbClientIPorDNS,
|
||
pPortMapping->Enabled ? VARIANT_TRUE : VARIANT_FALSE,
|
||
cbDescription,
|
||
&pPortMapping->pSPM);
|
||
}
|
||
return hr;
|
||
}
|
||
// else, just edit in place.
|
||
// Note that the client address must be filled out before trying to enable
|
||
|
||
// did the client IP address change?
|
||
CComBSTR cbOldClientIP;
|
||
pPortMapping->pSPM->get_InternalClient (&cbOldClientIP);
|
||
if (!(cbClientIPorDNS == cbOldClientIP)) {
|
||
hr = pPortMapping->pSPM->EditInternalClient (cbClientIPorDNS);
|
||
if (FAILED(hr))
|
||
return hr;
|
||
}
|
||
|
||
// did the internal port change?
|
||
long lOldInternalPort = 0;
|
||
pPortMapping->pSPM->get_InternalPort (&lOldInternalPort);
|
||
if (lOldInternalPort != lInternalPort) {
|
||
hr = pPortMapping->pSPM->EditInternalPort (lInternalPort);
|
||
if (FAILED(hr))
|
||
return hr;
|
||
}
|
||
|
||
// did the enabled flag change?
|
||
VARIANT_BOOL vbEnabled = FALSE;
|
||
pPortMapping->pSPM->get_Enabled (&vbEnabled);
|
||
if (vbEnabled != (pPortMapping->Enabled ? VARIANT_TRUE : VARIANT_FALSE)) {
|
||
hr = pPortMapping->pSPM->Enable (pPortMapping->Enabled ? VARIANT_TRUE : VARIANT_FALSE);
|
||
}
|
||
return hr;
|
||
}
|
||
|
||
HRESULT
|
||
SavePortMappingEntry(
|
||
SADLG *pDlg,
|
||
SAPM *pPortMapping )
|
||
|
||
{
|
||
if (pDlg->pUPS) // remote case
|
||
return SaveRemotePortMappingEntry (pDlg, pPortMapping);
|
||
|
||
HRESULT hr = S_OK;
|
||
OLECHAR *wszTitle;
|
||
|
||
ASSERT(NULL != pDlg);
|
||
ASSERT(NULL != pPortMapping);
|
||
|
||
wszTitle = StrDupWFromT(pPortMapping->Title);
|
||
if (NULL == wszTitle)
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
else if (pPortMapping->fNewEntry)
|
||
{
|
||
IHNetProtocolSettings *pSettings;
|
||
|
||
ASSERT(NULL == pPortMapping->pProtocol);
|
||
ASSERT(NULL == pPortMapping->pBinding);
|
||
|
||
hr = pDlg->pHNetCfgMgr->QueryInterface (IID_IHNetProtocolSettings,
|
||
(void**)&pSettings);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = pSettings->CreatePortMappingProtocol(
|
||
wszTitle,
|
||
pPortMapping->Protocol,
|
||
pPortMapping->ExternalPort,
|
||
&pPortMapping->pProtocol
|
||
);
|
||
|
||
pSettings->Release();
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = pDlg->pHNetConn->GetBindingForPortMappingProtocol(
|
||
pPortMapping->pProtocol,
|
||
&pPortMapping->pBinding
|
||
);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
//
|
||
// At this point, the protocol is set. However, we
|
||
// still need to save the binding information
|
||
//
|
||
|
||
pPortMapping->fProtocolModified = FALSE;
|
||
pPortMapping->fBindingModified = TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (SUCCEEDED(hr) && pPortMapping->fProtocolModified)
|
||
{
|
||
hr = pPortMapping->pProtocol->SetName (wszTitle);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = pPortMapping->pProtocol->SetIPProtocol (
|
||
pPortMapping->Protocol);
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = pPortMapping->pProtocol->SetPort (pPortMapping->ExternalPort);
|
||
}
|
||
}
|
||
|
||
if (SUCCEEDED(hr)
|
||
&& pPortMapping->fBindingModified
|
||
&& NULL != pPortMapping->InternalName)
|
||
{
|
||
ULONG ulAddress = INADDR_NONE;
|
||
|
||
if (lstrlen(pPortMapping->InternalName) >= 7)
|
||
{
|
||
//
|
||
// 1.2.3.4 -- minimum of 7 characters
|
||
//
|
||
|
||
ulAddress = IpPszToHostAddr(pPortMapping->InternalName);
|
||
}
|
||
|
||
if (INADDR_NONE == ulAddress)
|
||
{
|
||
//
|
||
// Check to see if the target name is either
|
||
// 1) this computer's name, or
|
||
// 2) "localhost"
|
||
//
|
||
// If so, use the loopback address instead of the name.
|
||
//
|
||
|
||
if (0 == _tcsicmp(pPortMapping->InternalName, pDlg->ComputerName)
|
||
|| 0 == _tcsicmp(pPortMapping->InternalName, _T("localhost")))
|
||
{
|
||
ulAddress = LOOPBACK_ADDR_HOST_ORDER;
|
||
}
|
||
}
|
||
|
||
//
|
||
// We can't just check for INADDR_NONE here, since that
|
||
// is 0xFFFFFFFF, which is 255.255.255.255. To catch this
|
||
// we need to compare the name against that explicit string
|
||
// address.
|
||
//
|
||
|
||
if (INADDR_NONE == ulAddress
|
||
&& 0 != _tcsicmp(pPortMapping->InternalName, _T("255.255.255.255")))
|
||
{
|
||
OLECHAR *wsz;
|
||
|
||
wsz = StrDupWFromT(pPortMapping->InternalName);
|
||
if (NULL != wsz)
|
||
{
|
||
hr = pPortMapping->pBinding->SetTargetComputerName (wsz);
|
||
|
||
Free(wsz);
|
||
}
|
||
else
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
hr = pPortMapping->pBinding->SetTargetComputerAddress
|
||
(HTONL(ulAddress));
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = pPortMapping->pBinding->SetEnabled (!!pPortMapping->Enabled);
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = pPortMapping->pBinding->SetTargetPort (pPortMapping->InternalPort);
|
||
}
|
||
}
|
||
|
||
Free0(wszTitle);
|
||
|
||
return hr;
|
||
}
|
||
|
||
VOID
|
||
SrvAddOrEditEntry(
|
||
SADLG* pDlg,
|
||
LONG iItem,
|
||
SAPM* PortMapping )
|
||
|
||
// Called to display the 'Add' or 'Edit' dialog for a service.
|
||
//
|
||
{
|
||
LV_ITEM lvi;
|
||
|
||
// Display the dialog, and return if the user cancels.
|
||
// Otherwise, remove the old item (if any) and insert the added or edited
|
||
// item.
|
||
//
|
||
|
||
if (!SharedAccessPortMappingDlg(pDlg->hwndDlg, &PortMapping))
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (iItem != -1)
|
||
{
|
||
ListView_DeleteItem(pDlg->hwndServers, iItem);
|
||
}
|
||
|
||
ZeroMemory(&lvi, sizeof(lvi));
|
||
lvi.mask = LVIF_TEXT | LVIF_PARAM;
|
||
lvi.lParam = (LPARAM)PortMapping;
|
||
lvi.pszText = PortMapping->Title;
|
||
lvi.cchTextMax = lstrlen(PortMapping->Title) + 1;
|
||
lvi.iItem = 0;
|
||
|
||
iItem = ListView_InsertItem(pDlg->hwndServers, &lvi);
|
||
if (iItem == -1)
|
||
{
|
||
RemoveEntryList(&PortMapping->Link);
|
||
if (NULL != PortMapping->pProtocol)
|
||
{
|
||
PortMapping->pProtocol->Delete();
|
||
}
|
||
else if (NULL != PortMapping->pSPM)
|
||
{
|
||
DeleteRemotePortMappingEntry (pDlg, PortMapping);
|
||
}
|
||
FreePortMappingEntry(PortMapping);
|
||
return;
|
||
}
|
||
|
||
// Update the item's 'enabled' state. Setting the check on the item
|
||
// triggers an update of the button state as well as conflict detection.
|
||
// (See 'SrvUpdateButtons' and the LVXN_SETCHECK handling in 'SasDlgProc').
|
||
//
|
||
ListView_SetCheck(pDlg->hwndServers, iItem, PortMapping->Enabled);
|
||
ListView_SetItemState(
|
||
pDlg->hwndServers, iItem, LVIS_SELECTED, LVIS_SELECTED);
|
||
pDlg->fModified = TRUE;
|
||
}
|
||
|
||
BOOL
|
||
SrvCommand(
|
||
IN SADLG* pDlg,
|
||
IN WORD wNotification,
|
||
IN WORD wId,
|
||
IN HWND hwndCtrl )
|
||
|
||
// Called to process a 'WM_COMMAND' message from one of the page's buttons.
|
||
//
|
||
{
|
||
switch (wId)
|
||
{
|
||
case CID_SS_PB_Add:
|
||
{
|
||
SrvAddOrEditEntry(pDlg, -1, NULL);
|
||
return TRUE;
|
||
}
|
||
|
||
case CID_SS_PB_Edit:
|
||
{
|
||
LONG i = ListView_GetNextItem(pDlg->hwndServers, -1, LVNI_SELECTED);
|
||
SAPM* PortMapping;
|
||
if (i == -1)
|
||
{
|
||
MsgDlg(pDlg->hwndDlg, SID_NoModifySelection, NULL);
|
||
SetFocus(pDlg->hwndServers);
|
||
return FALSE;
|
||
}
|
||
PortMapping = (SAPM*)ListView_GetParamPtr(pDlg->hwndServers, i);
|
||
if (PortMapping)
|
||
{
|
||
SrvAddOrEditEntry(pDlg, i, PortMapping);
|
||
}
|
||
SetFocus(pDlg->hwndServers);
|
||
return TRUE;
|
||
}
|
||
|
||
case CID_SS_PB_Delete:
|
||
{
|
||
LONG i = ListView_GetNextItem(pDlg->hwndServers, -1, LVNI_SELECTED);
|
||
SAPM* PortMapping;
|
||
if (i == -1)
|
||
{
|
||
MsgDlg(pDlg->hwndDlg, SID_NoDeleteSelection, NULL);
|
||
SetFocus(pDlg->hwndServers);
|
||
return FALSE;
|
||
}
|
||
|
||
// Delete each selected item. Items with marked 'built-in'
|
||
// cannot be deleted, and are ignored.
|
||
//
|
||
do {
|
||
PortMapping = (SAPM*)ListView_GetParamPtr(pDlg->hwndServers, i);
|
||
|
||
if(NULL == PortMapping)
|
||
{
|
||
break;
|
||
}
|
||
|
||
if (PortMapping->BuiltIn)
|
||
{
|
||
++i;
|
||
}
|
||
else
|
||
{
|
||
ListView_DeleteItem(pDlg->hwndServers, i);
|
||
--i;
|
||
|
||
//
|
||
// If this is a new entry we can immediately remove
|
||
// it from the list and free it; otherwise, we move
|
||
// it to the front of the list and mark it for
|
||
// deletion.
|
||
//
|
||
|
||
RemoveEntryList(&PortMapping->Link);
|
||
if (PortMapping->fNewEntry)
|
||
{
|
||
_ASSERT(NULL == PortMapping->pProtocol);
|
||
_ASSERT(NULL == PortMapping->pSPM);
|
||
|
||
FreePortMappingEntry(PortMapping);
|
||
}
|
||
else
|
||
{
|
||
InsertHeadList(&pDlg->PortMappings, &PortMapping->Link);
|
||
PortMapping->fDeleted = TRUE;
|
||
}
|
||
}
|
||
i = ListView_GetNextItem(pDlg->hwndServers, i, LVNI_SELECTED);
|
||
} while (i != -1);
|
||
|
||
// Update the dialog and synchronize the button-states with the
|
||
// current selection, if any.
|
||
//
|
||
pDlg->fModified = TRUE;
|
||
SetFocus(pDlg->hwndServers);
|
||
SrvUpdateButtons(pDlg, TRUE, -1);
|
||
return TRUE;
|
||
}
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL
|
||
SrvConflictDetected(
|
||
SADLG* pDlg,
|
||
SAPM* PortMapping )
|
||
|
||
// Called to determine whether the given item conflicts with any other
|
||
// item and, if so, to display a message.
|
||
//
|
||
{
|
||
SAPM* Duplicate;
|
||
PLIST_ENTRY Link;
|
||
for (Link = pDlg->PortMappings.Flink;
|
||
Link != &pDlg->PortMappings; Link = Link->Flink)
|
||
{
|
||
Duplicate = CONTAINING_RECORD(Link, SAPM, Link);
|
||
if (PortMapping != Duplicate &&
|
||
!Duplicate->fDeleted &&
|
||
PortMapping->Protocol == Duplicate->Protocol &&
|
||
PortMapping->ExternalPort == Duplicate->ExternalPort)
|
||
{
|
||
MsgDlg(pDlg->hwndDlg, SID_DuplicatePortNumber, NULL);
|
||
return TRUE;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL
|
||
SrvInit(
|
||
HWND hwndPage,
|
||
SADLG* pDlg )
|
||
|
||
// Called to initialize the services page. Fills the list-control with
|
||
// configured services.
|
||
//
|
||
{
|
||
BOOL fModified;
|
||
LONG i;
|
||
LV_ITEM lvi;
|
||
PLIST_ENTRY Link;
|
||
SAPM* PortMapping;
|
||
|
||
// Initialize the containing property-sheet, then store this page's
|
||
// data in the shared control-block at 'pDlg'.
|
||
//
|
||
if (!SasInit(hwndPage, pDlg))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
// Store this page's data in the shared control-block at 'pDlg'.
|
||
//
|
||
pDlg->hwndSrv = hwndPage;
|
||
pDlg->hwndServers = GetDlgItem(hwndPage, CID_SS_LV_Services);
|
||
|
||
// Initialize the list-control with checkbox-handling,
|
||
// insert a single column, and fill the list-control with the configured
|
||
// items.
|
||
//
|
||
ListView_InstallChecks(pDlg->hwndServers, g_hinstDll);
|
||
ListView_InsertSingleAutoWidthColumn(pDlg->hwndServers);
|
||
|
||
fModified = pDlg->fModified;
|
||
for (Link = pDlg->PortMappings.Flink;
|
||
Link != &pDlg->PortMappings; Link = Link->Flink)
|
||
{
|
||
PortMapping = CONTAINING_RECORD(Link, SAPM, Link);
|
||
|
||
ZeroMemory(&lvi, sizeof(lvi));
|
||
lvi.mask = LVIF_TEXT | LVIF_PARAM;
|
||
lvi.iItem = 0;
|
||
lvi.lParam = (LPARAM)PortMapping;
|
||
lvi.pszText = PortMapping->Title;
|
||
lvi.cchTextMax = lstrlen(PortMapping->Title) + 1;
|
||
|
||
i = ListView_InsertItem(pDlg->hwndServers, &lvi);
|
||
|
||
if (i != -1)
|
||
{
|
||
ListView_SetCheck(pDlg->hwndServers, i, PortMapping->Enabled);
|
||
}
|
||
}
|
||
pDlg->fModified = fModified;
|
||
|
||
// Finally, update the appearance of the buttons for the current selection.
|
||
//
|
||
ListView_SetItemState(pDlg->hwndServers, 0, LVIS_SELECTED, LVIS_SELECTED);
|
||
SrvUpdateButtons(pDlg, TRUE, -1);
|
||
|
||
// if we got no portmappings, check to see if the button allowing
|
||
// other network users to control the gateway is unchecked (on the host)
|
||
if (IsListEmpty (pDlg->PortMappings.Flink) &&
|
||
pDlg->pUPS && IsICSHost ()) {
|
||
|
||
// display error
|
||
DisplayError (pDlg->hwndDlg, SID_OP_OurGatewayError, SID_PopupTitle);
|
||
// cancel
|
||
PostMessage (hwndPage, WM_PRIVATE_CANCEL, 0, 0L);
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
VOID
|
||
SrvUpdateButtons(
|
||
SADLG* pDlg,
|
||
BOOL fAddDelete,
|
||
LONG iSetCheckItem )
|
||
|
||
// Called to set an initial selection if necessary, update the appearance
|
||
// of the 'Edit' and 'Delete' buttons, and perform conflict-detection
|
||
// if an entry's checkbox was set.
|
||
//
|
||
{
|
||
LONG i;
|
||
SAPM* PortMapping;
|
||
|
||
// If an entry was added or removed, ensure that there is a selection.
|
||
// If there are no entries at all, disable the 'Edit' button.
|
||
//
|
||
if (fAddDelete)
|
||
{
|
||
if (ListView_GetItemCount(pDlg->hwndServers))
|
||
{
|
||
ListView_SetItemState(
|
||
pDlg->hwndServers, 0, LVIS_SELECTED, LVIS_SELECTED);
|
||
EnableWindow(GetDlgItem(pDlg->hwndSrv, CID_SS_PB_Edit), TRUE);
|
||
}
|
||
else
|
||
{
|
||
EnableWindow(GetDlgItem(pDlg->hwndSrv, CID_SS_PB_Edit), FALSE);
|
||
}
|
||
}
|
||
|
||
// Disable the 'Delete' button, and enable it only if at least one of the
|
||
// selected items is not a built-in item.
|
||
//
|
||
EnableWindow(GetDlgItem(pDlg->hwndSrv, CID_SS_PB_Delete), FALSE);
|
||
i = ListView_GetNextItem(pDlg->hwndServers, -1, LVNI_SELECTED);
|
||
while (i != -1)
|
||
{
|
||
PortMapping = (SAPM*)ListView_GetParamPtr(pDlg->hwndServers, i);
|
||
if ( (NULL != PortMapping)
|
||
&& (!PortMapping->BuiltIn))
|
||
{
|
||
EnableWindow(GetDlgItem(pDlg->hwndSrv, CID_SS_PB_Delete), TRUE);
|
||
break;
|
||
}
|
||
|
||
i = ListView_GetNextItem(pDlg->hwndServers, i, LVNI_SELECTED);
|
||
}
|
||
|
||
// If the check-state of an item was changed and the item is now checked,
|
||
// perform conflict-detection. If a conflict is detected, clear the item's
|
||
// check state.
|
||
//
|
||
if (iSetCheckItem != -1)
|
||
{
|
||
PortMapping =
|
||
(SAPM*)ListView_GetParamPtr(pDlg->hwndServers, iSetCheckItem);
|
||
|
||
if(NULL == PortMapping)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (ListView_GetCheck(pDlg->hwndServers, iSetCheckItem))
|
||
{
|
||
if (SrvConflictDetected(pDlg, PortMapping))
|
||
{
|
||
ListView_SetCheck(pDlg->hwndServers, iSetCheckItem, FALSE);
|
||
SrvAddOrEditEntry(pDlg, iSetCheckItem, PortMapping);
|
||
}
|
||
else
|
||
{
|
||
PortMapping->Enabled = TRUE;
|
||
PortMapping->fBindingModified = TRUE;
|
||
|
||
// If the item is marked 'built-in' and it is being enabled
|
||
// for the first time, pop up the edit-dialog so the user can
|
||
// specify an internal IP address or name for the server.
|
||
//
|
||
if (PortMapping->BuiltIn &&
|
||
(!PortMapping->InternalName
|
||
|| !lstrlen(PortMapping->InternalName)))
|
||
{
|
||
|
||
//
|
||
// We fill in the local computer name as the default
|
||
// target. It's OK if this allocation fails; the UI
|
||
// will show an empty field, so the user will be
|
||
// required to enter a target.
|
||
//
|
||
|
||
PortMapping->InternalName = _StrDup(pDlg->ComputerName);
|
||
SrvAddOrEditEntry(pDlg, iSetCheckItem, PortMapping);
|
||
|
||
if (!PortMapping->InternalName
|
||
|| !lstrlen(PortMapping->InternalName))
|
||
{
|
||
ListView_SetCheck(
|
||
pDlg->hwndServers, iSetCheckItem, FALSE);
|
||
|
||
PortMapping->Enabled = FALSE;
|
||
PortMapping->fBindingModified = FALSE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
PortMapping->Enabled = FALSE;
|
||
PortMapping->fBindingModified = TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
BOOL
|
||
SharedAccessPortMappingDlg(
|
||
IN HWND hwndOwner,
|
||
IN OUT SAPM** PortMapping )
|
||
|
||
// Called to display the dialog for adding or editing a service-entry.
|
||
// 'Server' points to NULL if adding, or the target entry if editing.
|
||
//
|
||
{
|
||
LRESULT nResult =
|
||
DialogBoxParam(g_hinstDll, MAKEINTRESOURCE(DID_SS_Service),
|
||
hwndOwner, SspDlgProc, (LPARAM)PortMapping);
|
||
return nResult == -1 ? FALSE : (BOOL)nResult;
|
||
}
|
||
|
||
INT_PTR CALLBACK
|
||
SspDlgProc(
|
||
IN HWND hwnd,
|
||
IN UINT unMsg,
|
||
IN WPARAM wparam,
|
||
IN LPARAM lparam )
|
||
|
||
// Called to handle messages for the add/edit service dialog.
|
||
//
|
||
{
|
||
switch (unMsg)
|
||
{
|
||
case WM_INITDIALOG:
|
||
{
|
||
SADLG* pDlg;
|
||
SAPM* PortMapping;
|
||
|
||
// Retrieve the context-block for the settings dialog from which
|
||
// this dialog was launched.
|
||
//
|
||
if (!(pDlg = SasContext(hwnd)))
|
||
{
|
||
EndDialog(hwnd, FALSE);
|
||
return TRUE;
|
||
}
|
||
|
||
Edit_LimitText(GetDlgItem(hwnd, CID_SS_EB_ExternalPort), 5);
|
||
Edit_LimitText(GetDlgItem(hwnd, CID_SS_EB_InternalPort), 5);
|
||
|
||
// Create new service if adding a service, or retrieve the service
|
||
// to be edited.
|
||
//
|
||
if (!(PortMapping = *(SAPM**)lparam))
|
||
{
|
||
PortMapping = (SAPM*)Malloc(sizeof(*PortMapping));
|
||
if (!PortMapping)
|
||
{
|
||
EndDialog(hwnd, FALSE);
|
||
return TRUE;
|
||
}
|
||
*(SAPM**)lparam = PortMapping;
|
||
ZeroMemory(PortMapping, sizeof(*PortMapping));
|
||
PortMapping->Enabled = TRUE;
|
||
PortMapping->fNewEntry = TRUE;
|
||
InitializeListHead(&PortMapping->Link);
|
||
CheckDlgButton(hwnd, CID_SS_PB_Tcp, TRUE);
|
||
}
|
||
else
|
||
{
|
||
EnableWindow(GetDlgItem(hwnd, CID_SS_EB_Service), FALSE);
|
||
SetDlgItemText(hwnd, CID_SS_EB_Service, PortMapping->Title);
|
||
SetDlgItemInt(hwnd, CID_SS_EB_ExternalPort, ntohs(PortMapping->ExternalPort), FALSE);
|
||
SetDlgItemInt(hwnd, CID_SS_EB_InternalPort, ntohs(PortMapping->InternalPort), FALSE);
|
||
CheckDlgButton(
|
||
hwnd, CID_SS_PB_Tcp, PortMapping->Protocol == NAT_PROTOCOL_TCP);
|
||
CheckDlgButton(
|
||
hwnd, CID_SS_PB_Udp, PortMapping->Protocol != NAT_PROTOCOL_TCP);
|
||
SetDlgItemText(hwnd, CID_SS_EB_Address, PortMapping->InternalName);
|
||
|
||
// If the entry to be modified is marked 'built-in', disable
|
||
// all input fields except the server-name, which the user must
|
||
// now enter.
|
||
//
|
||
|
||
if (PortMapping->BuiltIn)
|
||
{
|
||
EnableWindow(GetDlgItem(hwnd, CID_SS_EB_ExternalPort), FALSE);
|
||
EnableWindow(GetDlgItem(hwnd, CID_SS_EB_InternalPort), FALSE);
|
||
EnableWindow(GetDlgItem(hwnd, CID_SS_PB_Tcp), FALSE);
|
||
EnableWindow(GetDlgItem(hwnd, CID_SS_PB_Udp), FALSE);
|
||
}
|
||
}
|
||
|
||
SetWindowLongPtr(hwnd, DWLP_USER, (ULONG_PTR)PortMapping);
|
||
CenterWindow(hwnd, GetParent(hwnd));
|
||
AddContextHelpButton(hwnd);
|
||
return TRUE;
|
||
}
|
||
|
||
case WM_HELP:
|
||
case WM_CONTEXTMENU:
|
||
{
|
||
ContextHelp( g_adwSspHelp, hwnd, unMsg, wparam, lparam );
|
||
break;
|
||
}
|
||
|
||
case WM_COMMAND:
|
||
{
|
||
if (HIWORD(wparam) != BN_CLICKED) { return FALSE; }
|
||
|
||
// If the user is dismissing the dialog, clean up and return.
|
||
//
|
||
SAPM* PortMapping;
|
||
SADLG* pDlg;
|
||
if (IDCANCEL == LOWORD(wparam))
|
||
{
|
||
PortMapping = (SAPM*)GetWindowLongPtr(hwnd, DWLP_USER);
|
||
if (IsListEmpty(&PortMapping->Link))
|
||
{
|
||
FreePortMappingEntry(PortMapping);
|
||
}
|
||
EndDialog (hwnd, FALSE);
|
||
return TRUE;
|
||
}
|
||
else if (LOWORD(wparam) != IDOK)
|
||
{
|
||
return FALSE;
|
||
}
|
||
else if (!(pDlg = SasContext(hwnd)))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
// Retrieve the service to be added or modified.
|
||
//
|
||
PortMapping = (SAPM*)GetWindowLongPtr(hwnd, DWLP_USER);
|
||
|
||
// Retrieve the values specified by the user,
|
||
// and attempt to save them in the new or modified entry.
|
||
//
|
||
UCHAR Protocol = IsDlgButtonChecked(hwnd, CID_SS_PB_Tcp)
|
||
? NAT_PROTOCOL_TCP : NAT_PROTOCOL_UDP;
|
||
|
||
BOOL Success;
|
||
ULONG ExternalPort = GetDlgItemInt(hwnd, CID_SS_EB_ExternalPort, &Success, FALSE);
|
||
if (!Success || ExternalPort < 1 || ExternalPort > 65535)
|
||
{
|
||
MsgDlg(hwnd, SID_TypePortNumber, NULL);
|
||
SetFocus(GetDlgItem(hwnd, CID_SS_EB_ExternalPort));
|
||
return FALSE;
|
||
}
|
||
ExternalPort = htons((USHORT)ExternalPort);
|
||
|
||
//
|
||
// Check to see if this is a duplicate. To do this we need
|
||
// to save the old port and protocol values, put the new
|
||
// values into the protocol entry, perform the check, and
|
||
// then restore the old values.
|
||
//
|
||
|
||
USHORT OldExternalPort = PortMapping->ExternalPort;
|
||
PortMapping->ExternalPort = (USHORT)ExternalPort;
|
||
UCHAR OldProtocol = PortMapping->Protocol;
|
||
PortMapping->Protocol = Protocol;
|
||
|
||
if (SrvConflictDetected(pDlg, PortMapping))
|
||
{
|
||
PortMapping->ExternalPort = OldExternalPort;
|
||
PortMapping->Protocol = OldProtocol;
|
||
SetFocus(GetDlgItem(hwnd, CID_SS_EB_ExternalPort));
|
||
return FALSE;
|
||
}
|
||
PortMapping->ExternalPort = OldExternalPort;
|
||
PortMapping->Protocol = OldProtocol;
|
||
|
||
// per BillI, there's no need to test internal ports for conflicts
|
||
ULONG InternalPort = GetDlgItemInt(hwnd, CID_SS_EB_InternalPort, &Success, FALSE);
|
||
if (InternalPort == 0)
|
||
InternalPort = ExternalPort;
|
||
else {
|
||
if (InternalPort < 1 || InternalPort > 65535)
|
||
{
|
||
MsgDlg(hwnd, SID_TypePortNumber, NULL);
|
||
SetFocus(GetDlgItem(hwnd, CID_SS_EB_InternalPort));
|
||
return FALSE;
|
||
}
|
||
InternalPort = htons((USHORT)InternalPort);
|
||
}
|
||
|
||
TCHAR* InternalName = GetText(GetDlgItem(hwnd, CID_SS_EB_Address));
|
||
if (!InternalName || !lstrlen(InternalName))
|
||
{
|
||
MsgDlg(hwnd, SID_SS_TypeAddress, NULL);
|
||
SetFocus(GetDlgItem(hwnd, CID_SS_EB_Address));
|
||
return FALSE;
|
||
}
|
||
|
||
if (IsListEmpty(&PortMapping->Link))
|
||
{
|
||
PortMapping->Title = GetText(GetDlgItem(hwnd, CID_SS_EB_Service));
|
||
if (!PortMapping->Title || !lstrlen(PortMapping->Title))
|
||
{
|
||
MsgDlg(hwnd, SID_TypeEntryName, NULL);
|
||
SetFocus(GetDlgItem(hwnd, CID_SS_EB_Service));
|
||
Free0(InternalName);
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
if (PortMapping->Protocol != Protocol ||
|
||
PortMapping->ExternalPort != (USHORT)ExternalPort ||
|
||
PortMapping->InternalPort != (USHORT)InternalPort)
|
||
{
|
||
PortMapping->fProtocolModified = TRUE;
|
||
}
|
||
|
||
PortMapping->fBindingModified = TRUE;
|
||
PortMapping->Protocol = Protocol;
|
||
PortMapping->ExternalPort = (USHORT)ExternalPort;
|
||
PortMapping->InternalPort = (USHORT)InternalPort;
|
||
if (PortMapping->InternalName)
|
||
{
|
||
Free(PortMapping->InternalName);
|
||
}
|
||
PortMapping->InternalName = InternalName;
|
||
if (IsListEmpty(&PortMapping->Link))
|
||
{
|
||
InsertTailList(&pDlg->PortMappings, &PortMapping->Link);
|
||
}
|
||
EndDialog (hwnd, TRUE);
|
||
return TRUE;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|