You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2231 lines
65 KiB
2231 lines
65 KiB
// 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 <wininet.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;
|
|
HANDLE hThread = CreateThread (NULL, 0,
|
|
CWaitDialog::ThreadProc,
|
|
(void*)m_pwd,
|
|
0, &ThreadId);
|
|
if (hThread == NULL) {
|
|
delete m_pwd;
|
|
m_pwd = NULL;
|
|
} else {
|
|
CloseHandle (hThread);
|
|
}
|
|
}
|
|
}
|
|
~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 (/* Bug 630840: a similar scenario can happen when you
|
|
create the "same" port mapping on two NICs:
|
|
the second one's per NIC info is missing, and
|
|
when enabling it, the code below needs to run.
|
|
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);
|
|
Edit_LimitText(GetDlgItem(hwnd, CID_SS_EB_Service), INTERNET_MAX_HOST_NAME_LENGTH-1);
|
|
Edit_LimitText(GetDlgItem(hwnd, CID_SS_EB_Address), INTERNET_MAX_HOST_NAME_LENGTH-1);
|
|
|
|
// 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;
|
|
}
|
|
|