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.

781 lines
24 KiB

  1. /*++
  2. Copyright(c) 1998,99 Microsoft Corporation
  3. Module Name:
  4. CommonClusterPage.cpp
  5. Abstract:
  6. Windows Load Balancing Service (WLBS)
  7. Cluster page UI. Shared by Notifier object and NLB Manager
  8. Author:
  9. kyrilf
  10. shouse
  11. // History:
  12. // --------
  13. //
  14. // Revised by : mhakim
  15. // Date : 02-09-01
  16. // Reason : Igmp box was enabled when it needed to be grayed out.
  17. //
  18. // Revised by : mhakim
  19. // Date : 02-12-01
  20. // Reason : Mac address was not being retrieved fully.
  21. --*/
  22. //
  23. // To share the code with notifier object
  24. // share string resurce
  25. // share the common structure
  26. // call SetChangedFlag() in OnInitDialog
  27. // add trace, assert
  28. // Share help file and add help handler
  29. //
  30. //
  31. #include "stdafx.h"
  32. #include <stdio.h>
  33. #include <process.h>
  34. #include "CommonClusterPage.h"
  35. #include "wlbsconfig.h"
  36. #include "wlbsutil.h"
  37. #define DUMMY_PASSWORD L"somepassword"
  38. #define EMPTY_PASSWORD L""
  39. //
  40. // No trace/assert for now
  41. //
  42. #define TraceMsg(x)
  43. #define Assert(x)
  44. //+---------------------------------------------------------------------------
  45. //
  46. // Function: SzLoadStringPcch
  47. //
  48. // Purpose: Load a resource string. (This function will never return NULL.)
  49. //
  50. // Arguments:
  51. // hinst [in] Instance handle of module with the string resource.
  52. // unId [in] Resource ID of the string to load.
  53. // pcch [out] Pointer to returned character length.
  54. //
  55. // Returns: Pointer to the constant string.
  56. //
  57. // Author: shaunco 24 Mar 1997
  58. // fengsun copied from net\config\common\ncbase\ncstring.cpp
  59. //
  60. // Notes: The loaded string is pointer directly into the read-only
  61. // resource section. Any attempt to write through this pointer
  62. // will generate an access violation.
  63. //
  64. // The implementations is referenced from "Win32 Binary Resource
  65. // Formats" (MSDN) 4.8 String Table Resources
  66. //
  67. // User must have RCOPTIONS = -N turned on in your sources file.
  68. //
  69. PCWSTR
  70. SzLoadStringPcch (
  71. IN HINSTANCE hinst,
  72. IN UINT unId,
  73. OUT int* pcch)
  74. {
  75. Assert(hinst);
  76. Assert(unId);
  77. Assert(pcch);
  78. static const WCHAR c_szSpace[] = L" ";
  79. PCWSTR psz = c_szSpace;
  80. int cch = 1;
  81. // String Tables are broken up into 16 string segments. Find the segment
  82. // containing the string we are interested in.
  83. HRSRC hrsrcInfo = FindResource (hinst,
  84. (PWSTR)ULongToPtr( ((LONG)(((USHORT)unId >> 4) + 1)) ),
  85. RT_STRING);
  86. if (hrsrcInfo)
  87. {
  88. // Page the resource segment into memory.
  89. HGLOBAL hglbSeg = LoadResource (hinst, hrsrcInfo);
  90. if (hglbSeg)
  91. {
  92. // Lock the resource.
  93. psz = (PCWSTR)LockResource(hglbSeg);
  94. if (psz)
  95. {
  96. // Move past the other strings in this segment.
  97. // (16 strings in a segment -> & 0x0F)
  98. unId &= 0x0F;
  99. cch = 0;
  100. do
  101. {
  102. psz += cch; // Step to start of next string
  103. cch = *((WCHAR*)psz++); // PASCAL like string count
  104. }
  105. while (unId--);
  106. // If we have a non-zero count, it includes the
  107. // null-terminiator. Subtract this off for the return value.
  108. //
  109. if (cch)
  110. {
  111. cch--;
  112. }
  113. else
  114. {
  115. // AssertSz(0, "String resource not found");
  116. psz = c_szSpace;
  117. cch = 1;
  118. }
  119. }
  120. else
  121. {
  122. psz = c_szSpace;
  123. cch = 1;
  124. // TraceLastWin32Error("SzLoadStringPcch: LockResource failed.");
  125. }
  126. }
  127. // else
  128. // TraceLastWin32Error("SzLoadStringPcch: LoadResource failed.");
  129. }
  130. // else
  131. // TraceLastWin32Error("SzLoadStringPcch: FindResource failed.");
  132. *pcch = cch;
  133. Assert(*pcch);
  134. Assert(psz);
  135. return psz;
  136. }
  137. //+---------------------------------------------------------------------------
  138. //
  139. // Function: SzLoadString
  140. //
  141. // Purpose: Load a resource string. (This function will never return NULL.)
  142. //
  143. // Arguments:
  144. // hinst [in] Instance handle of module with the string resource.
  145. // unId [in] Resource ID of the string to load.
  146. //
  147. // Returns: Pointer to the constant string.
  148. //
  149. // Author: shaunco 24 Mar 1997
  150. // fengsun copied from net\config\common\ncbase\ncstring.cpp
  151. //
  152. // Notes: See SzLoadStringPcch()
  153. //
  154. PCWSTR
  155. SzLoadString (
  156. HINSTANCE hinst,
  157. UINT unId)
  158. {
  159. int cch;
  160. return SzLoadStringPcch(hinst, unId, &cch);
  161. }
  162. //+---------------------------------------------------------------------------
  163. //
  164. // Function: NcMsgBox
  165. //
  166. // Purpose: Displays a message box using resource strings and replaceable
  167. // parameters.
  168. //
  169. // Arguments:
  170. // hinst [in] hinstance for resource strings
  171. // hwnd [in] parent window handle
  172. // unIdCaption [in] resource id of caption string
  173. // unIdFormat [in] resource id of text string (with %1, %2, etc.)
  174. // unStyle [in] standard message box styles
  175. // ... [in] replaceable parameters (optional)
  176. // (these must be PCWSTRs as that is all
  177. // FormatMessage handles.)
  178. //
  179. // Returns: the return value of MessageBox()
  180. //
  181. // Author: shaunco 24 Mar 1997
  182. // fengsun copied from net\config\common\ncbase\ncui.cpp
  183. //
  184. // Notes: FormatMessage is used to do the parameter substitution.
  185. //
  186. INT
  187. WINAPIV
  188. NcMsgBox (
  189. IN HINSTANCE hinst,
  190. IN HWND hwnd,
  191. IN UINT unIdCaption,
  192. IN UINT unIdFormat,
  193. IN UINT unStyle,
  194. IN ...)
  195. {
  196. PCWSTR pszCaption = SzLoadString (hinst, unIdCaption);
  197. PCWSTR pszFormat = SzLoadString (hinst, unIdFormat);
  198. PWSTR pszText = NULL;
  199. va_list val;
  200. va_start (val, unStyle);
  201. FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  202. pszFormat, 0, 0, (PWSTR)&pszText, 0, &val);
  203. va_end (val);
  204. INT nRet = MessageBox (hwnd, pszText, pszCaption, unStyle);
  205. LocalFree (pszText);
  206. return nRet;
  207. }
  208. //+----------------------------------------------------------------------------
  209. //
  210. // Function: CCommonClusterPage::CCommonClusterPage
  211. //
  212. // Description:
  213. //
  214. // Arguments: HINSTANCE hInstance - instance handle for string resources
  215. // NETCFG_WLBS_CONFIG * paramp - IN/OUT NLB properties
  216. // bool fDisablePassword - whether do disable password editing
  217. // const DWORD * adwHelpIDs - a list of help ID pairs, or NULL.
  218. // The pointer has to be valid through the lifetime of this dialog.
  219. //
  220. // Returns: Nothing
  221. //
  222. // History: fengsun Created Header 1/4/01
  223. //
  224. //+----------------------------------------------------------------------------
  225. CCommonClusterPage::CCommonClusterPage(HINSTANCE hInstance,
  226. NETCFG_WLBS_CONFIG * paramp,
  227. bool fDisablePassword, const DWORD * adwHelpIDs) :
  228. m_IpSubnetControl(IDC_EDIT_CL_IP, IDC_EDIT_CL_MASK)
  229. {
  230. TraceMsg(L"CCommonClusterPage::CCommonClusterPage\n");
  231. m_paramp = paramp;
  232. m_adwHelpIDs = adwHelpIDs;
  233. m_rct_warned = FALSE;
  234. m_igmp_warned = FALSE;
  235. m_igmp_mcast_warned = FALSE;
  236. m_hInstance = hInstance;
  237. m_fDisablePassword = fDisablePassword;
  238. }
  239. /*
  240. * Method: CCommonClusterPage
  241. * Description: The class destructor.
  242. */
  243. CCommonClusterPage::~CCommonClusterPage () {
  244. TraceMsg(L"CCommonClusterPage::~CCommonClusterPage\n");
  245. }
  246. /*
  247. * Method: OnInitDialog
  248. * Description: Called to initialize the cluster properties dialog.
  249. */
  250. LRESULT CCommonClusterPage::OnInitDialog (HWND hWnd)
  251. {
  252. TraceMsg(L"CCommonClusterPage::OnInitDialog\n");
  253. m_hWnd = hWnd;
  254. /* Limit the field ranges for the address and password fields. */
  255. ::SendDlgItemMessage(m_hWnd, IDC_EDIT_DOMAIN, EM_SETLIMITTEXT, CVY_MAX_DOMAIN_NAME, 0);
  256. ::SendDlgItemMessage(m_hWnd, IDC_EDIT_ETH, EM_SETLIMITTEXT, CVY_MAX_NETWORK_ADDR, 0);
  257. ::SendDlgItemMessage(m_hWnd, IDC_EDIT_PASSW, EM_SETLIMITTEXT, CVY_MAX_RCT_CODE, 0);
  258. ::SendDlgItemMessage(m_hWnd, IDC_EDIT_PASSW2, EM_SETLIMITTEXT, CVY_MAX_RCT_CODE, 0);
  259. /* Disable the MAC address field. It should be read-only. */
  260. if (m_paramp->fConvertMac) ::EnableWindow(::GetDlgItem (m_hWnd, IDC_EDIT_ETH), FALSE);
  261. m_IpSubnetControl.OnInitDialog(m_hWnd, AfxGetInstanceHandle());
  262. return 0;
  263. }
  264. /*
  265. * Method: OnContextMenu
  266. * Description:
  267. */
  268. LRESULT CCommonClusterPage::OnContextMenu ()
  269. {
  270. TraceMsg(L"CCommonClusterPage::OnContextMenu\n");
  271. /* Spawn a help window. */
  272. if (m_adwHelpIDs != NULL)
  273. ::WinHelp(m_hWnd, CVY_CTXT_HELP_FILE, HELP_CONTEXTMENU, (ULONG_PTR)m_adwHelpIDs);
  274. return 0;
  275. }
  276. /*
  277. * Method: OnHelp
  278. * Description:
  279. */
  280. LRESULT CCommonClusterPage::OnHelp (UINT uMsg, WPARAM wParam, LPARAM lParam) {
  281. TraceMsg(L"CCommonClusterPage::OnHelp\n");
  282. LPHELPINFO lphi = reinterpret_cast<LPHELPINFO>(lParam);
  283. /* Spawn a help window. */
  284. if ((HELPINFO_WINDOW == lphi->iContextType) && (m_adwHelpIDs != NULL))
  285. ::WinHelp(static_cast<HWND>(lphi->hItemHandle), CVY_CTXT_HELP_FILE, HELP_WM_HELP, (ULONG_PTR)m_adwHelpIDs);
  286. return 0;
  287. }
  288. /*
  289. * Method: OnActive
  290. * Description: Called when the cluster settings tab becomes active (is clicked).
  291. */
  292. LRESULT CCommonClusterPage::OnActive (int idCtrl, LPNMHDR pnmh, BOOL & fHandled)
  293. {
  294. TraceMsg(L"CCommonClusterPage::OnActive\n");
  295. /* Populate the UI with the current configuration. */
  296. SetInfo();
  297. //
  298. // NLB mamager always has password editing disabled
  299. //
  300. /* Enable/disable the password entry boxes based on the state of the remote control checkbox.
  301. Edited( mhakim 02-09-01)
  302. but only when remote control is enabled.
  303. */
  304. ::EnableWindow(::GetDlgItem(m_hWnd, IDC_EDIT_PASSW),
  305. ::IsDlgButtonChecked(m_hWnd, IDC_CHECK_RCT)
  306. &&
  307. ::IsWindowEnabled( ::GetDlgItem( m_hWnd, IDC_CHECK_RCT ) ) );
  308. ::EnableWindow(::GetDlgItem(m_hWnd, IDC_EDIT_PASSW2),
  309. ::IsDlgButtonChecked(m_hWnd, IDC_CHECK_RCT)
  310. &&
  311. ::IsWindowEnabled( ::GetDlgItem( m_hWnd, IDC_CHECK_RCT ) ) );
  312. /* Enable/disable the IGMP checkbox based on the state of the multicast checkbox.
  313. Edited( mhakim 02-09-01)
  314. but only when multicast button is enabled.
  315. */
  316. ::EnableWindow(::GetDlgItem(m_hWnd, IDC_CHECK_IGMP),
  317. ::IsDlgButtonChecked (m_hWnd, IDC_RADIO_MULTICAST)
  318. &&
  319. ::IsWindowEnabled( ::GetDlgItem( m_hWnd, IDC_RADIO_MULTICAST) ) );
  320. /* Fill in the cluster MAC address, based on the values of multicast, IGMP, and the cluster IP. */
  321. SetClusterMACAddress();
  322. ::SetWindowLongPtr(m_hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);
  323. return 0;
  324. }
  325. /*
  326. * Method: OnKillActive
  327. * Description: Called When the focus moves away from the cluster settings tab.
  328. */
  329. LRESULT CCommonClusterPage::OnKillActive (int idCtrl, LPNMHDR pnmh, BOOL & fHandled)
  330. {
  331. TraceMsg(L"CCommonClusterPage::OnKillActive\n");
  332. /* Get the new configuration from the UI. */
  333. UpdateInfo();
  334. ::SetWindowLongPtr(m_hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);
  335. return 0;
  336. }
  337. /*
  338. * Method: OnApply
  339. * Description: Called when the user clicks "OK".
  340. */
  341. LRESULT CCommonClusterPage::OnApply (int idCtrl, LPNMHDR pnmh, BOOL & fHandled)
  342. {
  343. LRESULT fError = PSNRET_NOERROR;
  344. TraceMsg(L"CCommonClusterPage::OnApply\n");
  345. /* Validate the UI values entered by the user. */
  346. fError = ValidateInfo();
  347. ::SetWindowLongPtr(m_hWnd, DWLP_MSGRESULT, fError);
  348. return fError;
  349. }
  350. /*
  351. * Method: OnCancel
  352. * Description: Called when the user clicks "Cancel".
  353. */
  354. LRESULT CCommonClusterPage::OnCancel (int idCtrl, LPNMHDR pnmh, BOOL & fHandled)
  355. {
  356. TraceMsg(L"CCommonClusterPage::OnCancel\n");
  357. return 0;
  358. }
  359. /*
  360. * Method: OnButtonHelp
  361. * Description: Called when the user clicks the NLB "Help" button.
  362. */
  363. LRESULT CCommonClusterPage::OnButtonHelp (WORD wNotifyCode, WORD wID, HWND hWndCtl) {
  364. WCHAR wbuf[CVY_STR_SIZE];
  365. TraceMsg(L"CCommonClusterPage::OnButtonHelp\n");
  366. switch (wNotifyCode) {
  367. case BN_CLICKED:
  368. /* Spawn the windows help process. */
  369. swprintf(wbuf, L"%%WINDIR%%\\help\\%ls::/installation.htm", CVY_HELP_FILE);
  370. _wspawnlp(P_NOWAIT, L"hh.exe", L"hh.exe", wbuf, NULL);
  371. break;
  372. }
  373. return 0;
  374. }
  375. /*
  376. * Method: OnEditClIp
  377. * Description: Called when the user edits the cluster IP address.
  378. */
  379. LRESULT CCommonClusterPage::OnEditClIp (WORD wNotifyCode, WORD wID, HWND hWndCtl) {
  380. TraceMsg(L"CCommonClusterPage::OnEditClIp\n");
  381. switch (wNotifyCode) {
  382. case EN_CHANGE:
  383. /* Update the cluster MAC address. */
  384. SetClusterMACAddress();
  385. break;
  386. }
  387. return 0;
  388. }
  389. /*
  390. * Method: OnIpFieldChange
  391. * Description: Called wnen a field (byte) of the cluster IP address changes. We use this
  392. * to make sure the first byte of the IP is not < 1 or > 223.
  393. */
  394. LRESULT CCommonClusterPage::OnIpFieldChange (int idCtrl, LPNMHDR pnmh, BOOL & fHandled)
  395. {
  396. return m_IpSubnetControl.OnIpFieldChange(idCtrl, pnmh);
  397. }
  398. /*
  399. * Method: OnEditClMask
  400. * Description: Called when the user modifies the cluster netmask.
  401. */
  402. LRESULT CCommonClusterPage::OnEditClMask (WORD wNotifyCode, WORD wID, HWND hWndCtl)
  403. {
  404. return m_IpSubnetControl.OnSubnetMask(wNotifyCode);
  405. }
  406. /*
  407. * Method: OnCheckRct
  408. * Description: Called when the user checks/unchecks the remote control enabled checkbox.
  409. */
  410. LRESULT CCommonClusterPage::OnCheckRct (WORD wNotifyCode, WORD wID, HWND hWndCtl) {
  411. TraceMsg(L"CCommonClusterPage::OnCheckRct\n");
  412. switch (wNotifyCode) {
  413. case BN_CLICKED:
  414. /* Decide whether to enable or diable the password entry boxes based on the value of the remote checkbox. */
  415. ::EnableWindow(::GetDlgItem(m_hWnd, IDC_EDIT_PASSW), ::IsDlgButtonChecked(m_hWnd, IDC_CHECK_RCT));
  416. ::EnableWindow(::GetDlgItem(m_hWnd, IDC_EDIT_PASSW2), ::IsDlgButtonChecked(m_hWnd, IDC_CHECK_RCT));
  417. /* Warn the user about the implications of enabling remote control. */
  418. if (::IsDlgButtonChecked(m_hWnd, IDC_CHECK_RCT) && !m_rct_warned) {
  419. /* Alert the user. */
  420. NcMsgBox(m_hInstance, ::GetActiveWindow(), IDS_PARM_WARN, IDS_PARM_RCT_WARN,
  421. MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK);
  422. /* Only warn the user once. */
  423. m_rct_warned = TRUE;
  424. }
  425. break;
  426. }
  427. return 0;
  428. }
  429. /*
  430. * Method: OnCheckMode
  431. * Description: Called when the user changes cluster mode.
  432. */
  433. LRESULT CCommonClusterPage::OnCheckMode (WORD wNotifyCode, WORD wID, HWND hWndCtl) {
  434. TraceMsg(L"CCommonClusterPage::OnCheckMode\n");
  435. switch (wNotifyCode) {
  436. case BN_CLICKED:
  437. /* If the user has IGMP checked, but is turning off multicast support, warn them. */
  438. if (::IsDlgButtonChecked(m_hWnd, IDC_CHECK_IGMP) && !::IsDlgButtonChecked(m_hWnd, IDC_RADIO_MULTICAST)) {
  439. if (!m_igmp_mcast_warned) {
  440. /* Alert the user. */
  441. NcMsgBox(m_hInstance, ::GetActiveWindow(), IDS_PARM_WARN, IDS_PARM_IGMP_MCAST,
  442. MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK);
  443. /* Only warn the user once. */
  444. m_igmp_mcast_warned = TRUE;
  445. }
  446. /* Uncheck and disable the IGMP checkbox and set the IGMP support flag to FALSE. */
  447. ::CheckDlgButton(m_hWnd, IDC_CHECK_IGMP, FALSE);
  448. ::EnableWindow(::GetDlgItem(m_hWnd, IDC_CHECK_IGMP), FALSE);
  449. m_paramp->fIGMPSupport = FALSE;
  450. } else {
  451. /* Enable/disable and check/uncheck the IGMP checkbox based on the value of the cluster mode radio buttons. */
  452. ::EnableWindow(::GetDlgItem(m_hWnd, IDC_CHECK_IGMP), ::IsDlgButtonChecked(m_hWnd, IDC_RADIO_MULTICAST));
  453. }
  454. /* Update the cluster MAC address. */
  455. SetClusterMACAddress();
  456. break;
  457. }
  458. return 0;
  459. }
  460. /*
  461. * Method: OnCheckIGMP
  462. * Description: Called when the user checks/unchecks the IGMP support checkbox.
  463. */
  464. LRESULT CCommonClusterPage::OnCheckIGMP (WORD wNotifyCode, WORD wID, HWND hWndCtl) {
  465. TraceMsg(L"CCommonClusterPage::OnCheckIGMP\n");
  466. switch (wNotifyCode) {
  467. case BN_CLICKED:
  468. /* Update the cluster MAC address. */
  469. SetClusterMACAddress();
  470. /* Warn the user about the implications of enabling remote control. */
  471. if (::IsDlgButtonChecked(m_hWnd, IDC_CHECK_IGMP) && !m_igmp_warned) {
  472. /* Alert the user. */
  473. NcMsgBox(m_hInstance, ::GetActiveWindow(), IDS_PARM_WARN, IDS_PARM_IGMP_WARN,
  474. MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK);
  475. /* Only warn the user once. */
  476. m_igmp_warned = TRUE;
  477. }
  478. break;
  479. }
  480. return 0;
  481. }
  482. /*
  483. * Method: SetClusterMACAddress
  484. * Description: Used to determine the cluster MAC address based on the cluster IP, and the
  485. * state of multicast and IGMP support.
  486. */
  487. void CCommonClusterPage::SetClusterMACAddress () {
  488. WCHAR cl_ip_addr[CVY_MAX_CL_IP_ADDR + 1];
  489. WCHAR cl_mac_addr[CVY_MAX_NETWORK_ADDR + 1];
  490. TraceMsg(L"CCommonClusterPage::SetClusterMACAddress\n");
  491. /* If the convert MAC flag isn't set, the bail out. */
  492. if (!m_paramp->fConvertMac) return;
  493. /* Retrieve the cluster IP address from the UI. */
  494. ::SendDlgItemMessage(m_hWnd, IDC_EDIT_CL_IP, WM_GETTEXT, CVY_MAX_CL_IP_ADDR + 1, (LPARAM)cl_ip_addr);
  495. /* Generate the cluster MAC address. */
  496. ParamsGenerateMAC(cl_ip_addr, cl_mac_addr, m_paramp->szMCastIpAddress, m_paramp->fConvertMac, ::IsDlgButtonChecked(m_hWnd, IDC_RADIO_MULTICAST),
  497. ::IsDlgButtonChecked(m_hWnd, IDC_CHECK_IGMP), m_paramp->fIpToMCastIp);
  498. /* Set the cluster MAC address. */
  499. ::SendDlgItemMessage(m_hWnd, IDC_EDIT_ETH, WM_SETTEXT, 0, (LPARAM)cl_mac_addr);
  500. }
  501. /*
  502. * Method: CheckClusterMACAddress
  503. * Description: Used to check the cluster MAC address in the case where we aren't generating it ourselves.
  504. */
  505. BOOL CCommonClusterPage::CheckClusterMACAddress () {
  506. PWCHAR p1, p2;
  507. WCHAR mac_addr[WLBS_MAX_NETWORK_ADDR + 1];
  508. DWORD i, j;
  509. BOOL flag = TRUE;
  510. /* Valid formats include:
  511. 02:bf:0b:0b:01:01
  512. 02-bf-0b-0b-01-01
  513. 02:bf:0b:b:01:1 */
  514. /* Make a copy of the MAC address. */
  515. _tcscpy(mac_addr, m_paramp->cl_mac_addr);
  516. /* Point to the beginning of the MAC. */
  517. p2 = p1 = mac_addr;
  518. /* Loop through all six bytes. */
  519. for (i = 0 ; i < 6 ; i++) {
  520. /* If we are pointing at the end of the string, its invalid. */
  521. if (*p2 == _TEXT('\0')) return FALSE;
  522. /* Convert the hex characters into decimal. */
  523. j = _tcstoul(p1, &p2, 16);
  524. /* If the number is greater than 255, then the format is bad. */
  525. if (j > 255) return FALSE;
  526. /* If the NEXT character is neither a -, :, nor the NUL character, then the format is bad. */
  527. if (!((*p2 == _TEXT('-')) || (*p2 == _TEXT(':')) || (*p2 == _TEXT('\0')))) return FALSE;
  528. /* If the NEXT character is the end of the string, but we don't have enough bytes yet, bail out. */
  529. if (*p2 == _TEXT('\0') && i < 5) return FALSE;
  530. /* Repoint to the NEXT character. */
  531. p1 = p2 + 1;
  532. p2 = p1;
  533. }
  534. return TRUE;
  535. }
  536. /*
  537. * Method: SetInfo
  538. * Description: Called to populate the UI with the current cluster settings.
  539. */
  540. void CCommonClusterPage::SetInfo () {
  541. /* Check (or uncheck) the checkboxes. */
  542. ::CheckDlgButton(m_hWnd, IDC_CHECK_RCT, m_paramp->fRctEnabled);
  543. /* Check the appropriate radio button for cluster mode. */
  544. if (m_paramp->fMcastSupport) {
  545. ::CheckDlgButton(m_hWnd, IDC_RADIO_MULTICAST, TRUE);
  546. if (m_paramp->fIGMPSupport) ::CheckDlgButton(m_hWnd, IDC_CHECK_IGMP, TRUE);
  547. } else
  548. ::CheckDlgButton(m_hWnd, IDC_RADIO_UNICAST, TRUE);
  549. m_IpSubnetControl.SetInfo(m_paramp->cl_ip_addr, m_paramp->cl_net_mask);
  550. /* Fill in the edit boxes. */
  551. ::SendDlgItemMessage(m_hWnd, IDC_EDIT_DOMAIN, WM_SETTEXT, 0, (LPARAM)m_paramp->domain_name);
  552. ::SendDlgItemMessage(m_hWnd, IDC_EDIT_ETH, WM_SETTEXT, 0, (LPARAM)m_paramp->cl_mac_addr);
  553. ::SendDlgItemMessage(m_hWnd, IDC_EDIT_PASSW, WM_SETTEXT, 0, (LPARAM)m_paramp->szPassword );
  554. ::SendDlgItemMessage(m_hWnd, IDC_EDIT_PASSW2, WM_SETTEXT, 0, (LPARAM)m_paramp->szPassword );
  555. }
  556. /*
  557. * Method: UpdateInfo
  558. * Description: Called to copy the UI state to the cluster configuration.
  559. */
  560. void CCommonClusterPage::UpdateInfo () {
  561. TraceMsg(L"CCommonClusterPage::UpdateInfo\n");
  562. /* Retrieve the checkbox values. */
  563. m_paramp->fRctEnabled = ::IsDlgButtonChecked(m_hWnd, IDC_CHECK_RCT) == 1;
  564. /* Retrieve the cluster mode radio button value. */
  565. m_paramp->fIGMPSupport = ::IsDlgButtonChecked(m_hWnd, IDC_CHECK_IGMP) == 1;
  566. m_paramp->fMcastSupport = ::IsDlgButtonChecked(m_hWnd, IDC_RADIO_MULTICAST) == 1;
  567. m_IpSubnetControl.UpdateInfo(m_paramp->cl_ip_addr, m_paramp->cl_net_mask);
  568. /* Retrieve the entry box values. */
  569. // Edited ( mhakim 02-12-01 )
  570. // We need to retrieve one more byte for the domain name and network address.
  571. // ::SendDlgItemMessage(m_hWnd, IDC_EDIT_DOMAIN, WM_GETTEXT, CVY_MAX_DOMAIN_NAME, (LPARAM)m_paramp->domain_name);
  572. // ::SendDlgItemMessage(m_hWnd, IDC_EDIT_ETH, WM_GETTEXT, CVY_MAX_NETWORK_ADDR, (LPARAM)m_paramp->cl_mac_addr);
  573. ::SendDlgItemMessage(m_hWnd, IDC_EDIT_DOMAIN, WM_GETTEXT, CVY_MAX_DOMAIN_NAME + 1, (LPARAM)m_paramp->domain_name);
  574. ::SendDlgItemMessage(m_hWnd, IDC_EDIT_ETH, WM_GETTEXT, CVY_MAX_NETWORK_ADDR + 1, (LPARAM)m_paramp->cl_mac_addr);
  575. ::SendDlgItemMessage(m_hWnd, IDC_EDIT_PASSW, WM_GETTEXT, CVY_MAX_RCT_CODE + 1, (LPARAM)m_passw);
  576. ::SendDlgItemMessage(m_hWnd, IDC_EDIT_PASSW2, WM_GETTEXT, CVY_MAX_RCT_CODE + 1, (LPARAM)m_passw2);
  577. }
  578. /*
  579. * Method: ValidateInfo
  580. * Description: Called to validate the entries made by the user.
  581. */
  582. LRESULT CCommonClusterPage::ValidateInfo () {
  583. DWORD IPAddr;
  584. TraceMsg(L"CCommonClusterPage::ValidateInfo\n");
  585. if (!m_IpSubnetControl.ValidateInfo())
  586. {
  587. //
  588. // Check whether IP address and subnet mask pair is valid
  589. //
  590. return PSNRET_INVALID;
  591. }
  592. //
  593. // Get the user input
  594. //
  595. m_IpSubnetControl.UpdateInfo(m_paramp->cl_ip_addr, m_paramp->cl_net_mask);
  596. /* Check to make sure that the dedicated IP and cluster IP are not the same. */
  597. if (!wcscmp(m_paramp->ded_ip_addr, m_paramp->cl_ip_addr)) {
  598. /* Alert the user. */
  599. NcMsgBox(m_hInstance, ::GetActiveWindow(), IDS_PARM_ERROR, IDS_PARM_IP_CONFLICT,
  600. MB_APPLMODAL | MB_ICONSTOP | MB_OK);
  601. /* An error occurred. */
  602. return PSNRET_INVALID;
  603. }
  604. if (!m_paramp->fConvertMac && !CheckClusterMACAddress()) {
  605. /* Alert the user. */
  606. NcMsgBox(m_hInstance, ::GetActiveWindow(), IDS_PARM_ERROR, IDS_PARM_INVAL_MAC,
  607. MB_APPLMODAL | MB_ICONSTOP | MB_OK);
  608. /* An error occurred. */
  609. return PSNRET_INVALID;
  610. }
  611. /* Only check for invalid passwords and update if remote control is enabled. */
  612. if (::IsDlgButtonChecked(m_hWnd, IDC_CHECK_RCT)) {
  613. /* Make sure the passwords match. */
  614. if (wcscmp(m_passw, m_passw2) != 0) {
  615. /* Alert the user. */
  616. NcMsgBox(m_hInstance, ::GetActiveWindow(), IDS_PARM_ERROR, IDS_PARM_PASSWORD,
  617. MB_APPLMODAL | MB_ICONSTOP | MB_OK);
  618. /* Empty the passwords. */
  619. m_passw [0] = m_passw2 [0] = 0;
  620. /* An error occurred. */
  621. return PSNRET_INVALID;
  622. } else {
  623. /* If the new password is not the dummy password, update the password. */
  624. if (wcscmp (m_passw, DUMMY_PASSWORD) != 0) {
  625. lstrcpy(m_paramp->szPassword, m_passw);
  626. m_paramp->fChangePassword = true;
  627. }
  628. }
  629. }
  630. return PSNRET_NOERROR;
  631. }