Leaked source code of windows server 2003
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

  1. // Copyright (c) 1998, Microsoft Corporation, all rights reserved
  2. //
  3. // sadlg.c
  4. // Remote Access Common Dialog APIs
  5. // Shared Access Settings property sheet
  6. //
  7. // 10/20/1998 Abolade Gbadegesin
  8. //
  9. //#include "pch.h"
  10. #pragma hdrstop
  11. #include "sautil.h"
  12. #include <wininet.h>
  13. #include <winsock2.h>
  14. #include "sainfo.h"
  15. #include "ipnat.h"
  16. #include "fwpages.h"
  17. // extern(s)
  18. // replaced global atom with "HNETCFG_SADLG"
  19. // Loopback address (127.0.0.1) in network and host byte order
  20. //
  21. #define LOOPBACK_ADDR 0x0100007f
  22. #define LOOPBACK_ADDR_HOST_ORDER 0x7f000001
  23. // 'Shared Access Settings' common block
  24. //
  25. typedef struct
  26. _SADLG
  27. {
  28. HWND hwndOwner;
  29. HWND hwndDlg;
  30. HWND hwndSrv;
  31. HWND hwndServers;
  32. IHNetCfgMgr *pHNetCfgMgr;
  33. IHNetConnection *pHNetConn;
  34. LIST_ENTRY PortMappings;
  35. BOOL fModified;
  36. TCHAR *ComputerName;
  37. IUPnPService * pUPS; // iff downlevel
  38. }
  39. SADLG;
  40. // Info block for port mapping entries
  41. //
  42. typedef struct
  43. _SAPM
  44. {
  45. LIST_ENTRY Link;
  46. IHNetPortMappingProtocol *pProtocol;
  47. IHNetPortMappingBinding *pBinding;
  48. BOOL fProtocolModified;
  49. BOOL fBindingModified;
  50. BOOL fNewEntry;
  51. BOOL fDeleted;
  52. TCHAR *Title;
  53. BOOL Enabled;
  54. BOOL BuiltIn;
  55. UCHAR Protocol;
  56. USHORT ExternalPort;
  57. USHORT InternalPort;
  58. TCHAR *InternalName;
  59. IStaticPortMapping * pSPM;
  60. }
  61. SAPM;
  62. #define HTONS(s) ((UCHAR)((s) >> 8) | ((UCHAR)(s) << 8))
  63. #define HTONL(l) ((HTONS(l) << 16) | HTONS((l) >> 16))
  64. #define NTOHS(s) HTONS(s)
  65. #define NTOHL(l) HTONL(l)
  66. #define SAPAGE_Servers 0
  67. #define SAPAGE_Applications 1
  68. #define SAPAGE_FirewallLogging 2
  69. #define SAPAGE_ICMPSettings 3
  70. #define SAPAGE_PageCount 4
  71. inline SADLG * SasContext(HWND hwnd)
  72. {
  73. return (SADLG*)GetProp(GetParent(hwnd), _T("HNETCFG_SADLG"));
  74. }
  75. #define SasErrorDlg(h,o,e,a) \
  76. ErrorDlgUtil(h,o,e,a,g_hinstDll,SID_SharedAccessSettings,SID_FMT_ErrorMsg)
  77. const TCHAR c_szEmpty[] = TEXT("");
  78. static DWORD g_adwSrvHelp[] =
  79. {
  80. CID_SS_LV_Services, HID_SS_LV_Services,
  81. CID_SS_PB_Add, HID_SS_PB_Add,
  82. CID_SS_PB_Edit, HID_SS_PB_Edit,
  83. CID_SS_PB_Delete, HID_SS_PB_Delete,
  84. 0, 0
  85. };
  86. static DWORD g_adwSspHelp[] =
  87. {
  88. CID_SS_EB_Service, HID_SS_EB_Service,
  89. CID_SS_EB_ExternalPort, -1,
  90. CID_SS_EB_InternalPort, HID_SS_EB_Port,
  91. CID_SS_PB_Tcp, HID_SS_PB_Tcp,
  92. CID_SS_PB_Udp, HID_SS_PB_Udp,
  93. CID_SS_EB_Address, HID_SS_EB_Address,
  94. 0, 0
  95. };
  96. // FORWARD DECLARATIONS
  97. //
  98. HRESULT
  99. DeleteRemotePortMappingEntry(
  100. SADLG *pDlg,
  101. SAPM * pPortMapping
  102. );
  103. VOID
  104. FreePortMappingEntry(
  105. SAPM *pPortMapping );
  106. VOID
  107. FreeSharingAndFirewallSettings(
  108. SADLG* pDlg );
  109. HRESULT
  110. LoadPortMappingEntry(
  111. IHNetPortMappingBinding *pBinding,
  112. SADLG* pDlg,
  113. SAPM **ppPortMapping );
  114. HRESULT
  115. LoadRemotePortMappingEntry (
  116. IDispatch * pDisp,
  117. /* SADLG* pDlg, */
  118. SAPM **ppPortMapping );
  119. HRESULT
  120. LoadSharingAndFirewallSettings(
  121. SADLG* pDlg );
  122. VOID
  123. SasApply(
  124. SADLG* pDlg );
  125. LVXDRAWINFO*
  126. SasLvxCallback(
  127. HWND hwndLv,
  128. DWORD dwItem );
  129. INT_PTR CALLBACK
  130. SasSrvDlgProc(
  131. HWND hwnd,
  132. UINT unMsg,
  133. WPARAM wparam,
  134. LPARAM lparam );
  135. HRESULT
  136. SavePortMappingEntry(
  137. SADLG *pDlg,
  138. SAPM *pPortMapping );
  139. BOOL
  140. SharedAccessPortMappingDlg(
  141. IN HWND hwndOwner,
  142. IN OUT SAPM** PortMapping );
  143. INT_PTR CALLBACK
  144. SspDlgProc(
  145. IN HWND hwnd,
  146. IN UINT unMsg,
  147. IN WPARAM wparam,
  148. IN LPARAM lparam );
  149. VOID
  150. SrvAddOrEditEntry(
  151. SADLG* pDlg,
  152. LONG iItem,
  153. SAPM* PortMapping );
  154. BOOL
  155. SrvCommand(
  156. IN SADLG* pDlg,
  157. IN WORD wNotification,
  158. IN WORD wId,
  159. IN HWND hwndCtrl );
  160. BOOL
  161. SrvConflictDetected(
  162. SADLG* pDlg,
  163. SAPM* PortMapping );
  164. BOOL
  165. SrvInit(
  166. HWND hwndPage,
  167. SADLG* pDlg );
  168. #define WM_PRIVATE_CANCEL 0x8000
  169. VOID
  170. SrvUpdateButtons(
  171. SADLG* pDlg,
  172. BOOL fAddDelete,
  173. LONG iSetCheckItem );
  174. void DisplayError (HWND hwnd, int idError, int idTitle)
  175. {
  176. TCHAR* pszError = PszFromId (g_hinstDll, idError);
  177. if (pszError) {
  178. TCHAR* pszTitle = PszFromId (g_hinstDll, idTitle);
  179. if (pszTitle) {
  180. MessageBox (hwnd,
  181. pszError, pszTitle,
  182. MB_OK | MB_ICONERROR | MB_APPLMODAL);
  183. Free (pszTitle);
  184. }
  185. Free (pszError);
  186. }
  187. }
  188. BOOL APIENTRY
  189. HNetSharedAccessSettingsDlg(
  190. BOOL fSharedAccessMode,
  191. HWND hwndOwner )
  192. // Displays the shared access settings property-sheet.
  193. // On input, 'hwndOwner' indicates the window of the caller,
  194. // with respect to which we offset the displayed property-sheet.
  195. //
  196. {
  197. HRESULT hr;
  198. IHNetCfgMgr *pHNetCfgMgr;
  199. BOOL fComInitialized = FALSE;
  200. BOOL fModified = FALSE;
  201. TRACE("HNetSharedAccessSettingsDlg");
  202. //
  203. // Make sure COM is initialized on this thread
  204. //
  205. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
  206. if (SUCCEEDED(hr))
  207. {
  208. fComInitialized = TRUE;
  209. }
  210. else if (RPC_E_CHANGED_MODE == hr)
  211. {
  212. hr = S_OK;
  213. }
  214. //
  215. // Create the HNetCfgMgr
  216. //
  217. if (SUCCEEDED(hr))
  218. {
  219. hr = CoCreateInstance(
  220. CLSID_HNetCfgMgr,
  221. NULL,
  222. CLSCTX_ALL,
  223. IID_IHNetCfgMgr,
  224. (VOID**) &pHNetCfgMgr
  225. );
  226. if (SUCCEEDED(hr))
  227. {
  228. fModified = HNetSharingAndFirewallSettingsDlg(
  229. hwndOwner,
  230. pHNetCfgMgr,
  231. FALSE,
  232. NULL
  233. );
  234. pHNetCfgMgr->Release();
  235. }
  236. }
  237. if (TRUE == fComInitialized)
  238. {
  239. CoUninitialize();
  240. }
  241. return fModified;
  242. }
  243. int CALLBACK
  244. UnHelpCallbackFunc(
  245. IN HWND hwndDlg,
  246. IN UINT unMsg,
  247. IN LPARAM lparam )
  248. // A standard Win32 commctrl PropSheetProc. See MSDN documentation.
  249. //
  250. // Returns 0 always.
  251. //
  252. {
  253. TRACE2( "UnHelpCallbackFunc(m=%d,l=%08x)",unMsg, lparam );
  254. if (unMsg == PSCB_PRECREATE)
  255. {
  256. extern BOOL g_fNoWinHelp;
  257. // Turn off context help button if WinHelp won't work. See
  258. // common\uiutil\ui.c.
  259. //
  260. if (g_fNoWinHelp)
  261. {
  262. DLGTEMPLATE* pDlg = (DLGTEMPLATE* )lparam;
  263. pDlg->style &= ~(DS_CONTEXTHELP);
  264. }
  265. }
  266. return 0;
  267. }
  268. HRESULT APIENTRY HNetGetSharingServicesPage (IUPnPService * pUPS, PROPSHEETPAGE * psp)
  269. {
  270. // _asm int 3
  271. if (!pUPS) return E_INVALIDARG;
  272. if (!psp) return E_INVALIDARG;
  273. // psp->dwSize muust be filled out by caller!
  274. if (psp->dwSize == 0)
  275. return E_INVALIDARG;
  276. SADLG* pDlg = (SADLG*)Malloc(sizeof(*pDlg));
  277. if (!pDlg)
  278. return E_OUTOFMEMORY;
  279. ZeroMemory(pDlg, sizeof(*pDlg));
  280. pDlg->hwndOwner = (HWND)psp->lParam; // double-secret place to hang the owning window
  281. pDlg->pUPS = pUPS;
  282. pUPS->AddRef();
  283. InitializeListHead(&pDlg->PortMappings);
  284. HRESULT hr = LoadSharingAndFirewallSettings(pDlg);
  285. if (SUCCEEDED(hr)) {
  286. // use the size we're given
  287. DWORD dwSize = psp->dwSize;
  288. ZeroMemory (psp, dwSize); // double-secret place gets wiped here
  289. psp->dwSize = dwSize;
  290. psp->hInstance = g_hinstDll;
  291. psp->pszTemplate = MAKEINTRESOURCE(PID_SS_SharedAccessServices);
  292. psp->pfnDlgProc = SasSrvDlgProc;
  293. psp->lParam = (LPARAM)pDlg;
  294. } else {
  295. FreeSharingAndFirewallSettings(pDlg);
  296. Free(pDlg);
  297. }
  298. return hr;
  299. }
  300. HRESULT APIENTRY HNetFreeSharingServicesPage (PROPSHEETPAGE * psp)
  301. { // this must be called if and only if the psp has not been displayed
  302. // NOTE: these tests are not definitive!!!
  303. if (IsBadReadPtr ((void*)psp->lParam, sizeof(SADLG)))
  304. return E_UNEXPECTED;
  305. SADLG * pDlg = (SADLG *)psp->lParam;
  306. if (pDlg->pUPS == NULL)
  307. return E_UNEXPECTED;
  308. // TODO: should I walk the heap?
  309. FreeSharingAndFirewallSettings(pDlg);
  310. Free(pDlg);
  311. return S_OK;
  312. }
  313. BOOL
  314. APIENTRY
  315. HNetSharingAndFirewallSettingsDlg(
  316. IN HWND hwndOwner,
  317. IN IHNetCfgMgr *pHNetCfgMgr,
  318. IN BOOL fShowFwOnlySettings,
  319. IN OPTIONAL IHNetConnection *pHNetConn )
  320. // Displays the shared access settings property-sheet.
  321. // On input, 'hwndOwner' indicates the window of the caller,
  322. // with respect to which we offset the displayed property-sheet.
  323. //
  324. {
  325. // _asm int 3
  326. DWORD dwErr;
  327. BOOL fModified = FALSE;
  328. SADLG* pDlg;
  329. PROPSHEETHEADER psh;
  330. PROPSHEETPAGE psp[SAPAGE_PageCount];
  331. TCHAR* pszCaption;
  332. CFirewallLoggingDialog FirewallLoggingDialog = {0};
  333. CICMPSettingsDialog ICMPSettingsDialog = {0};
  334. HRESULT hr;
  335. HRESULT hFirewallLoggingResult = E_FAIL;
  336. HRESULT hICMPSettingsResult = E_FAIL;
  337. TRACE("HNetSharingAndFirewallSettingsDlg");
  338. // Allocate and initialize the property-sheet's context block,
  339. // and read into it the current shared access settings.
  340. //
  341. pDlg = (SADLG*)Malloc(sizeof(*pDlg));
  342. if (!pDlg) { return FALSE; }
  343. ZeroMemory(pDlg, sizeof(*pDlg));
  344. pDlg->hwndOwner = hwndOwner;
  345. pDlg->pHNetCfgMgr = pHNetCfgMgr;
  346. pDlg->pHNetConn = pHNetConn;
  347. InitializeListHead(&pDlg->PortMappings);
  348. hr = LoadSharingAndFirewallSettings(pDlg);
  349. if (SUCCEEDED(hr))
  350. {
  351. // Construct the property sheet.
  352. // We use a single DlgProc for both our pages, and distinguish the pages
  353. // by setting the applications page's 'lParam' to contain the shared
  354. // context-block.
  355. // (See the 'WM_INITDIALOG' handling in 'SasDlgProc'.)
  356. //
  357. int nPages = 0;
  358. ZeroMemory(psp, sizeof(psp));
  359. ZeroMemory(&psh, sizeof(psh));
  360. if(NULL != pHNetConn && fShowFwOnlySettings)
  361. {
  362. hFirewallLoggingResult = CFirewallLoggingDialog_Init(&FirewallLoggingDialog, pHNetCfgMgr);
  363. hICMPSettingsResult = CICMPSettingsDialog_Init(&ICMPSettingsDialog, pHNetConn);
  364. }
  365. if(NULL != pHNetConn)
  366. {
  367. psp[nPages].dwSize = sizeof(PROPSHEETPAGE);
  368. psp[nPages].hInstance = g_hinstDll;
  369. psp[nPages].pszTemplate =
  370. MAKEINTRESOURCE(PID_SS_SharedAccessServices);
  371. psp[nPages].pfnDlgProc = SasSrvDlgProc;
  372. psp[nPages].lParam = (LPARAM)pDlg;
  373. nPages++;
  374. }
  375. if(SUCCEEDED(hFirewallLoggingResult))
  376. {
  377. psp[nPages].dwSize = sizeof(PROPSHEETPAGE);
  378. psp[nPages].hInstance = g_hinstDll;
  379. psp[nPages].pszTemplate =
  380. MAKEINTRESOURCE(PID_FW_FirewallLogging);
  381. psp[nPages].pfnDlgProc = CFirewallLoggingDialog_StaticDlgProc;
  382. psp[nPages].lParam = (LPARAM)&FirewallLoggingDialog;
  383. nPages++;
  384. }
  385. if(SUCCEEDED(hICMPSettingsResult))
  386. {
  387. psp[nPages].dwSize = sizeof(PROPSHEETPAGE);
  388. psp[nPages].hInstance = g_hinstDll;
  389. psp[nPages].pszTemplate =
  390. MAKEINTRESOURCE(PID_FW_ICMP);
  391. psp[nPages].pfnDlgProc = CICMPSettingsDialog_StaticDlgProc;
  392. psp[nPages].lParam = (LPARAM)&ICMPSettingsDialog;
  393. nPages++;
  394. }
  395. psh.dwSize = sizeof(PROPSHEETHEADER);
  396. psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW | PSH_USECALLBACK;
  397. psh.hInstance = g_hinstDll;
  398. psh.nPages = nPages;
  399. psh.hwndParent = hwndOwner;
  400. psh.ppsp = (LPCPROPSHEETPAGE)psp;
  401. pszCaption = pHNetConn
  402. ? PszFromId(g_hinstDll, SID_SharedAccessSettings)
  403. : PszFromId(g_hinstDll, SID_NetworkApplicationSettings);
  404. psh.pszCaption = (pszCaption ? pszCaption : c_szEmpty);
  405. psh.pfnCallback = UnHelpCallbackFunc;
  406. if (PropertySheet(&psh) == -1)
  407. {
  408. dwErr = GetLastError();
  409. TRACE1("SharedAccessSettingsDlg: PropertySheet=%d", dwErr);
  410. SasErrorDlg(hwndOwner, SID_OP_LoadDlg, dwErr, NULL);
  411. }
  412. fModified = pDlg->fModified;
  413. Free0(pszCaption); // REVIEW is this right
  414. if(SUCCEEDED(hICMPSettingsResult))
  415. {
  416. CICMPSettingsDialog_FinalRelease(&ICMPSettingsDialog);
  417. }
  418. if(SUCCEEDED(hFirewallLoggingResult))
  419. {
  420. CFirewallLoggingDialog_FinalRelease(&FirewallLoggingDialog);
  421. }
  422. FreeSharingAndFirewallSettings(pDlg);
  423. }
  424. Free(pDlg);
  425. return fModified;
  426. }
  427. VOID
  428. FreePortMappingEntry(
  429. SAPM *pPortMapping )
  430. {
  431. ASSERT(NULL != pPortMapping);
  432. if (NULL != pPortMapping->pProtocol)
  433. {
  434. pPortMapping->pProtocol->Release();
  435. }
  436. if (NULL != pPortMapping->pBinding)
  437. {
  438. pPortMapping->pBinding->Release();
  439. }
  440. if (pPortMapping->pSPM)
  441. pPortMapping->pSPM->Release();
  442. Free0(pPortMapping->Title);
  443. Free0(pPortMapping->InternalName);
  444. Free(pPortMapping);
  445. }
  446. VOID
  447. FreeSharingAndFirewallSettings(
  448. SADLG* pDlg )
  449. // Frees all sharing and firewall settings
  450. //
  451. {
  452. PLIST_ENTRY pLink;
  453. SAPM *pPortMapping;
  454. ASSERT(pDlg);
  455. //
  456. // Free port-mapping entries
  457. //
  458. while (!IsListEmpty(&pDlg->PortMappings))
  459. {
  460. pLink = RemoveHeadList(&pDlg->PortMappings);
  461. pPortMapping = CONTAINING_RECORD(pLink, SAPM, Link);
  462. ASSERT(pPortMapping);
  463. FreePortMappingEntry(pPortMapping);
  464. }
  465. //
  466. // Free computer name
  467. //
  468. Free0(pDlg->ComputerName);
  469. if (pDlg->pUPS) {
  470. pDlg->pUPS->Release();
  471. pDlg->pUPS = NULL;
  472. }
  473. }
  474. #define NAT_API_ENTER
  475. #define NAT_API_LEAVE
  476. #include "natutils.h"
  477. #include "sprtmapc.h"
  478. HRESULT GetCollectionFromService (IUPnPService * pUPS, IStaticPortMappingCollection ** ppSPMC)
  479. {
  480. CComObject<CStaticPortMappingCollection> * pC = NULL;
  481. HRESULT hr = CComObject<CStaticPortMappingCollection>::CreateInstance (&pC);
  482. if (pC) {
  483. pC->AddRef();
  484. // init
  485. hr = pC->Initialize (pUPS);
  486. if (SUCCEEDED(hr))
  487. hr = pC->QueryInterface (__uuidof(IStaticPortMappingCollection), (void**)ppSPMC);
  488. pC->Release();
  489. }
  490. return hr;
  491. }
  492. HRESULT GetStaticPortMappingCollection (
  493. SADLG* pDlg,
  494. IStaticPortMappingCollection ** ppSPMC)
  495. {
  496. _ASSERT (pDlg);
  497. _ASSERT (pDlg->pUPS);
  498. _ASSERT (ppSPMC);
  499. *ppSPMC = NULL;
  500. return GetCollectionFromService (pDlg->pUPS, ppSPMC);
  501. }
  502. HRESULT
  503. LoadRemotePortMappingEntry (IDispatch * pDisp, /* SADLG* pDlg, */ SAPM **ppPortMapping )
  504. { // NOTE: may need pDlg to get computer name if loopback
  505. *ppPortMapping = NULL;
  506. SAPM *pMapping = (SAPM*)Malloc(sizeof(*pMapping));
  507. if (!pMapping)
  508. return E_OUTOFMEMORY;
  509. ZeroMemory(pMapping, sizeof(*pMapping));
  510. InitializeListHead(&pMapping->Link);
  511. HRESULT hr = pDisp->QueryInterface (__uuidof(IStaticPortMapping),
  512. (void**)&pMapping->pSPM);
  513. if (SUCCEEDED(hr)) {
  514. // get title (description)
  515. CComBSTR cbDescription;
  516. hr = pMapping->pSPM->get_Description (&cbDescription);
  517. if (SUCCEEDED(hr)) {
  518. // immediately figure out if it's "built-in"
  519. #define BUILTIN_KEY L" [MICROSOFT]"
  520. OLECHAR * tmp = wcsstr (cbDescription.m_str, BUILTIN_KEY);
  521. if (tmp && (tmp[wcslen(BUILTIN_KEY)] == 0)) {
  522. // if the key exists and is at the end, then it's a built-in mapping
  523. pMapping->BuiltIn = TRUE;
  524. *tmp = 0;
  525. }
  526. pMapping->Title = StrDupTFromW (cbDescription);
  527. if (NULL == pMapping->Title)
  528. hr = E_OUTOFMEMORY;
  529. }
  530. if (SUCCEEDED(hr)) {
  531. // get protocol
  532. CComBSTR cbProtocol;
  533. hr = pMapping->pSPM->get_Protocol (&cbProtocol);
  534. if (SUCCEEDED(hr)) {
  535. if (!_wcsicmp (L"tcp", cbProtocol))
  536. pMapping->Protocol = NAT_PROTOCOL_TCP;
  537. else
  538. if (!_wcsicmp (L"udp", cbProtocol))
  539. pMapping->Protocol = NAT_PROTOCOL_UDP;
  540. else {
  541. _ASSERT (0 && "bad protocol!?");
  542. hr = E_UNEXPECTED;
  543. }
  544. if (SUCCEEDED(hr)) {
  545. // get external port
  546. long lExternalPort = 0;
  547. hr = pMapping->pSPM->get_ExternalPort (&lExternalPort);
  548. if (SUCCEEDED(hr)) {
  549. _ASSERT (lExternalPort > 0);
  550. _ASSERT (lExternalPort < 65536);
  551. pMapping->ExternalPort = ntohs ((USHORT)lExternalPort);
  552. // get internal port
  553. long lInternalPort = 0;
  554. hr = pMapping->pSPM->get_InternalPort (&lInternalPort);
  555. if (SUCCEEDED(hr)) {
  556. _ASSERT (lInternalPort > 0);
  557. _ASSERT (lInternalPort < 65536);
  558. pMapping->InternalPort = ntohs ((USHORT)lInternalPort);
  559. // get Enabled
  560. VARIANT_BOOL vb;
  561. hr = pMapping->pSPM->get_Enabled (&vb);
  562. if (SUCCEEDED(hr)) {
  563. pMapping->Enabled = vb == VARIANT_TRUE;
  564. }
  565. }
  566. }
  567. }
  568. }
  569. }
  570. }
  571. if (SUCCEEDED(hr)) {
  572. // lastly, get private IP or host name (hard one)
  573. // TODO: check for loopback, etc., like in LoadPortMappingEntry code below
  574. CComBSTR cbInternalClient;
  575. hr = pMapping->pSPM->get_InternalClient (&cbInternalClient);
  576. if (SUCCEEDED(hr)) {
  577. if (!(cbInternalClient == L"0.0.0.0")) {
  578. pMapping->InternalName = StrDupTFromW (cbInternalClient);
  579. if (!pMapping->InternalName)
  580. hr = E_OUTOFMEMORY;
  581. }
  582. }
  583. }
  584. if (SUCCEEDED(hr))
  585. *ppPortMapping = pMapping;
  586. else
  587. FreePortMappingEntry (pMapping);
  588. return hr;
  589. }
  590. HRESULT
  591. LoadPortMappingEntry(
  592. IHNetPortMappingBinding *pBinding,
  593. SADLG* pDlg,
  594. SAPM **ppPortMapping )
  595. {
  596. HRESULT hr = S_OK;
  597. IHNetPortMappingProtocol *pProtocol = NULL;
  598. SAPM *pMapping;
  599. BOOLEAN fTemp;
  600. OLECHAR *pwsz;
  601. ASSERT(NULL != pBinding);
  602. ASSERT(NULL != ppPortMapping);
  603. pMapping = (SAPM*) Malloc(sizeof(*pMapping));
  604. if (NULL != pMapping)
  605. {
  606. ZeroMemory(pMapping, sizeof(*pMapping));
  607. InitializeListHead(&pMapping->Link);
  608. hr = pBinding->GetProtocol (&pProtocol);
  609. if (SUCCEEDED(hr))
  610. {
  611. hr = pProtocol->GetName (&pwsz);
  612. if (SUCCEEDED(hr))
  613. {
  614. pMapping->Title = StrDupTFromW(pwsz);
  615. if (NULL == pMapping->Title)
  616. {
  617. hr = E_OUTOFMEMORY;
  618. }
  619. CoTaskMemFree(pwsz);
  620. }
  621. if (SUCCEEDED(hr))
  622. {
  623. hr = pProtocol->GetBuiltIn (&fTemp);
  624. }
  625. if (SUCCEEDED(hr))
  626. {
  627. pMapping->BuiltIn = !!fTemp;
  628. hr = pProtocol->GetIPProtocol (&pMapping->Protocol);
  629. }
  630. if (SUCCEEDED(hr))
  631. {
  632. hr = pProtocol->GetPort (&pMapping->ExternalPort);
  633. }
  634. pMapping->pProtocol = pProtocol;
  635. pMapping->pProtocol->AddRef();
  636. pProtocol->Release();
  637. }
  638. }
  639. else
  640. {
  641. hr = E_OUTOFMEMORY;
  642. }
  643. if (SUCCEEDED(hr))
  644. {
  645. hr = pBinding->GetTargetPort (&pMapping->InternalPort);
  646. }
  647. if (SUCCEEDED(hr))
  648. {
  649. hr = pBinding->GetEnabled (&fTemp);
  650. }
  651. if (SUCCEEDED(hr))
  652. {
  653. pMapping->Enabled = !!fTemp;
  654. hr = pBinding->GetCurrentMethod (&fTemp);
  655. }
  656. if (SUCCEEDED(hr))
  657. {
  658. if (fTemp)
  659. {
  660. hr = pBinding->GetTargetComputerName (&pwsz);
  661. if (SUCCEEDED(hr))
  662. {
  663. pMapping->InternalName = StrDupTFromW(pwsz);
  664. if (NULL == pMapping->InternalName)
  665. {
  666. hr = E_OUTOFMEMORY;
  667. }
  668. CoTaskMemFree(pwsz);
  669. }
  670. }
  671. else
  672. {
  673. ULONG ulAddress;
  674. hr = pBinding->GetTargetComputerAddress (&ulAddress);
  675. if (SUCCEEDED(hr))
  676. {
  677. if (LOOPBACK_ADDR == ulAddress)
  678. {
  679. //
  680. // The mapping is directed at this machine, so
  681. // replace the loopback address with our
  682. // machine name
  683. //
  684. pMapping->InternalName = _StrDup(pDlg->ComputerName);
  685. if (NULL == pMapping->InternalName)
  686. {
  687. hr = E_OUTOFMEMORY;
  688. }
  689. }
  690. else if (0 != ulAddress)
  691. {
  692. pMapping->InternalName =
  693. (LPTSTR) Malloc(16 * sizeof(TCHAR));
  694. if (NULL != pMapping->InternalName)
  695. {
  696. IpHostAddrToPsz(
  697. NTOHL(ulAddress),
  698. pMapping->InternalName
  699. );
  700. }
  701. else
  702. {
  703. hr = E_OUTOFMEMORY;
  704. }
  705. }
  706. }
  707. }
  708. }
  709. if (SUCCEEDED(hr))
  710. {
  711. hr = S_OK;
  712. pMapping->pBinding = pBinding;
  713. pMapping->pBinding->AddRef();
  714. *ppPortMapping = pMapping;
  715. }
  716. else if (NULL != pMapping)
  717. {
  718. FreePortMappingEntry(pMapping);
  719. }
  720. return hr;
  721. }
  722. class CWaitDialog
  723. {
  724. public:
  725. struct SWaitDialog
  726. {
  727. HWND hwndOwner;
  728. private:
  729. CComAutoCriticalSection m_acs;
  730. HWND m_hwndDlg;
  731. public:
  732. SWaitDialog (HWND hwnd)
  733. {
  734. hwndOwner = hwnd;
  735. m_hwndDlg = NULL;
  736. }
  737. void SetWindow (HWND hwnd)
  738. {
  739. m_acs.Lock();
  740. if (m_hwndDlg == NULL)
  741. m_hwndDlg = hwnd;
  742. m_acs.Unlock();
  743. }
  744. HWND GetWindow () { return m_hwndDlg; }
  745. };
  746. private:
  747. SWaitDialog * m_pwd;
  748. public:
  749. CWaitDialog (HWND hwndOwner)
  750. {
  751. m_pwd = new SWaitDialog (hwndOwner);
  752. if (m_pwd) {
  753. // create thread
  754. DWORD ThreadId = NULL;
  755. HANDLE hThread = CreateThread (NULL, 0,
  756. CWaitDialog::ThreadProc,
  757. (void*)m_pwd,
  758. 0, &ThreadId);
  759. if (hThread == NULL) {
  760. delete m_pwd;
  761. m_pwd = NULL;
  762. } else {
  763. CloseHandle (hThread);
  764. }
  765. }
  766. }
  767. ~CWaitDialog ()
  768. {
  769. if (m_pwd) {
  770. HWND hwnd = m_pwd->GetWindow();
  771. m_pwd->SetWindow ((HWND)INVALID_HANDLE_VALUE);
  772. if (hwnd != NULL)
  773. EndDialog (hwnd, 1);
  774. }
  775. }
  776. static DWORD WINAPI ThreadProc (VOID *pVoid)
  777. {
  778. SWaitDialog * pWD = (SWaitDialog *)pVoid;
  779. EnableWindow (pWD->hwndOwner, FALSE);
  780. DialogBoxParam (g_hinstDll,
  781. MAKEINTRESOURCE(PID_SS_PleaseWait),
  782. pWD->hwndOwner,
  783. CWaitDialog::DlgProc,
  784. (LPARAM)pWD);
  785. EnableWindow (pWD->hwndOwner, TRUE);
  786. delete pWD;
  787. return 1;
  788. }
  789. static INT_PTR CALLBACK DlgProc (HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam)
  790. {
  791. switch (uMsg) {
  792. case WM_INITDIALOG:
  793. {
  794. // hang onto my data
  795. SWaitDialog * pWD = (SWaitDialog *)lparam;
  796. SetWindowLongPtr (hwnd, DWLP_USER, (LONG_PTR)pWD);
  797. // center window on owner
  798. CenterWindow (hwnd, pWD->hwndOwner);
  799. // fill out dlg's hwnd
  800. pWD->SetWindow (hwnd);
  801. if (pWD->GetWindow() == INVALID_HANDLE_VALUE) // already destructed!
  802. PostMessage (hwnd, 0x8000, 0, 0L);
  803. return TRUE;
  804. }
  805. case WM_PAINT:
  806. {
  807. SWaitDialog * pWD = (SWaitDialog *)GetWindowLongPtr (hwnd, DWLP_USER);
  808. if (pWD->GetWindow() == INVALID_HANDLE_VALUE) // already destructed!
  809. PostMessage (hwnd, 0x8000, 0, 0L);
  810. break;
  811. }
  812. case 0x8000:
  813. EndDialog (hwnd, 1);
  814. return TRUE;
  815. }
  816. return FALSE;
  817. }
  818. };
  819. HRESULT
  820. LoadSharingAndFirewallSettings(
  821. SADLG* pDlg )
  822. {
  823. CWaitDialog wd(pDlg->hwndOwner); // may be NULL
  824. HRESULT hr = S_OK;
  825. IHNetProtocolSettings *pProtSettings;
  826. ULONG ulCount;
  827. DWORD dwError;
  828. ASSERT(pDlg);
  829. //
  830. // Load the name of the computer
  831. //
  832. #ifndef DOWNLEVEL_CLIENT // downlevel client doesn't have this call
  833. ulCount = 0;
  834. if (!GetComputerNameEx(ComputerNameDnsHostname, NULL, &ulCount))
  835. {
  836. dwError = GetLastError();
  837. if (ERROR_MORE_DATA == dwError)
  838. {
  839. pDlg->ComputerName = (TCHAR*) Malloc(ulCount * sizeof(TCHAR));
  840. if (NULL != pDlg->ComputerName)
  841. {
  842. if (!GetComputerNameEx(
  843. ComputerNameDnsHostname,
  844. pDlg->ComputerName,
  845. &ulCount
  846. ))
  847. {
  848. hr = HRESULT_FROM_WIN32(GetLastError());
  849. }
  850. }
  851. else
  852. {
  853. hr = E_OUTOFMEMORY;
  854. }
  855. }
  856. else
  857. {
  858. hr = HRESULT_FROM_WIN32(dwError);
  859. }
  860. }
  861. else
  862. {
  863. //
  864. // Since we didn't pass in a buffer, this should never happen.
  865. //
  866. ASSERT(FALSE);
  867. hr = E_UNEXPECTED;
  868. }
  869. if (FAILED(hr))
  870. return hr;
  871. #else
  872. // downlevel client version
  873. TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1];
  874. DWORD dwSize = MAX_COMPUTERNAME_LENGTH+1;
  875. if (!GetComputerName (szComputerName, &dwSize))
  876. hr = HRESULT_FROM_WIN32(GetLastError());
  877. else {
  878. pDlg->ComputerName = _StrDup (szComputerName);
  879. if (!pDlg->ComputerName)
  880. hr = E_OUTOFMEMORY;
  881. }
  882. #endif
  883. // do downlevel and remote case here
  884. if (pDlg->pUPS) {
  885. CComPtr<IStaticPortMappingCollection> spSPMC = NULL;
  886. hr = GetCollectionFromService (pDlg->pUPS, &spSPMC);
  887. if (spSPMC) {
  888. CComPtr<IEnumVARIANT> spEV = NULL;
  889. CComPtr<IUnknown> spunk = NULL;
  890. hr = spSPMC->get__NewEnum (&spunk);
  891. if (spunk)
  892. hr = spunk->QueryInterface (
  893. __uuidof(IEnumVARIANT),
  894. (void**)&spEV);
  895. if (spEV) {
  896. CComVariant cv;
  897. while (S_OK == spEV->Next (1, &cv, NULL)) {
  898. if (V_VT (&cv) == VT_DISPATCH) {
  899. SAPM *pSAPortMap = NULL;
  900. hr = LoadRemotePortMappingEntry (V_DISPATCH (&cv), /* pDlg, */ &pSAPortMap);
  901. if (SUCCEEDED(hr))
  902. InsertTailList(&pDlg->PortMappings, &pSAPortMap->Link);
  903. }
  904. cv.Clear();
  905. }
  906. }
  907. }
  908. }
  909. // do stuff below iff not remote
  910. if (NULL != pDlg->pHNetConn)
  911. {
  912. IEnumHNetPortMappingBindings *pEnumBindings = NULL;
  913. //
  914. // Load port-mapping settings
  915. //
  916. hr = pDlg->pHNetConn->EnumPortMappings (FALSE, &pEnumBindings);
  917. if (SUCCEEDED(hr))
  918. {
  919. IHNetPortMappingBinding *pBinding;
  920. do
  921. {
  922. hr = pEnumBindings->Next (1, &pBinding, &ulCount);
  923. if (SUCCEEDED(hr) && 1 == ulCount)
  924. {
  925. SAPM *pSAPortMap;
  926. hr = LoadPortMappingEntry(pBinding, pDlg, &pSAPortMap);
  927. if (SUCCEEDED(hr))
  928. {
  929. InsertTailList(&pDlg->PortMappings, &pSAPortMap->Link);
  930. }
  931. else
  932. {
  933. //
  934. // Even though an error occured for this entry we'll
  935. // keep on going -- this allows the UI to show up.
  936. //
  937. hr = S_OK;
  938. }
  939. pBinding->Release();
  940. }
  941. } while (SUCCEEDED(hr) && 1 == ulCount);
  942. pEnumBindings->Release();
  943. }
  944. }
  945. return hr;
  946. }
  947. extern BOOL IsICSHost (); // in upnpnat.cpp
  948. VOID
  949. SasApply(
  950. SADLG* pDlg )
  951. // Called to save all changes made in the property sheet.
  952. //
  953. {
  954. if (!pDlg->fModified)
  955. {
  956. return;
  957. }
  958. if (pDlg->hwndServers)
  959. {
  960. SAPM* pPortMapping;
  961. #if DBG
  962. LONG i = -1;
  963. while ((i = ListView_GetNextItem(pDlg->hwndServers, i, LVNI_ALL))
  964. >= 0)
  965. {
  966. pPortMapping = (SAPM*)ListView_GetParamPtr(pDlg->hwndServers, i);
  967. ASSERT(pPortMapping->Enabled == ListView_GetCheck(pDlg->hwndServers, i));
  968. }
  969. #endif
  970. //
  971. // Commit modified port-mapping entries. Since entries marked
  972. // for deletion were placed at the front of the port-mapping
  973. // list there's no chance of having a new or modified entry
  974. // conflicting with a deleted entry.
  975. //
  976. HRESULT hr = S_OK;
  977. PLIST_ENTRY Link;
  978. for (Link = pDlg->PortMappings.Flink;
  979. Link != &pDlg->PortMappings; Link = Link->Flink)
  980. {
  981. pPortMapping = CONTAINING_RECORD(Link, SAPM, Link);
  982. if (pPortMapping->fDeleted)
  983. {
  984. Link = Link->Blink;
  985. RemoveEntryList(&pPortMapping->Link);
  986. if(NULL != pPortMapping->pProtocol)
  987. {
  988. pPortMapping->pProtocol->Delete();
  989. }
  990. else if (pPortMapping->pSPM)
  991. {
  992. HRESULT hr = DeleteRemotePortMappingEntry (pDlg, pPortMapping);
  993. if (FAILED(hr)) {
  994. // TODO: should I pop up some UI?
  995. }
  996. }
  997. FreePortMappingEntry(pPortMapping);
  998. }
  999. else if (pPortMapping->fProtocolModified
  1000. || pPortMapping->fBindingModified
  1001. || pPortMapping->fNewEntry)
  1002. {
  1003. HRESULT hr2 = SavePortMappingEntry(pDlg, pPortMapping);
  1004. if (SUCCEEDED(hr2))
  1005. {
  1006. pPortMapping->fProtocolModified = FALSE;
  1007. pPortMapping->fBindingModified = FALSE;
  1008. pPortMapping->fNewEntry = FALSE;
  1009. } else {
  1010. if (SUCCEEDED(hr))
  1011. hr = hr2; // grab first error
  1012. }
  1013. }
  1014. }
  1015. if (FAILED(hr)) {
  1016. if (pDlg->pUPS && !IsICSHost ())
  1017. DisplayError (pDlg->hwndDlg,
  1018. SID_OP_TheirGatewayError,
  1019. SID_PopupTitle);
  1020. else
  1021. DisplayError (pDlg->hwndDlg,
  1022. SID_OP_GenericPortMappingError,
  1023. SID_PopupTitle);
  1024. }
  1025. }
  1026. }
  1027. INT_PTR CALLBACK
  1028. SasSrvDlgProc(
  1029. HWND hwnd,
  1030. UINT unMsg,
  1031. WPARAM wparam,
  1032. LPARAM lparam )
  1033. // Called to handle messages for the 'Services' pages.
  1034. //
  1035. {
  1036. // Give the extended list-control a chance to look at all messages first.
  1037. //
  1038. if (ListView_OwnerHandler(hwnd, unMsg, wparam, lparam, SasLvxCallback))
  1039. {
  1040. return TRUE;
  1041. }
  1042. switch (unMsg)
  1043. {
  1044. case WM_INITDIALOG:
  1045. {
  1046. SADLG* pDlg = (SADLG*)((PROPSHEETPAGE*)lparam)->lParam;
  1047. return SrvInit(hwnd, pDlg);
  1048. }
  1049. case WM_PRIVATE_CANCEL:
  1050. {
  1051. SADLG* pDlg = SasContext(hwnd);
  1052. PostMessage (pDlg->hwndDlg, PSM_PRESSBUTTON, PSBTN_CANCEL, 0L);
  1053. return TRUE;
  1054. }
  1055. case WM_HELP:
  1056. case WM_CONTEXTMENU:
  1057. {
  1058. SADLG* pDlg = SasContext(hwnd);
  1059. ContextHelp(g_adwSrvHelp, hwnd, unMsg, wparam, lparam);
  1060. break;
  1061. }
  1062. case WM_COMMAND:
  1063. {
  1064. SADLG* pDlg = SasContext(hwnd);
  1065. return SrvCommand(
  1066. pDlg, HIWORD(wparam), LOWORD(wparam), (HWND)lparam);
  1067. }
  1068. case WM_NOTIFY:
  1069. {
  1070. SADLG* pDlg = SasContext(hwnd);
  1071. switch (((NMHDR*)lparam)->code)
  1072. {
  1073. case PSN_APPLY:
  1074. {
  1075. SasApply(pDlg);
  1076. return TRUE;
  1077. }
  1078. case NM_DBLCLK:
  1079. {
  1080. SendMessage(
  1081. GetDlgItem(hwnd, CID_SS_PB_Edit), BM_CLICK, 0, 0);
  1082. return TRUE;
  1083. }
  1084. case LVXN_SETCHECK:
  1085. {
  1086. pDlg->fModified = TRUE;
  1087. SrvUpdateButtons(
  1088. pDlg, FALSE, ((NM_LISTVIEW*)lparam)->iItem);
  1089. return TRUE;
  1090. }
  1091. case LVN_ITEMCHANGED:
  1092. {
  1093. if ((((NM_LISTVIEW*)lparam)->uNewState & LVIS_SELECTED)
  1094. != (((NM_LISTVIEW*)lparam)->uOldState & LVIS_SELECTED))
  1095. {
  1096. SrvUpdateButtons(
  1097. pDlg, FALSE, ((NM_LISTVIEW*)lparam)->iItem);
  1098. }
  1099. return TRUE;
  1100. }
  1101. }
  1102. break;
  1103. }
  1104. }
  1105. return FALSE;
  1106. }
  1107. BOOL
  1108. SasInit(
  1109. HWND hwndPage,
  1110. SADLG* pDlg )
  1111. // Called to initialize the settings property sheet.
  1112. // Sets the window-property in which the shared context-block is stored,
  1113. // and records the dialog's window-handle.
  1114. //
  1115. {
  1116. HWND hwndDlg = GetParent(hwndPage);
  1117. if (!SetProp(hwndDlg, _T("HNETCFG_SADLG"), pDlg))
  1118. {
  1119. return FALSE;
  1120. }
  1121. pDlg->hwndDlg = hwndDlg;
  1122. return TRUE;
  1123. }
  1124. LVXDRAWINFO*
  1125. SasLvxCallback(
  1126. HWND hwndLv,
  1127. DWORD dwItem )
  1128. // Callback for extended list-controls on the 'Applications' and 'Services'
  1129. // pages.
  1130. //
  1131. {
  1132. static LVXDRAWINFO info = { 1, 0, LVXDI_DxFill, { LVXDIA_Static } };
  1133. return &info;
  1134. }
  1135. HRESULT DeleteRemotePortMappingEntry (SADLG *pDlg, SAPM * pPortMapping)
  1136. {
  1137. _ASSERT (pPortMapping);
  1138. _ASSERT (!pPortMapping->pProtocol);
  1139. _ASSERT (!pPortMapping->pBinding);
  1140. _ASSERT (pPortMapping->pSPM);
  1141. // don't use value in pPortMapping struct: they could have been edited.
  1142. long lExternalPort = 0;
  1143. HRESULT hr = pPortMapping->pSPM->get_ExternalPort (&lExternalPort);
  1144. if (SUCCEEDED(hr)) {
  1145. CComBSTR cbProtocol;
  1146. hr = pPortMapping->pSPM->get_Protocol (&cbProtocol);
  1147. if (SUCCEEDED(hr)) {
  1148. // get IStaticPortMappings interface (collection has Remove method)
  1149. CComPtr<IStaticPortMappingCollection> spSPMC = NULL;
  1150. hr = GetStaticPortMappingCollection (pDlg, &spSPMC);
  1151. if (spSPMC)
  1152. hr = spSPMC->Remove (lExternalPort, cbProtocol);
  1153. }
  1154. }
  1155. return hr;
  1156. }
  1157. HRESULT
  1158. SaveRemotePortMappingEntry(
  1159. SADLG *pDlg,
  1160. SAPM *pPortMapping )
  1161. {
  1162. _ASSERT (pPortMapping);
  1163. _ASSERT (!pPortMapping->pProtocol);
  1164. _ASSERT (!pPortMapping->pBinding);
  1165. _ASSERT (pDlg->pUPS); // either remote or downlevel
  1166. USES_CONVERSION;
  1167. HRESULT hr = S_OK;
  1168. // common params
  1169. long lExternalPort = htons (pPortMapping->ExternalPort);
  1170. long lInternalPort = htons (pPortMapping->InternalPort);
  1171. CComBSTR cbClientIPorDNS = T2OLE(pPortMapping->InternalName);
  1172. CComBSTR cbDescription = T2OLE(pPortMapping->Title);
  1173. CComBSTR cbProtocol;
  1174. if (pPortMapping->Protocol == NAT_PROTOCOL_TCP)
  1175. cbProtocol = L"TCP";
  1176. else
  1177. cbProtocol = L"UDP";
  1178. if (NULL == pPortMapping->pSPM) {
  1179. // brand-new entry:
  1180. // delete dup if any
  1181. // add new entry
  1182. CComPtr<IStaticPortMappingCollection> spSPMC = NULL;
  1183. hr = GetStaticPortMappingCollection (pDlg, &spSPMC);
  1184. if (spSPMC) {
  1185. spSPMC->Remove (lExternalPort, cbProtocol); // just in case
  1186. hr = spSPMC->Add (lExternalPort,
  1187. cbProtocol,
  1188. lInternalPort,
  1189. cbClientIPorDNS,
  1190. pPortMapping->Enabled ? VARIANT_TRUE : VARIANT_FALSE,
  1191. cbDescription,
  1192. &pPortMapping->pSPM);
  1193. }
  1194. return hr;
  1195. }
  1196. // edited case: check what changed.
  1197. // if ports or protocol changed,...
  1198. long lOldExternalPort = 0;
  1199. pPortMapping->pSPM->get_ExternalPort (&lOldExternalPort);
  1200. CComBSTR cbOldProtocol;
  1201. pPortMapping->pSPM->get_Protocol (&cbOldProtocol);
  1202. if ((lOldExternalPort != lExternalPort) ||
  1203. (!(cbOldProtocol == cbProtocol))) {
  1204. // ... delete old entry and create new entry
  1205. CComPtr<IStaticPortMappingCollection> spSPMC = NULL;
  1206. hr = GetStaticPortMappingCollection (pDlg, &spSPMC);
  1207. if (spSPMC)
  1208. hr = spSPMC->Remove (lOldExternalPort, cbOldProtocol);
  1209. if (SUCCEEDED(hr)) {
  1210. pPortMapping->pSPM->Release();
  1211. pPortMapping->pSPM = NULL;
  1212. hr = spSPMC->Add (lExternalPort,
  1213. cbProtocol,
  1214. lInternalPort,
  1215. cbClientIPorDNS,
  1216. pPortMapping->Enabled ? VARIANT_TRUE : VARIANT_FALSE,
  1217. cbDescription,
  1218. &pPortMapping->pSPM);
  1219. }
  1220. return hr;
  1221. }
  1222. // else, just edit in place.
  1223. // Note that the client address must be filled out before trying to enable
  1224. // did the client IP address change?
  1225. CComBSTR cbOldClientIP;
  1226. pPortMapping->pSPM->get_InternalClient (&cbOldClientIP);
  1227. if (!(cbClientIPorDNS == cbOldClientIP)) {
  1228. hr = pPortMapping->pSPM->EditInternalClient (cbClientIPorDNS);
  1229. if (FAILED(hr))
  1230. return hr;
  1231. }
  1232. // did the internal port change?
  1233. long lOldInternalPort = 0;
  1234. pPortMapping->pSPM->get_InternalPort (&lOldInternalPort);
  1235. if (lOldInternalPort != lInternalPort) {
  1236. hr = pPortMapping->pSPM->EditInternalPort (lInternalPort);
  1237. if (FAILED(hr))
  1238. return hr;
  1239. }
  1240. // did the enabled flag change?
  1241. VARIANT_BOOL vbEnabled = FALSE;
  1242. pPortMapping->pSPM->get_Enabled (&vbEnabled);
  1243. if (vbEnabled != (pPortMapping->Enabled ? VARIANT_TRUE : VARIANT_FALSE)) {
  1244. hr = pPortMapping->pSPM->Enable (pPortMapping->Enabled ? VARIANT_TRUE : VARIANT_FALSE);
  1245. }
  1246. return hr;
  1247. }
  1248. HRESULT
  1249. SavePortMappingEntry(
  1250. SADLG *pDlg,
  1251. SAPM *pPortMapping )
  1252. {
  1253. if (pDlg->pUPS) // remote case
  1254. return SaveRemotePortMappingEntry (pDlg, pPortMapping);
  1255. HRESULT hr = S_OK;
  1256. OLECHAR *wszTitle;
  1257. ASSERT(NULL != pDlg);
  1258. ASSERT(NULL != pPortMapping);
  1259. wszTitle = StrDupWFromT(pPortMapping->Title);
  1260. if (NULL == wszTitle)
  1261. {
  1262. hr = E_OUTOFMEMORY;
  1263. }
  1264. else if (pPortMapping->fNewEntry)
  1265. {
  1266. IHNetProtocolSettings *pSettings;
  1267. ASSERT(NULL == pPortMapping->pProtocol);
  1268. ASSERT(NULL == pPortMapping->pBinding);
  1269. hr = pDlg->pHNetCfgMgr->QueryInterface (IID_IHNetProtocolSettings,
  1270. (void**)&pSettings);
  1271. if (SUCCEEDED(hr))
  1272. {
  1273. hr = pSettings->CreatePortMappingProtocol(
  1274. wszTitle,
  1275. pPortMapping->Protocol,
  1276. pPortMapping->ExternalPort,
  1277. &pPortMapping->pProtocol
  1278. );
  1279. pSettings->Release();
  1280. }
  1281. if (SUCCEEDED(hr))
  1282. {
  1283. hr = pDlg->pHNetConn->GetBindingForPortMappingProtocol(
  1284. pPortMapping->pProtocol,
  1285. &pPortMapping->pBinding
  1286. );
  1287. if (SUCCEEDED(hr))
  1288. {
  1289. //
  1290. // At this point, the protocol is set. However, we
  1291. // still need to save the binding information
  1292. //
  1293. pPortMapping->fProtocolModified = FALSE;
  1294. pPortMapping->fBindingModified = TRUE;
  1295. }
  1296. }
  1297. }
  1298. if (SUCCEEDED(hr) && pPortMapping->fProtocolModified)
  1299. {
  1300. hr = pPortMapping->pProtocol->SetName (wszTitle);
  1301. if (SUCCEEDED(hr))
  1302. {
  1303. hr = pPortMapping->pProtocol->SetIPProtocol (
  1304. pPortMapping->Protocol);
  1305. }
  1306. if (SUCCEEDED(hr))
  1307. {
  1308. hr = pPortMapping->pProtocol->SetPort (pPortMapping->ExternalPort);
  1309. }
  1310. }
  1311. if (SUCCEEDED(hr)
  1312. && pPortMapping->fBindingModified
  1313. && NULL != pPortMapping->InternalName)
  1314. {
  1315. ULONG ulAddress = INADDR_NONE;
  1316. if (lstrlen(pPortMapping->InternalName) >= 7)
  1317. {
  1318. //
  1319. // 1.2.3.4 -- minimum of 7 characters
  1320. //
  1321. ulAddress = IpPszToHostAddr(pPortMapping->InternalName);
  1322. }
  1323. if (INADDR_NONE == ulAddress)
  1324. {
  1325. //
  1326. // Check to see if the target name is either
  1327. // 1) this computer's name, or
  1328. // 2) "localhost"
  1329. //
  1330. // If so, use the loopback address instead of the name.
  1331. //
  1332. if (0 == _tcsicmp(pPortMapping->InternalName, pDlg->ComputerName)
  1333. || 0 == _tcsicmp(pPortMapping->InternalName, _T("localhost")))
  1334. {
  1335. ulAddress = LOOPBACK_ADDR_HOST_ORDER;
  1336. }
  1337. }
  1338. //
  1339. // We can't just check for INADDR_NONE here, since that
  1340. // is 0xFFFFFFFF, which is 255.255.255.255. To catch this
  1341. // we need to compare the name against that explicit string
  1342. // address.
  1343. //
  1344. if (INADDR_NONE == ulAddress
  1345. && 0 != _tcsicmp(pPortMapping->InternalName, _T("255.255.255.255")))
  1346. {
  1347. OLECHAR *wsz;
  1348. wsz = StrDupWFromT(pPortMapping->InternalName);
  1349. if (NULL != wsz)
  1350. {
  1351. hr = pPortMapping->pBinding->SetTargetComputerName (wsz);
  1352. Free(wsz);
  1353. }
  1354. else
  1355. {
  1356. hr = E_OUTOFMEMORY;
  1357. }
  1358. }
  1359. else
  1360. {
  1361. hr = pPortMapping->pBinding->SetTargetComputerAddress
  1362. (HTONL(ulAddress));
  1363. }
  1364. if (SUCCEEDED(hr))
  1365. {
  1366. hr = pPortMapping->pBinding->SetEnabled (!!pPortMapping->Enabled);
  1367. }
  1368. if (SUCCEEDED(hr))
  1369. {
  1370. hr = pPortMapping->pBinding->SetTargetPort (pPortMapping->InternalPort);
  1371. }
  1372. }
  1373. Free0(wszTitle);
  1374. return hr;
  1375. }
  1376. VOID
  1377. SrvAddOrEditEntry(
  1378. SADLG* pDlg,
  1379. LONG iItem,
  1380. SAPM* PortMapping )
  1381. // Called to display the 'Add' or 'Edit' dialog for a service.
  1382. //
  1383. {
  1384. LV_ITEM lvi;
  1385. // Display the dialog, and return if the user cancels.
  1386. // Otherwise, remove the old item (if any) and insert the added or edited
  1387. // item.
  1388. //
  1389. if (!SharedAccessPortMappingDlg(pDlg->hwndDlg, &PortMapping))
  1390. {
  1391. return;
  1392. }
  1393. if (iItem != -1)
  1394. {
  1395. ListView_DeleteItem(pDlg->hwndServers, iItem);
  1396. }
  1397. ZeroMemory(&lvi, sizeof(lvi));
  1398. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  1399. lvi.lParam = (LPARAM)PortMapping;
  1400. lvi.pszText = PortMapping->Title;
  1401. lvi.cchTextMax = lstrlen(PortMapping->Title) + 1;
  1402. lvi.iItem = 0;
  1403. iItem = ListView_InsertItem(pDlg->hwndServers, &lvi);
  1404. if (iItem == -1)
  1405. {
  1406. RemoveEntryList(&PortMapping->Link);
  1407. if (NULL != PortMapping->pProtocol)
  1408. {
  1409. PortMapping->pProtocol->Delete();
  1410. }
  1411. else if (NULL != PortMapping->pSPM)
  1412. {
  1413. DeleteRemotePortMappingEntry (pDlg, PortMapping);
  1414. }
  1415. FreePortMappingEntry(PortMapping);
  1416. return;
  1417. }
  1418. // Update the item's 'enabled' state. Setting the check on the item
  1419. // triggers an update of the button state as well as conflict detection.
  1420. // (See 'SrvUpdateButtons' and the LVXN_SETCHECK handling in 'SasDlgProc').
  1421. //
  1422. ListView_SetCheck(pDlg->hwndServers, iItem, PortMapping->Enabled);
  1423. ListView_SetItemState(
  1424. pDlg->hwndServers, iItem, LVIS_SELECTED, LVIS_SELECTED);
  1425. pDlg->fModified = TRUE;
  1426. }
  1427. BOOL
  1428. SrvCommand(
  1429. IN SADLG* pDlg,
  1430. IN WORD wNotification,
  1431. IN WORD wId,
  1432. IN HWND hwndCtrl )
  1433. // Called to process a 'WM_COMMAND' message from one of the page's buttons.
  1434. //
  1435. {
  1436. switch (wId)
  1437. {
  1438. case CID_SS_PB_Add:
  1439. {
  1440. SrvAddOrEditEntry(pDlg, -1, NULL);
  1441. return TRUE;
  1442. }
  1443. case CID_SS_PB_Edit:
  1444. {
  1445. LONG i = ListView_GetNextItem(pDlg->hwndServers, -1, LVNI_SELECTED);
  1446. SAPM* PortMapping;
  1447. if (i == -1)
  1448. {
  1449. MsgDlg(pDlg->hwndDlg, SID_NoModifySelection, NULL);
  1450. SetFocus(pDlg->hwndServers);
  1451. return FALSE;
  1452. }
  1453. PortMapping = (SAPM*)ListView_GetParamPtr(pDlg->hwndServers, i);
  1454. if (PortMapping)
  1455. {
  1456. SrvAddOrEditEntry(pDlg, i, PortMapping);
  1457. }
  1458. SetFocus(pDlg->hwndServers);
  1459. return TRUE;
  1460. }
  1461. case CID_SS_PB_Delete:
  1462. {
  1463. LONG i = ListView_GetNextItem(pDlg->hwndServers, -1, LVNI_SELECTED);
  1464. SAPM* PortMapping;
  1465. if (i == -1)
  1466. {
  1467. MsgDlg(pDlg->hwndDlg, SID_NoDeleteSelection, NULL);
  1468. SetFocus(pDlg->hwndServers);
  1469. return FALSE;
  1470. }
  1471. // Delete each selected item. Items with marked 'built-in'
  1472. // cannot be deleted, and are ignored.
  1473. //
  1474. do {
  1475. PortMapping = (SAPM*)ListView_GetParamPtr(pDlg->hwndServers, i);
  1476. if(NULL == PortMapping)
  1477. {
  1478. break;
  1479. }
  1480. if (PortMapping->BuiltIn)
  1481. {
  1482. ++i;
  1483. }
  1484. else
  1485. {
  1486. ListView_DeleteItem(pDlg->hwndServers, i);
  1487. --i;
  1488. //
  1489. // If this is a new entry we can immediately remove
  1490. // it from the list and free it; otherwise, we move
  1491. // it to the front of the list and mark it for
  1492. // deletion.
  1493. //
  1494. RemoveEntryList(&PortMapping->Link);
  1495. if (PortMapping->fNewEntry)
  1496. {
  1497. _ASSERT(NULL == PortMapping->pProtocol);
  1498. _ASSERT(NULL == PortMapping->pSPM);
  1499. FreePortMappingEntry(PortMapping);
  1500. }
  1501. else
  1502. {
  1503. InsertHeadList(&pDlg->PortMappings, &PortMapping->Link);
  1504. PortMapping->fDeleted = TRUE;
  1505. }
  1506. }
  1507. i = ListView_GetNextItem(pDlg->hwndServers, i, LVNI_SELECTED);
  1508. } while (i != -1);
  1509. // Update the dialog and synchronize the button-states with the
  1510. // current selection, if any.
  1511. //
  1512. pDlg->fModified = TRUE;
  1513. SetFocus(pDlg->hwndServers);
  1514. SrvUpdateButtons(pDlg, TRUE, -1);
  1515. return TRUE;
  1516. }
  1517. }
  1518. return TRUE;
  1519. }
  1520. BOOL
  1521. SrvConflictDetected(
  1522. SADLG* pDlg,
  1523. SAPM* PortMapping )
  1524. // Called to determine whether the given item conflicts with any other
  1525. // item and, if so, to display a message.
  1526. //
  1527. {
  1528. SAPM* Duplicate;
  1529. PLIST_ENTRY Link;
  1530. for (Link = pDlg->PortMappings.Flink;
  1531. Link != &pDlg->PortMappings; Link = Link->Flink)
  1532. {
  1533. Duplicate = CONTAINING_RECORD(Link, SAPM, Link);
  1534. if (PortMapping != Duplicate &&
  1535. !Duplicate->fDeleted &&
  1536. PortMapping->Protocol == Duplicate->Protocol &&
  1537. PortMapping->ExternalPort == Duplicate->ExternalPort)
  1538. {
  1539. MsgDlg(pDlg->hwndDlg, SID_DuplicatePortNumber, NULL);
  1540. return TRUE;
  1541. }
  1542. }
  1543. return FALSE;
  1544. }
  1545. BOOL
  1546. SrvInit(
  1547. HWND hwndPage,
  1548. SADLG* pDlg )
  1549. // Called to initialize the services page. Fills the list-control with
  1550. // configured services.
  1551. //
  1552. {
  1553. BOOL fModified;
  1554. LONG i;
  1555. LV_ITEM lvi;
  1556. PLIST_ENTRY Link;
  1557. SAPM* PortMapping;
  1558. // Initialize the containing property-sheet, then store this page's
  1559. // data in the shared control-block at 'pDlg'.
  1560. //
  1561. if (!SasInit(hwndPage, pDlg))
  1562. {
  1563. return FALSE;
  1564. }
  1565. // Store this page's data in the shared control-block at 'pDlg'.
  1566. //
  1567. pDlg->hwndSrv = hwndPage;
  1568. pDlg->hwndServers = GetDlgItem(hwndPage, CID_SS_LV_Services);
  1569. // Initialize the list-control with checkbox-handling,
  1570. // insert a single column, and fill the list-control with the configured
  1571. // items.
  1572. //
  1573. ListView_InstallChecks(pDlg->hwndServers, g_hinstDll);
  1574. ListView_InsertSingleAutoWidthColumn(pDlg->hwndServers);
  1575. fModified = pDlg->fModified;
  1576. for (Link = pDlg->PortMappings.Flink;
  1577. Link != &pDlg->PortMappings; Link = Link->Flink)
  1578. {
  1579. PortMapping = CONTAINING_RECORD(Link, SAPM, Link);
  1580. ZeroMemory(&lvi, sizeof(lvi));
  1581. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  1582. lvi.iItem = 0;
  1583. lvi.lParam = (LPARAM)PortMapping;
  1584. lvi.pszText = PortMapping->Title;
  1585. lvi.cchTextMax = lstrlen(PortMapping->Title) + 1;
  1586. i = ListView_InsertItem(pDlg->hwndServers, &lvi);
  1587. if (i != -1)
  1588. {
  1589. ListView_SetCheck(pDlg->hwndServers, i, PortMapping->Enabled);
  1590. }
  1591. }
  1592. pDlg->fModified = fModified;
  1593. // Finally, update the appearance of the buttons for the current selection.
  1594. //
  1595. ListView_SetItemState(pDlg->hwndServers, 0, LVIS_SELECTED, LVIS_SELECTED);
  1596. SrvUpdateButtons(pDlg, TRUE, -1);
  1597. // if we got no portmappings, check to see if the button allowing
  1598. // other network users to control the gateway is unchecked (on the host)
  1599. if (IsListEmpty (pDlg->PortMappings.Flink) &&
  1600. pDlg->pUPS && IsICSHost ()) {
  1601. // display error
  1602. DisplayError (pDlg->hwndDlg, SID_OP_OurGatewayError, SID_PopupTitle);
  1603. // cancel
  1604. PostMessage (hwndPage, WM_PRIVATE_CANCEL, 0, 0L);
  1605. }
  1606. return TRUE;
  1607. }
  1608. VOID
  1609. SrvUpdateButtons(
  1610. SADLG* pDlg,
  1611. BOOL fAddDelete,
  1612. LONG iSetCheckItem )
  1613. // Called to set an initial selection if necessary, update the appearance
  1614. // of the 'Edit' and 'Delete' buttons, and perform conflict-detection
  1615. // if an entry's checkbox was set.
  1616. //
  1617. {
  1618. LONG i;
  1619. SAPM* PortMapping;
  1620. // If an entry was added or removed, ensure that there is a selection.
  1621. // If there are no entries at all, disable the 'Edit' button.
  1622. //
  1623. if (fAddDelete)
  1624. {
  1625. if (ListView_GetItemCount(pDlg->hwndServers))
  1626. {
  1627. ListView_SetItemState(
  1628. pDlg->hwndServers, 0, LVIS_SELECTED, LVIS_SELECTED);
  1629. EnableWindow(GetDlgItem(pDlg->hwndSrv, CID_SS_PB_Edit), TRUE);
  1630. }
  1631. else
  1632. {
  1633. EnableWindow(GetDlgItem(pDlg->hwndSrv, CID_SS_PB_Edit), FALSE);
  1634. }
  1635. }
  1636. // Disable the 'Delete' button, and enable it only if at least one of the
  1637. // selected items is not a built-in item.
  1638. //
  1639. EnableWindow(GetDlgItem(pDlg->hwndSrv, CID_SS_PB_Delete), FALSE);
  1640. i = ListView_GetNextItem(pDlg->hwndServers, -1, LVNI_SELECTED);
  1641. while (i != -1)
  1642. {
  1643. PortMapping = (SAPM*)ListView_GetParamPtr(pDlg->hwndServers, i);
  1644. if ( (NULL != PortMapping)
  1645. && (!PortMapping->BuiltIn))
  1646. {
  1647. EnableWindow(GetDlgItem(pDlg->hwndSrv, CID_SS_PB_Delete), TRUE);
  1648. break;
  1649. }
  1650. i = ListView_GetNextItem(pDlg->hwndServers, i, LVNI_SELECTED);
  1651. }
  1652. // If the check-state of an item was changed and the item is now checked,
  1653. // perform conflict-detection. If a conflict is detected, clear the item's
  1654. // check state.
  1655. //
  1656. if (iSetCheckItem != -1)
  1657. {
  1658. PortMapping =
  1659. (SAPM*)ListView_GetParamPtr(pDlg->hwndServers, iSetCheckItem);
  1660. if(NULL == PortMapping)
  1661. {
  1662. return;
  1663. }
  1664. if (ListView_GetCheck(pDlg->hwndServers, iSetCheckItem))
  1665. {
  1666. if (SrvConflictDetected(pDlg, PortMapping))
  1667. {
  1668. ListView_SetCheck(pDlg->hwndServers, iSetCheckItem, FALSE);
  1669. SrvAddOrEditEntry(pDlg, iSetCheckItem, PortMapping);
  1670. }
  1671. else
  1672. {
  1673. PortMapping->Enabled = TRUE;
  1674. PortMapping->fBindingModified = TRUE;
  1675. // If the item is marked 'built-in' and it is being enabled
  1676. // for the first time, pop up the edit-dialog so the user can
  1677. // specify an internal IP address or name for the server.
  1678. //
  1679. if (/* Bug 630840: a similar scenario can happen when you
  1680. create the "same" port mapping on two NICs:
  1681. the second one's per NIC info is missing, and
  1682. when enabling it, the code below needs to run.
  1683. PortMapping->BuiltIn &&
  1684. */
  1685. (!PortMapping->InternalName
  1686. || !lstrlen(PortMapping->InternalName)))
  1687. {
  1688. //
  1689. // We fill in the local computer name as the default
  1690. // target. It's OK if this allocation fails; the UI
  1691. // will show an empty field, so the user will be
  1692. // required to enter a target.
  1693. //
  1694. PortMapping->InternalName = _StrDup(pDlg->ComputerName);
  1695. SrvAddOrEditEntry(pDlg, iSetCheckItem, PortMapping);
  1696. if (!PortMapping->InternalName
  1697. || !lstrlen(PortMapping->InternalName))
  1698. {
  1699. ListView_SetCheck(
  1700. pDlg->hwndServers, iSetCheckItem, FALSE);
  1701. PortMapping->Enabled = FALSE;
  1702. PortMapping->fBindingModified = FALSE;
  1703. }
  1704. }
  1705. }
  1706. }
  1707. else
  1708. {
  1709. PortMapping->Enabled = FALSE;
  1710. PortMapping->fBindingModified = TRUE;
  1711. }
  1712. }
  1713. }
  1714. BOOL
  1715. SharedAccessPortMappingDlg(
  1716. IN HWND hwndOwner,
  1717. IN OUT SAPM** PortMapping )
  1718. // Called to display the dialog for adding or editing a service-entry.
  1719. // 'Server' points to NULL if adding, or the target entry if editing.
  1720. //
  1721. {
  1722. LRESULT nResult =
  1723. DialogBoxParam(g_hinstDll, MAKEINTRESOURCE(DID_SS_Service),
  1724. hwndOwner, SspDlgProc, (LPARAM)PortMapping);
  1725. return nResult == -1 ? FALSE : (BOOL)nResult;
  1726. }
  1727. INT_PTR CALLBACK
  1728. SspDlgProc(
  1729. IN HWND hwnd,
  1730. IN UINT unMsg,
  1731. IN WPARAM wparam,
  1732. IN LPARAM lparam )
  1733. // Called to handle messages for the add/edit service dialog.
  1734. //
  1735. {
  1736. switch (unMsg)
  1737. {
  1738. case WM_INITDIALOG:
  1739. {
  1740. SADLG* pDlg;
  1741. SAPM* PortMapping;
  1742. // Retrieve the context-block for the settings dialog from which
  1743. // this dialog was launched.
  1744. //
  1745. if (!(pDlg = SasContext(hwnd)))
  1746. {
  1747. EndDialog(hwnd, FALSE);
  1748. return TRUE;
  1749. }
  1750. Edit_LimitText(GetDlgItem(hwnd, CID_SS_EB_ExternalPort), 5);
  1751. Edit_LimitText(GetDlgItem(hwnd, CID_SS_EB_InternalPort), 5);
  1752. Edit_LimitText(GetDlgItem(hwnd, CID_SS_EB_Service), INTERNET_MAX_HOST_NAME_LENGTH-1);
  1753. Edit_LimitText(GetDlgItem(hwnd, CID_SS_EB_Address), INTERNET_MAX_HOST_NAME_LENGTH-1);
  1754. // Create new service if adding a service, or retrieve the service
  1755. // to be edited.
  1756. //
  1757. if (!(PortMapping = *(SAPM**)lparam))
  1758. {
  1759. PortMapping = (SAPM*)Malloc(sizeof(*PortMapping));
  1760. if (!PortMapping)
  1761. {
  1762. EndDialog(hwnd, FALSE);
  1763. return TRUE;
  1764. }
  1765. *(SAPM**)lparam = PortMapping;
  1766. ZeroMemory(PortMapping, sizeof(*PortMapping));
  1767. PortMapping->Enabled = TRUE;
  1768. PortMapping->fNewEntry = TRUE;
  1769. InitializeListHead(&PortMapping->Link);
  1770. CheckDlgButton(hwnd, CID_SS_PB_Tcp, TRUE);
  1771. }
  1772. else
  1773. {
  1774. EnableWindow(GetDlgItem(hwnd, CID_SS_EB_Service), FALSE);
  1775. SetDlgItemText(hwnd, CID_SS_EB_Service, PortMapping->Title);
  1776. SetDlgItemInt(hwnd, CID_SS_EB_ExternalPort, ntohs(PortMapping->ExternalPort), FALSE);
  1777. SetDlgItemInt(hwnd, CID_SS_EB_InternalPort, ntohs(PortMapping->InternalPort), FALSE);
  1778. CheckDlgButton(
  1779. hwnd, CID_SS_PB_Tcp, PortMapping->Protocol == NAT_PROTOCOL_TCP);
  1780. CheckDlgButton(
  1781. hwnd, CID_SS_PB_Udp, PortMapping->Protocol != NAT_PROTOCOL_TCP);
  1782. SetDlgItemText(hwnd, CID_SS_EB_Address, PortMapping->InternalName);
  1783. // If the entry to be modified is marked 'built-in', disable
  1784. // all input fields except the server-name, which the user must
  1785. // now enter.
  1786. //
  1787. if (PortMapping->BuiltIn)
  1788. {
  1789. EnableWindow(GetDlgItem(hwnd, CID_SS_EB_ExternalPort), FALSE);
  1790. EnableWindow(GetDlgItem(hwnd, CID_SS_EB_InternalPort), FALSE);
  1791. EnableWindow(GetDlgItem(hwnd, CID_SS_PB_Tcp), FALSE);
  1792. EnableWindow(GetDlgItem(hwnd, CID_SS_PB_Udp), FALSE);
  1793. }
  1794. }
  1795. SetWindowLongPtr(hwnd, DWLP_USER, (ULONG_PTR)PortMapping);
  1796. CenterWindow(hwnd, GetParent(hwnd));
  1797. AddContextHelpButton(hwnd);
  1798. return TRUE;
  1799. }
  1800. case WM_HELP:
  1801. case WM_CONTEXTMENU:
  1802. {
  1803. ContextHelp( g_adwSspHelp, hwnd, unMsg, wparam, lparam );
  1804. break;
  1805. }
  1806. case WM_COMMAND:
  1807. {
  1808. if (HIWORD(wparam) != BN_CLICKED) { return FALSE; }
  1809. // If the user is dismissing the dialog, clean up and return.
  1810. //
  1811. SAPM* PortMapping;
  1812. SADLG* pDlg;
  1813. if (IDCANCEL == LOWORD(wparam))
  1814. {
  1815. PortMapping = (SAPM*)GetWindowLongPtr(hwnd, DWLP_USER);
  1816. if (IsListEmpty(&PortMapping->Link))
  1817. {
  1818. FreePortMappingEntry(PortMapping);
  1819. }
  1820. EndDialog (hwnd, FALSE);
  1821. return TRUE;
  1822. }
  1823. else if (LOWORD(wparam) != IDOK)
  1824. {
  1825. return FALSE;
  1826. }
  1827. else if (!(pDlg = SasContext(hwnd)))
  1828. {
  1829. return FALSE;
  1830. }
  1831. // Retrieve the service to be added or modified.
  1832. //
  1833. PortMapping = (SAPM*)GetWindowLongPtr(hwnd, DWLP_USER);
  1834. // Retrieve the values specified by the user,
  1835. // and attempt to save them in the new or modified entry.
  1836. //
  1837. UCHAR Protocol = IsDlgButtonChecked(hwnd, CID_SS_PB_Tcp)
  1838. ? NAT_PROTOCOL_TCP : NAT_PROTOCOL_UDP;
  1839. BOOL Success;
  1840. ULONG ExternalPort = GetDlgItemInt(hwnd, CID_SS_EB_ExternalPort, &Success, FALSE);
  1841. if (!Success || ExternalPort < 1 || ExternalPort > 65535)
  1842. {
  1843. MsgDlg(hwnd, SID_TypePortNumber, NULL);
  1844. SetFocus(GetDlgItem(hwnd, CID_SS_EB_ExternalPort));
  1845. return FALSE;
  1846. }
  1847. ExternalPort = htons((USHORT)ExternalPort);
  1848. //
  1849. // Check to see if this is a duplicate. To do this we need
  1850. // to save the old port and protocol values, put the new
  1851. // values into the protocol entry, perform the check, and
  1852. // then restore the old values.
  1853. //
  1854. USHORT OldExternalPort = PortMapping->ExternalPort;
  1855. PortMapping->ExternalPort = (USHORT)ExternalPort;
  1856. UCHAR OldProtocol = PortMapping->Protocol;
  1857. PortMapping->Protocol = Protocol;
  1858. if (SrvConflictDetected(pDlg, PortMapping))
  1859. {
  1860. PortMapping->ExternalPort = OldExternalPort;
  1861. PortMapping->Protocol = OldProtocol;
  1862. SetFocus(GetDlgItem(hwnd, CID_SS_EB_ExternalPort));
  1863. return FALSE;
  1864. }
  1865. PortMapping->ExternalPort = OldExternalPort;
  1866. PortMapping->Protocol = OldProtocol;
  1867. // per BillI, there's no need to test internal ports for conflicts
  1868. ULONG InternalPort = GetDlgItemInt(hwnd, CID_SS_EB_InternalPort, &Success, FALSE);
  1869. if (InternalPort == 0)
  1870. InternalPort = ExternalPort;
  1871. else {
  1872. if (InternalPort < 1 || InternalPort > 65535)
  1873. {
  1874. MsgDlg(hwnd, SID_TypePortNumber, NULL);
  1875. SetFocus(GetDlgItem(hwnd, CID_SS_EB_InternalPort));
  1876. return FALSE;
  1877. }
  1878. InternalPort = htons((USHORT)InternalPort);
  1879. }
  1880. TCHAR* InternalName = GetText(GetDlgItem(hwnd, CID_SS_EB_Address));
  1881. if (!InternalName || !lstrlen(InternalName))
  1882. {
  1883. MsgDlg(hwnd, SID_SS_TypeAddress, NULL);
  1884. SetFocus(GetDlgItem(hwnd, CID_SS_EB_Address));
  1885. return FALSE;
  1886. }
  1887. if (IsListEmpty(&PortMapping->Link))
  1888. {
  1889. PortMapping->Title = GetText(GetDlgItem(hwnd, CID_SS_EB_Service));
  1890. if (!PortMapping->Title || !lstrlen(PortMapping->Title))
  1891. {
  1892. MsgDlg(hwnd, SID_TypeEntryName, NULL);
  1893. SetFocus(GetDlgItem(hwnd, CID_SS_EB_Service));
  1894. Free0(InternalName);
  1895. return FALSE;
  1896. }
  1897. }
  1898. if (PortMapping->Protocol != Protocol ||
  1899. PortMapping->ExternalPort != (USHORT)ExternalPort ||
  1900. PortMapping->InternalPort != (USHORT)InternalPort)
  1901. {
  1902. PortMapping->fProtocolModified = TRUE;
  1903. }
  1904. PortMapping->fBindingModified = TRUE;
  1905. PortMapping->Protocol = Protocol;
  1906. PortMapping->ExternalPort = (USHORT)ExternalPort;
  1907. PortMapping->InternalPort = (USHORT)InternalPort;
  1908. if (PortMapping->InternalName)
  1909. {
  1910. Free(PortMapping->InternalName);
  1911. }
  1912. PortMapping->InternalName = InternalName;
  1913. if (IsListEmpty(&PortMapping->Link))
  1914. {
  1915. InsertTailList(&pDlg->PortMappings, &PortMapping->Link);
  1916. }
  1917. EndDialog (hwnd, TRUE);
  1918. return TRUE;
  1919. }
  1920. }
  1921. return FALSE;
  1922. }