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.

1219 lines
30 KiB

  1. // Copyright (C) 2000 Microsoft Corporation
  2. //
  3. // Dynamic DNS detection/diagnostic page
  4. //
  5. // 22 Aug 2000 sburns
  6. #include "headers.hxx"
  7. #include "page.hpp"
  8. #include "DynamicDnsPage.hpp"
  9. #include "resource.h"
  10. #include "state.hpp"
  11. HINSTANCE DynamicDnsPage::richEditHInstance = 0;
  12. DynamicDnsPage::DynamicDnsPage()
  13. :
  14. DCPromoWizardPage(
  15. IDD_DYNAMIC_DNS,
  16. IDS_DYNAMIC_DNS_PAGE_TITLE,
  17. IDS_DYNAMIC_DNS_PAGE_SUBTITLE),
  18. diagnosticResultCode(UNEXPECTED_FINDING_SERVER),
  19. needToKillSelection(false),
  20. originalMessageHeight(0),
  21. testPassCount(0)
  22. {
  23. LOG_CTOR(DynamicDnsPage);
  24. WSADATA data;
  25. DWORD err = ::WSAStartup(MAKEWORD(2,0), &data);
  26. // if winsock startup fails, that's a shame. The gethostbyname will
  27. // not work, but there's not much we can do about that.
  28. ASSERT(!err);
  29. if (!richEditHInstance)
  30. {
  31. // You have to load the rich edit dll to get the window class, etc.
  32. // to register. Otherwise the dialog will fail create, and the page
  33. // will not appear.
  34. HRESULT hr = Win::LoadLibrary(L"riched20.dll", richEditHInstance);
  35. ASSERT(SUCCEEDED(hr));
  36. if (FAILED(hr))
  37. {
  38. // we've no choice than crash the app.
  39. throw Win::Error(hr, IDS_RICHEDIT_LOAD_FAILED);
  40. }
  41. }
  42. }
  43. DynamicDnsPage::~DynamicDnsPage()
  44. {
  45. LOG_DTOR(DynamicDnsPage);
  46. ::WSACleanup();
  47. Win::FreeLibrary(richEditHInstance);
  48. }
  49. void
  50. DynamicDnsPage::ShowButtons(bool shown)
  51. {
  52. LOG_FUNCTION(DynamicDnsPage::ShowButtons);
  53. HWND ignoreButton = Win::GetDlgItem(hwnd, IDC_IGNORE);
  54. HWND richEdit = Win::GetDlgItem(hwnd, IDC_MESSAGE);
  55. int state = shown ? SW_SHOW : SW_HIDE;
  56. Win::ShowWindow(Win::GetDlgItem(hwnd, IDC_RETRY), state);
  57. Win::ShowWindow(Win::GetDlgItem(hwnd, IDC_INSTALL_DNS), state);
  58. Win::ShowWindow(ignoreButton, state);
  59. RECT r;
  60. Win::GetWindowRect(richEdit, r);
  61. // Convert r to coords relative to the parent window.
  62. Win::MapWindowPoints(0, hwnd, r);
  63. if (shown)
  64. {
  65. // If we're showing the buttons, collapse the rich edit to it's normal
  66. // height.
  67. Win::MoveWindow(
  68. richEdit,
  69. r.left,
  70. r.top,
  71. r.right - r.left,
  72. originalMessageHeight,
  73. true);
  74. }
  75. else
  76. {
  77. // If we're hiding the buttons, expand the rich edit to include their
  78. // real estate.
  79. RECT r1;
  80. Win::GetWindowRect(ignoreButton, r1);
  81. Win::MapWindowPoints(0, hwnd, r1);
  82. Win::MoveWindow(
  83. richEdit,
  84. r.left,
  85. r.top,
  86. r.right - r.left,
  87. r1.bottom - r.top,
  88. true);
  89. }
  90. }
  91. void
  92. DynamicDnsPage::SelectRadioButton(int buttonResId)
  93. {
  94. // If the order of the buttons changes, then this must be changed. The
  95. // buttons also need to have consecutively numbered res IDs in the tab
  96. // order.
  97. Win::CheckRadioButton(hwnd, IDC_RETRY, IDC_IGNORE, buttonResId);
  98. }
  99. void
  100. DynamicDnsPage::OnInit()
  101. {
  102. LOG_FUNCTION(DynamicDnsPage::OnInit);
  103. HWND richEdit = Win::GetDlgItem(hwnd, IDC_MESSAGE);
  104. // ask for link messages
  105. Win::RichEdit_SetEventMask(richEdit, ENM_LINK);
  106. // save the normal size of the message box so we can restore it later.
  107. RECT r;
  108. Win::GetWindowRect(richEdit, r);
  109. originalMessageHeight = r.bottom - r.top;
  110. Win::SendMessage(
  111. richEdit,
  112. EM_SETBKGNDCOLOR,
  113. 0,
  114. Win::GetSysColor(COLOR_BTNFACE));
  115. SelectRadioButton(IDC_IGNORE);
  116. // Hide the radio buttons initially
  117. ShowButtons(false);
  118. multiLineEdit.Init(Win::GetDlgItem(hwnd, IDC_MESSAGE));
  119. // pick the proper radio button label
  120. if (State::GetInstance().ShouldConfigDnsClient())
  121. {
  122. Win::SetDlgItemText(
  123. hwnd,
  124. IDC_INSTALL_DNS,
  125. IDS_INSTALL_DNS_RADIO_LABEL_WITH_CLIENT);
  126. }
  127. else
  128. {
  129. Win::SetDlgItemText(
  130. hwnd,
  131. IDC_INSTALL_DNS,
  132. IDS_INSTALL_DNS_RADIO_LABEL);
  133. }
  134. }
  135. // Adds a trailing '.' to the supplied name if one is not already present.
  136. //
  137. // name - in, name to add a trailing '.' to, if it doesn't already have one.
  138. // If this value is the empty string, then '.' is returned.
  139. String
  140. FullyQualifyDnsName(const String& name)
  141. {
  142. LOG_FUNCTION2(FullyQualifyDnsName, name);
  143. if (name.empty())
  144. {
  145. return L".";
  146. }
  147. // needs a trailing dot
  148. // REVIEW: name[name.length() - 1] is the same as *(name.rbegin())
  149. // which is cheaper?
  150. if (name[name.length() - 1] != L'.')
  151. {
  152. return name + L".";
  153. }
  154. // already has a trailing dot
  155. return name;
  156. }
  157. // Scans a linked list of DNS_RECORDs, returning a pointer to the first record
  158. // of type SOA, or 0 if no record of that type is in the list.
  159. //
  160. // recordList - in, linked list of DNS_RECORDs, as returned from DnsQuery
  161. DNS_RECORD*
  162. FindSoaRecord(DNS_RECORD* recordList)
  163. {
  164. LOG_FUNCTION(FindSoaRecord);
  165. ASSERT(recordList);
  166. DNS_RECORD* result = recordList;
  167. while (result)
  168. {
  169. if (result->wType == DNS_TYPE_SOA)
  170. {
  171. LOG(L"SOA record found");
  172. break;
  173. }
  174. result = result->pNext;
  175. }
  176. return result;
  177. }
  178. // Returns the textual representation of the IP address for the given server
  179. // name, in the form "xxx.xxx.xxx.xxx", or the empty string if not IP address
  180. // can be determined.
  181. //
  182. // serverName - in, the host name of the server for which to find the IP
  183. // address. If the value is the empty string, then the empty string is
  184. // returned from the function.
  185. String
  186. GetIpAddress(const String& serverName)
  187. {
  188. LOG_FUNCTION2(GetIpAddress, serverName);
  189. ASSERT(!serverName.empty());
  190. String result;
  191. do
  192. {
  193. if (serverName.empty())
  194. {
  195. break;
  196. }
  197. LOG(L"Calling gethostbyname");
  198. AnsiString ansi;
  199. serverName.convert(ansi);
  200. HOSTENT* host = gethostbyname(ansi.c_str());
  201. if (host && host->h_addr_list[0])
  202. {
  203. struct in_addr a;
  204. ::CopyMemory(&a.S_un.S_addr, host->h_addr_list[0], sizeof a.S_un.S_addr);
  205. result = inet_ntoa(a);
  206. break;
  207. }
  208. LOG(String::format(L"WSAGetLastError = 0x%1!0X", WSAGetLastError()));
  209. }
  210. while (0);
  211. LOG(result);
  212. return result;
  213. }
  214. // Find the DNS server that is authoritative for registering the given server
  215. // name, i.e. what server would register the name. Returns NO_ERROR on
  216. // success, or a DNS status code (a win32 error) on failure. On failure, the
  217. // out parameters are all empty strings.
  218. //
  219. // serverName - in, candidate name for registration. This value should not be the
  220. // empty string.
  221. //
  222. // authZone - out, the zone the name would be registered in.
  223. //
  224. // authServer - out, the name of the DNS server that would have the
  225. // registration.
  226. //
  227. // authServerIpAddress - out, textual representation of the IP address of the
  228. // server named by authServer.
  229. DNS_STATUS
  230. FindAuthoritativeServer(
  231. const String& serverName,
  232. String& authZone,
  233. String& authServer,
  234. String& authServerIpAddress)
  235. {
  236. LOG_FUNCTION2(FindAuthoritativeServer, serverName);
  237. ASSERT(!serverName.empty());
  238. authZone.erase();
  239. authServer.erase();
  240. authServerIpAddress.erase();
  241. // ensure that the server name ends with a "." so that we have a stop
  242. // point for our loop
  243. String currentName = FullyQualifyDnsName(serverName);
  244. DNS_STATUS result = NO_ERROR;
  245. DNS_RECORD* queryResults = 0;
  246. while (!currentName.empty())
  247. {
  248. result =
  249. MyDnsQuery(
  250. currentName,
  251. DNS_TYPE_SOA,
  252. DNS_QUERY_BYPASS_CACHE,
  253. queryResults);
  254. if (
  255. result == ERROR_TIMEOUT
  256. || result == DNS_ERROR_RCODE_SERVER_FAILURE)
  257. {
  258. // we bail out entirely
  259. LOG(L"failed to find autoritative server.");
  260. break;
  261. }
  262. // search for an SOA RR
  263. DNS_RECORD* soaRecord =
  264. queryResults ? FindSoaRecord(queryResults) : 0;
  265. if (soaRecord)
  266. {
  267. // collect return values, and we're done.
  268. LOG(L"autoritative server found");
  269. authZone = soaRecord->pName;
  270. authServer = soaRecord->Data.SOA.pNamePrimaryServer;
  271. authServerIpAddress = GetIpAddress(authServer);
  272. break;
  273. }
  274. // no SOA record found.
  275. if (currentName == L".")
  276. {
  277. // We've run out of names to query. This situation is so unlikely
  278. // that the DNS server would have to be seriously broken to put
  279. // us in this state. So this is almost an assert case.
  280. LOG(L"Root zone reached without finding SOA record!");
  281. result = DNS_ERROR_ZONE_HAS_NO_SOA_RECORD;
  282. break;
  283. }
  284. // whack off the leftmost label, and iterate again on the parent
  285. // zone.
  286. currentName = Dns::GetParentDomainName(currentName);
  287. MyDnsRecordListFree(queryResults);
  288. queryResults = 0;
  289. }
  290. MyDnsRecordListFree(queryResults);
  291. LOG(String::format(L"result = %1!08X!", result));
  292. LOG(L"authZone = " + authZone);
  293. LOG(L"authServer = " + authServer);
  294. LOG(L"authServerIpAddress = " + authServerIpAddress);
  295. return result;
  296. }
  297. DNS_STATUS
  298. MyDnsUpdateTest(const String& name)
  299. {
  300. LOG_FUNCTION2(MyDnsUpdateTest, name);
  301. ASSERT(!name.empty());
  302. LOG(L"Calling DnsUpdateTest");
  303. LOG( L"hContextHandle : 0");
  304. LOG(String::format(L"pszName : %1", name.c_str()));
  305. LOG( L"fOptions : 0");
  306. LOG( L"aipServers : 0");
  307. DNS_STATUS status =
  308. ::DnsUpdateTest(
  309. 0,
  310. const_cast<wchar_t*>(name.c_str()),
  311. 0,
  312. 0);
  313. LOG(String::format(L"status = %1!08X!", status));
  314. LOG(MyDnsStatusString(status));
  315. return status;
  316. }
  317. // Returns result code that corresponds to what messages to be displayed and
  318. // what radio buttons to make available as a result of the diagnostic.
  319. //
  320. // Also returns thru out parameters information to be included in the
  321. // messages.
  322. //
  323. // serverName - in, the name of the domain contoller to be registered.
  324. //
  325. // errorCode - out, the DNS error code (a win32 error) encountered when
  326. // running the diagnostic.
  327. //
  328. // authZone - out, the zone the name would be registered in.
  329. //
  330. // authServer - out, the name of the DNS server that would have the
  331. // registration.
  332. //
  333. // authServerIpAddress - out, textual representation of the IP address of the
  334. // server named by authServer.
  335. DynamicDnsPage::DiagnosticCode
  336. DynamicDnsPage::DiagnoseDnsRegistration(
  337. const String& serverName,
  338. DNS_STATUS& errorCode,
  339. String& authZone,
  340. String& authServer,
  341. String& authServerIpAddress)
  342. {
  343. LOG_FUNCTION(DynamicDnsPage::DiagnoseDnsRegistration);
  344. ASSERT(!serverName.empty());
  345. DiagnosticCode result = UNEXPECTED_FINDING_SERVER;
  346. errorCode =
  347. FindAuthoritativeServer(
  348. serverName,
  349. authZone,
  350. authServer,
  351. authServerIpAddress);
  352. switch (errorCode)
  353. {
  354. case NO_ERROR:
  355. {
  356. if (authZone == L".")
  357. {
  358. // Message 8
  359. LOG(L"authZone is root");
  360. result = ZONE_IS_ROOT;
  361. }
  362. else
  363. {
  364. errorCode = MyDnsUpdateTest(serverName);
  365. switch (errorCode)
  366. {
  367. case DNS_ERROR_RCODE_NO_ERROR:
  368. case DNS_ERROR_RCODE_YXDOMAIN:
  369. {
  370. // Message 1
  371. LOG(L"DNS registration support verified.");
  372. result = SUCCESS;
  373. break;
  374. }
  375. case DNS_ERROR_RCODE_NOT_IMPLEMENTED:
  376. case DNS_ERROR_RCODE_REFUSED:
  377. {
  378. // Message 2
  379. LOG(L"Server does not support update");
  380. result = SERVER_CANT_UPDATE;
  381. break;
  382. }
  383. default:
  384. {
  385. // Message 3
  386. result = ERROR_TESTING_SERVER;
  387. break;
  388. }
  389. }
  390. }
  391. break;
  392. }
  393. case DNS_ERROR_RCODE_SERVER_FAILURE:
  394. {
  395. // Message 6
  396. result = ERROR_FINDING_SERVER;
  397. break;
  398. }
  399. case ERROR_TIMEOUT:
  400. {
  401. // Message 11
  402. result = TIMEOUT;
  403. break;
  404. }
  405. default:
  406. {
  407. // Message 4
  408. LOG(L"Unexpected error");
  409. result = UNEXPECTED_FINDING_SERVER;
  410. break;
  411. }
  412. }
  413. LOG(String::format(L"DiagnosticCode = %1!x!", result));
  414. return result;
  415. }
  416. // void
  417. // DumpSel(HWND richEdit)
  418. // {
  419. // CHARRANGE range;
  420. // RichEdit_GetSel(richEdit, range);
  421. //
  422. // LOG(String::format("cpMin = %1!d! cpMax = %1!d!", range.cpMin, range.cpMax));
  423. // }
  424. void
  425. DynamicDnsPage::UpdateMessageWindow(const String& message)
  426. {
  427. LOG_FUNCTION(UpdateMessageWindow);
  428. ASSERT(!message.empty());
  429. // this should have been set before we get here
  430. ASSERT(!details.empty());
  431. HWND richEdit = Win::GetDlgItem(hwnd, IDC_MESSAGE);
  432. // Clear out the window of any prior contents. This is needed because in
  433. // the code that follows, we take advantage of the fact that the set text
  434. // functions create an empty selection to the end of the text, and
  435. // subsequent ST_SELECTION type calls to set text will append at that
  436. // point.
  437. Win::RichEdit_SetText(richEdit, ST_DEFAULT, L"");
  438. static const String RTF_HEADER_ON(
  439. L"{\\rtf" // RTF header
  440. L"\\pard" // start default paragraph style
  441. L"\\sa100" // whitespace after paragraph = 100 twips
  442. L"\\b "); // bold on
  443. static const String RTF_HEADER_OFF(
  444. L"\\b0" // bold off
  445. L"\\par " // end paragraph
  446. L"}"); // end RTF
  447. Win::RichEdit_SetRtfText(
  448. richEdit,
  449. ST_SELECTION,
  450. RTF_HEADER_ON
  451. + String::load(IDS_DIAGNOSTIC_RESULTS)
  452. + RTF_HEADER_OFF);
  453. Win::RichEdit_SetText(
  454. richEdit,
  455. ST_SELECTION,
  456. String::format(
  457. (testPassCount == 1)
  458. ? IDS_DIAGNOSTIC_COUNTER_1
  459. : IDS_DIAGNOSTIC_COUNTER_N,
  460. testPassCount)
  461. + L"\r\n\r\n"
  462. + message
  463. + L"\r\n\r\n");
  464. if (!helpTopicLink.empty())
  465. {
  466. // We have help to show, so insert a line with a link to click for it.
  467. Win::RichEdit_SetText(
  468. richEdit,
  469. ST_SELECTION,
  470. String::load(IDS_DIAGNOSTIC_HELP_LINK_PRE));
  471. // At this point, we want to insert the help link and set it to the link
  472. // style. We do this by tracking the position of the link text, and
  473. // then selecting that text, and then setting the selection to the link
  474. // style.
  475. CHARRANGE beginRange;
  476. Win::RichEdit_GetSel(richEdit, beginRange);
  477. Win::RichEdit_SetText(
  478. richEdit,
  479. ST_SELECTION,
  480. String::load(IDS_DIAGNOSTIC_HELP_LINK));
  481. CHARRANGE endRange;
  482. Win::RichEdit_GetSel(richEdit, endRange);
  483. ASSERT(endRange.cpMin > beginRange.cpMax);
  484. Win::Edit_SetSel(richEdit, beginRange.cpMax, endRange.cpMin);
  485. CHARFORMAT2 format;
  486. // REVIEWED-2002/02/26-sburns correct byte count passed.
  487. ::ZeroMemory(&format, sizeof format);
  488. format.dwMask = CFM_LINK;
  489. format.dwEffects = CFE_LINK;
  490. Win::RichEdit_SetCharacterFormat(richEdit, SCF_SELECTION, format);
  491. // set the selection back to the end of where the link was inserted.
  492. Win::RichEdit_SetSel(richEdit, endRange);
  493. // now continue to the end
  494. Win::RichEdit_SetText(
  495. richEdit,
  496. ST_SELECTION,
  497. String::load(IDS_DIAGNOSTIC_HELP_LINK_POST) + L"\r\n\r\n");
  498. }
  499. Win::RichEdit_SetRtfText(
  500. richEdit,
  501. ST_SELECTION,
  502. RTF_HEADER_ON
  503. + String::load(IDS_DETAILS)
  504. + RTF_HEADER_OFF);
  505. Win::RichEdit_SetText(richEdit, ST_SELECTION, details + L"\r\n\r\n");
  506. }
  507. // do the test, update the text on the page, update the radio buttons
  508. // enabled state, choose a radio button default if neccessary
  509. void
  510. DynamicDnsPage::DoDnsTestAndUpdatePage()
  511. {
  512. LOG_FUNCTION(DynamicDnsPage::DoDnsTestAndUpdatePage);
  513. // this might take a while.
  514. Win::WaitCursor cursor;
  515. State& state = State::GetInstance();
  516. String domain = state.GetNewDomainDNSName();
  517. DNS_STATUS errorCode = 0;
  518. String authZone;
  519. String authServer;
  520. String authServerIpAddress;
  521. String serverName = L"_ldap._tcp.dc._msdcs." + domain;
  522. diagnosticResultCode =
  523. DiagnoseDnsRegistration(
  524. serverName,
  525. errorCode,
  526. authZone,
  527. authServer,
  528. authServerIpAddress);
  529. ++testPassCount;
  530. String message;
  531. int defaultButton = IDC_IGNORE;
  532. switch (diagnosticResultCode)
  533. {
  534. // Message 1
  535. case SUCCESS:
  536. {
  537. message = String::load(IDS_DYN_DNS_MESSAGE_SUCCESS);
  538. String errorMessage;
  539. if (errorCode == DNS_ERROR_RCODE_YXDOMAIN)
  540. {
  541. // NTRAID#NTBUG9-586579-2002/04/15-sburns
  542. errorMessage =
  543. String::format(
  544. IDS_DNS_ERROR_RCODE_YXDOMAIN_ADDENDA,
  545. serverName.c_str(),
  546. authZone.c_str(),
  547. serverName.c_str());
  548. }
  549. else
  550. {
  551. errorMessage = GetErrorMessage(Win32ToHresult(errorCode));
  552. }
  553. details =
  554. String::format(
  555. // NTRAID#NTBUG9-485456-2001/10/24-sburns
  556. IDS_DYN_DNS_DETAIL_FULL_SANS_CODE,
  557. authServer.c_str(),
  558. authServerIpAddress.c_str(),
  559. authZone.c_str(),
  560. errorMessage.c_str());
  561. helpTopicLink = L"";
  562. defaultButton = IDC_IGNORE;
  563. ShowButtons(false);
  564. break;
  565. }
  566. // Message 2
  567. case SERVER_CANT_UPDATE:
  568. {
  569. message = String::load(IDS_DYN_DNS_MESSAGE_SERVER_CANT_UPDATE);
  570. details =
  571. String::format(
  572. IDS_DYN_DNS_DETAIL_FULL,
  573. authServer.c_str(),
  574. authServerIpAddress.c_str(),
  575. authZone.c_str(),
  576. GetErrorMessage(Win32ToHresult(errorCode)).c_str(),
  577. errorCode,
  578. MyDnsStatusString(errorCode).c_str());
  579. if (Dns::CompareNames(authZone, domain) == DnsNameCompareEqual)
  580. {
  581. helpTopicLink =
  582. L"DNSConcepts.chm::/sag_DNS_tro_dynamic_message2a.htm";
  583. }
  584. else
  585. {
  586. helpTopicLink =
  587. L"DNSConcepts.chm::/sag_DNS_tro_dynamic_message2b.htm";
  588. }
  589. defaultButton = IDC_RETRY;
  590. ShowButtons(true);
  591. break;
  592. }
  593. // Message 3
  594. case ERROR_TESTING_SERVER:
  595. {
  596. message = String::load(IDS_DYN_DNS_MESSAGE_ERROR_TESTING_SERVER);
  597. details =
  598. String::format(
  599. IDS_DYN_DNS_DETAIL_FULL,
  600. authServer.c_str(),
  601. authServerIpAddress.c_str(),
  602. authZone.c_str(),
  603. GetErrorMessage(Win32ToHresult(errorCode)).c_str(),
  604. errorCode,
  605. MyDnsStatusString(errorCode).c_str());
  606. helpTopicLink = "DNSConcepts.chm::/sag_DNS_tro_dynamic_message3.htm";
  607. defaultButton = IDC_RETRY;
  608. ShowButtons(true);
  609. break;
  610. }
  611. // Message 6
  612. case ERROR_FINDING_SERVER:
  613. {
  614. ASSERT(authServer.empty());
  615. ASSERT(authZone.empty());
  616. ASSERT(authServerIpAddress.empty());
  617. message = String::load(IDS_DYN_DNS_MESSAGE_ERROR_FINDING_SERVER);
  618. details =
  619. String::format(
  620. IDS_DYN_DNS_DETAIL_SCANT,
  621. serverName.c_str(),
  622. GetErrorMessage(Win32ToHresult(errorCode)).c_str(),
  623. errorCode,
  624. MyDnsStatusString(errorCode).c_str());
  625. helpTopicLink = "DNSConcepts.chm::/sag_DNS_tro_dynamic_message6.htm";
  626. defaultButton = IDC_INSTALL_DNS;
  627. ShowButtons(true);
  628. break;
  629. }
  630. // Message 8
  631. case ZONE_IS_ROOT:
  632. {
  633. message =
  634. String::format(
  635. IDS_DYN_DNS_MESSAGE_ZONE_IS_ROOT,
  636. domain.c_str(),
  637. domain.c_str());
  638. details =
  639. String::format(
  640. IDS_DYN_DNS_DETAIL_ROOT_ZONE,
  641. authServer.c_str(),
  642. authServerIpAddress.c_str());
  643. helpTopicLink = L"DNSConcepts.chm::/sag_DNS_tro_dynamic_message8.htm";
  644. defaultButton = IDC_INSTALL_DNS;
  645. ShowButtons(true);
  646. break;
  647. }
  648. // Message 11
  649. case TIMEOUT:
  650. {
  651. message = String::load(IDS_DYN_DNS_MESSAGE_TIMEOUT);
  652. details =
  653. String::format(
  654. IDS_DYN_DNS_DETAIL_SCANT,
  655. serverName.c_str(),
  656. GetErrorMessage(Win32ToHresult(errorCode)).c_str(),
  657. errorCode,
  658. MyDnsStatusString(errorCode).c_str());
  659. helpTopicLink = L"DNSConcepts.chm::/sag_DNS_tro_dynamic_message11.htm";
  660. defaultButton = IDC_INSTALL_DNS;
  661. ShowButtons(true);
  662. break;
  663. }
  664. // Message 4
  665. case UNEXPECTED_FINDING_SERVER:
  666. // Anything else
  667. default:
  668. {
  669. #ifdef DBG
  670. ASSERT(authServer.empty());
  671. ASSERT(authZone.empty());
  672. ASSERT(authServerIpAddress.empty());
  673. if (diagnosticResultCode != UNEXPECTED_FINDING_SERVER)
  674. {
  675. ASSERT(false);
  676. }
  677. #endif
  678. message = String::load(IDS_DYN_DNS_MESSAGE_UNEXPECTED);
  679. details =
  680. String::format(
  681. IDS_DYN_DNS_DETAIL_SCANT,
  682. serverName.c_str(),
  683. GetErrorMessage(Win32ToHresult(errorCode)).c_str(),
  684. errorCode,
  685. MyDnsStatusString(errorCode).c_str());
  686. helpTopicLink = L"DNSConcepts.chm::/sag_DNS_tro_dynamic_message4.htm";
  687. defaultButton = IDC_RETRY;
  688. ShowButtons(true);
  689. break;
  690. }
  691. }
  692. UpdateMessageWindow(message);
  693. // success always forces the ignore option
  694. if (diagnosticResultCode == SUCCESS)
  695. {
  696. SelectRadioButton(IDC_IGNORE);
  697. }
  698. else
  699. {
  700. // On the first pass only, decide what radio button to set. On
  701. // subsequent passes, the user will have had the chance to change the
  702. // button selection, so we don't change his selections.
  703. if (testPassCount == 1)
  704. {
  705. int button = defaultButton;
  706. ASSERT(diagnosticResultCode != SUCCESS);
  707. // if the test failed, and the wizard is running unattended, then
  708. // consult the answer file for the user's preference in dealing
  709. // with the failure.
  710. if (state.UsingAnswerFile())
  711. {
  712. String option =
  713. state.GetAnswerFileOption(AnswerFile::OPTION_AUTO_CONFIG_DNS);
  714. if (
  715. option.empty()
  716. || (option.icompare(AnswerFile::VALUE_YES) == 0) )
  717. {
  718. button = IDC_INSTALL_DNS;
  719. }
  720. else
  721. {
  722. button = IDC_IGNORE;
  723. }
  724. }
  725. SelectRadioButton(button);
  726. }
  727. }
  728. }
  729. bool
  730. DynamicDnsPage::OnSetActive()
  731. {
  732. LOG_FUNCTION(DynamicDnsPage::OnSetActive);
  733. State& state = State::GetInstance();
  734. State::Operation oper = state.GetOperation();
  735. // these are the only operations for which this page is valid; i.e.
  736. // new domain scenarios
  737. if (
  738. oper == State::FOREST
  739. || oper == State::CHILD
  740. || oper == State::TREE)
  741. {
  742. DoDnsTestAndUpdatePage();
  743. needToKillSelection = true;
  744. }
  745. if (
  746. ( oper != State::FOREST
  747. && oper != State::CHILD
  748. && oper != State::TREE)
  749. || state.RunHiddenUnattended() )
  750. {
  751. LOG(L"Planning to Skip DynamicDnsPage");
  752. Wizard& wizard = GetWizard();
  753. if (wizard.IsBacktracking())
  754. {
  755. // backup once again
  756. wizard.Backtrack(hwnd);
  757. return true;
  758. }
  759. int nextPage = Validate();
  760. if (nextPage != -1)
  761. {
  762. LOG(L"skipping DynamicDnsPage");
  763. wizard.SetNextPageID(hwnd, nextPage);
  764. return true;
  765. }
  766. state.ClearHiddenWhileUnattended();
  767. }
  768. Win::PropSheet_SetWizButtons(
  769. Win::GetParent(hwnd),
  770. PSWIZB_BACK | PSWIZB_NEXT);
  771. return true;
  772. }
  773. void
  774. DumpButtons(HWND dialog)
  775. {
  776. LOG(String::format(L"retry : (%1)", Win::IsDlgButtonChecked(dialog, IDC_RETRY) ? L"*" : L" "));
  777. LOG(String::format(L"ignore : (%1)", Win::IsDlgButtonChecked(dialog, IDC_IGNORE) ? L"*" : L" "));
  778. LOG(String::format(L"install: (%1)", Win::IsDlgButtonChecked(dialog, IDC_INSTALL_DNS) ? L"*" : L" "));
  779. }
  780. int
  781. DynamicDnsPage::Validate()
  782. {
  783. LOG_FUNCTION(DynamicDnsPage::Validate);
  784. int nextPage = -1;
  785. do
  786. {
  787. State& state = State::GetInstance();
  788. State::Operation oper = state.GetOperation();
  789. DumpButtons(hwnd);
  790. if (
  791. oper != State::FOREST
  792. && oper != State::CHILD
  793. && oper != State::TREE)
  794. {
  795. // by definition valid, as the page does not apply
  796. State::GetInstance().SetAutoConfigureDNS(false);
  797. nextPage = IDD_RAS_FIXUP;
  798. break;
  799. }
  800. if (
  801. diagnosticResultCode == SUCCESS
  802. || Win::IsDlgButtonChecked(hwnd, IDC_IGNORE))
  803. {
  804. // You can go about your business. Move along, move long.
  805. // Force ignore, even if the user previously had encountered a
  806. // failure and chose retry or install DNS. We do this in case the
  807. // user backed up in the wizard and corrected the domain name.
  808. State::GetInstance().SetAutoConfigureDNS(false);
  809. nextPage = IDD_RAS_FIXUP;
  810. break;
  811. }
  812. // if the radio button selection = retry, then do the test over again,
  813. // and stick to this page.
  814. if (Win::IsDlgButtonChecked(hwnd, IDC_RETRY))
  815. {
  816. DoDnsTestAndUpdatePage();
  817. break;
  818. }
  819. ASSERT(Win::IsDlgButtonChecked(hwnd, IDC_INSTALL_DNS));
  820. State::GetInstance().SetAutoConfigureDNS(true);
  821. nextPage = IDD_RAS_FIXUP;
  822. break;
  823. }
  824. while (0);
  825. LOG(String::format(L"nextPage = %1!d!", nextPage));
  826. return nextPage;
  827. }
  828. bool
  829. DynamicDnsPage::OnWizBack()
  830. {
  831. LOG_FUNCTION(DynamicDnsPage::OnWizBack);
  832. // make sure we reset the auto-config flag => the only way it gets set
  833. // it on the 'next' button.
  834. State::GetInstance().SetAutoConfigureDNS(false);
  835. return DCPromoWizardPage::OnWizBack();
  836. }
  837. bool
  838. DynamicDnsPage::OnCommand(
  839. HWND windowFrom,
  840. unsigned controlIdFrom,
  841. unsigned code)
  842. {
  843. bool result = false;
  844. switch (controlIdFrom)
  845. {
  846. case IDC_MESSAGE:
  847. {
  848. switch (code)
  849. {
  850. case EN_SETFOCUS:
  851. {
  852. if (needToKillSelection)
  853. {
  854. // kill the text selection
  855. Win::Edit_SetSel(windowFrom, 0, 0);
  856. needToKillSelection = false;
  857. result = true;
  858. }
  859. break;
  860. }
  861. case MultiLineEditBoxThatForwardsEnterKey::FORWARDED_ENTER:
  862. {
  863. // our subclasses mutli-line edit control will send us
  864. // WM_COMMAND messages when the enter key is pressed. We
  865. // reinterpret this message as a press on the default button of
  866. // the prop sheet.
  867. // This workaround from phellyar.
  868. // NTRAID#NTBUG9-232092-2000/11/22-sburns
  869. HWND propSheet = Win::GetParent(hwnd);
  870. int defaultButtonId =
  871. Win::Dialog_GetDefaultButtonId(propSheet);
  872. // we expect that there is always a default button on the prop sheet
  873. ASSERT(defaultButtonId);
  874. Win::SendMessage(
  875. propSheet,
  876. WM_COMMAND,
  877. MAKELONG(defaultButtonId, BN_CLICKED),
  878. 0);
  879. result = true;
  880. break;
  881. }
  882. default:
  883. {
  884. // do nothing
  885. break;
  886. }
  887. }
  888. break;
  889. }
  890. default:
  891. {
  892. // do nothing
  893. break;
  894. }
  895. }
  896. return result;
  897. }
  898. bool
  899. DynamicDnsPage::OnNotify(
  900. HWND /* windowFrom */ ,
  901. UINT_PTR controlIDFrom,
  902. UINT code,
  903. LPARAM lParam)
  904. {
  905. bool result = false;
  906. if (controlIDFrom == IDC_MESSAGE)
  907. {
  908. switch (code)
  909. {
  910. case EN_LINK:
  911. {
  912. ENLINK *enlink = reinterpret_cast<ENLINK*>(lParam);
  913. if (enlink && enlink->msg == WM_LBUTTONUP)
  914. {
  915. ASSERT(!helpTopicLink.empty());
  916. if (!helpTopicLink.empty())
  917. {
  918. Win::HtmlHelp(hwnd, helpTopicLink, HH_DISPLAY_TOPIC, 0);
  919. }
  920. }
  921. break;
  922. }
  923. default:
  924. {
  925. // do nothing
  926. break;
  927. }
  928. }
  929. }
  930. return result;
  931. }