Source code of Windows XP (NT5)
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.

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