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.

1401 lines
44 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. /////////////////////////////////////////////////////////////////////////////
  3. //
  4. // CServerNode
  5. //
  6. /////////////////////////////////////////////////////////////////////////////
  7. /////////////////////////////////////////////////////////////////////////////
  8. #include "stdafx.h"
  9. #include <Pop3RegKeys.h>
  10. #include <AuthID.h>
  11. // Access to Snapin
  12. #include "pop3.h"
  13. #include "pop3snap.h"
  14. // Access to Nodes we use
  15. #include "ServerNode.h"
  16. #include "DomainNode.h"
  17. // Access to dialogs we'll display
  18. #include "NewDomainDlg.h"
  19. #include "ServerProp.h"
  20. static const GUID CServerNodeGUID_NODETYPE =
  21. { 0x4c30b06c, 0x1dc3, 0x4c0d, { 0x87, 0xb4, 0x64, 0xbf, 0xe8, 0x22, 0xf4, 0x50 } };
  22. const GUID* CServerNode::m_NODETYPE = &CServerNodeGUID_NODETYPE;
  23. const OLECHAR* CServerNode::m_SZNODETYPE = OLESTR("4C30B06C-1DC3-4c0d-87B4-64BFE822F450");
  24. const OLECHAR* CServerNode::m_SZDISPLAY_NAME = OLESTR("");
  25. const CLSID* CServerNode::m_SNAPIN_CLASSID = &CLSID_POP3ServerSnap;
  26. /////////////////////////////////////////////////////////////////////////
  27. //
  28. // Class implementation
  29. //
  30. /////////////////////////////////////////////////////////////////////////
  31. /////////////////////////////////////////////////////////////////////////
  32. // CServerNode::CServerNode
  33. //
  34. // Constructor : Uses servername for remote Servers
  35. CServerNode::CServerNode(BSTR strServerName, CRootNode* pParent, BOOL bLocalServer) :
  36. m_lRefCount(1),
  37. m_hrValidServer(S_OK),
  38. m_bstrAuthentication(_T("")),
  39. m_bstrMailRoot(_T("")),
  40. m_bstrPort(_T("")),
  41. m_bstrLogLevel(_T("")),
  42. m_bstrServiceStatus(_T(""))
  43. {
  44. // Initialize our Scope item
  45. memset( &m_scopeDataItem, 0, sizeof(m_scopeDataItem) );
  46. m_scopeDataItem.mask = SDI_STR | SDI_IMAGE | SDI_OPENIMAGE | SDI_PARAM;
  47. m_scopeDataItem.displayname = MMC_CALLBACK;
  48. m_scopeDataItem.nImage = 0;
  49. m_scopeDataItem.nOpenImage = 0;
  50. m_scopeDataItem.lParam = (LPARAM) this;
  51. // Initialize our Result item
  52. memset( &m_resultDataItem, 0, sizeof(m_resultDataItem) );
  53. m_resultDataItem.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
  54. m_resultDataItem.str = MMC_CALLBACK;
  55. m_resultDataItem.nImage = 0;
  56. m_resultDataItem.lParam = (LPARAM) this;
  57. if( bLocalServer )
  58. {
  59. // We are the local server for now.
  60. TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1] = {0};
  61. DWORD dwBuffer = MAX_COMPUTERNAME_LENGTH+1;
  62. if( GetComputerName(szComputerName, &dwBuffer) )
  63. {
  64. m_bstrDisplayName = szComputerName;
  65. }
  66. else
  67. {
  68. #if DBG
  69. m_bstrDisplayName = CComBSTR("Local Server");
  70. #else
  71. m_bstrDisplayName = CComBSTR("");
  72. #endif
  73. }
  74. }
  75. // Get Parent Information
  76. m_pParent = pParent;
  77. // Open our Pop3 Admin Interface and store it
  78. HRESULT hr = CoCreateInstance(__uuidof(P3Config), NULL, CLSCTX_ALL, __uuidof(IP3Config), (LPVOID*)&m_spConfig);
  79. if( FAILED(hr) || !m_spConfig )
  80. {
  81. m_hrValidServer = FAILED(hr) ? hr : E_FAIL;
  82. return;
  83. }
  84. if( !bLocalServer )
  85. {
  86. // Configure our remote computer setup
  87. m_bstrDisplayName = strServerName;
  88. hr = m_spConfig->put_MachineName( strServerName );
  89. if( FAILED(hr) )
  90. {
  91. // Invalid Server Name!
  92. m_hrValidServer = hr;
  93. return;
  94. }
  95. }
  96. // Do our User creation property
  97. DWORD dwValue = 0;
  98. RegQueryCreateUser( dwValue, m_bstrDisplayName );
  99. m_bCreateUser = dwValue;
  100. }
  101. /////////////////////////////////////////////////////////////////////////
  102. // CServerNode::~CServerNode
  103. //
  104. // Destructor : Make sure to clean up our member-list
  105. CServerNode::~CServerNode()
  106. {
  107. for(DOMAINLIST::iterator iter = m_lDomains.begin(); iter != m_lDomains.end(); iter++)
  108. {
  109. delete (*iter);
  110. }
  111. m_lDomains.clear();
  112. }
  113. /////////////////////////////////////////////////////////////////////////
  114. // CServerNode::DeleteDomain
  115. //
  116. // Helper function to delete a child domain from all of POP3
  117. HRESULT CServerNode::DeleteDomain(CDomainNode* pDomainNode)
  118. {
  119. if( !pDomainNode ) return E_INVALIDARG;
  120. if( !m_spConfig ) return E_FAIL;
  121. // Delete from POP3 Admin Interface
  122. CComPtr<IP3Domains> spDomains;
  123. HRESULT hr = m_spConfig->get_Domains( &spDomains );
  124. // Update the P3Admin Interface
  125. if( SUCCEEDED(hr) )
  126. {
  127. hr = spDomains->Remove( pDomainNode->m_bstrDisplayName );
  128. }
  129. // Update our list
  130. if( SUCCEEDED(hr) )
  131. {
  132. m_lDomains.remove(pDomainNode);
  133. }
  134. return hr;
  135. }
  136. /////////////////////////////////////////////////////////////////////////
  137. // CServerNode::OnExpand
  138. //
  139. // Helper function to refresh list of domains and insert them
  140. HRESULT CServerNode::OnExpand(BOOL bExpand, HSCOPEITEM hScopeItem, IConsole* pConsole)
  141. {
  142. if( !hScopeItem || !pConsole ) return E_INVALIDARG;
  143. if( !m_spConfig ) return E_FAIL;
  144. HRESULT hr = S_OK;
  145. CComQIPtr<IConsoleNameSpace> spConsoleNameSpace = pConsole;
  146. if( !spConsoleNameSpace ) return E_NOINTERFACE;
  147. // If we have any children, delete them all from the namespace
  148. HSCOPEITEM hChild = NULL;
  149. MMC_COOKIE cookie = 0;
  150. hr = spConsoleNameSpace->GetChildItem(m_scopeDataItem.ID, &hChild, &cookie);
  151. if( SUCCEEDED(hr) && hChild )
  152. {
  153. hr = spConsoleNameSpace->DeleteItem(m_scopeDataItem.ID, FALSE);
  154. }
  155. if( SUCCEEDED(hr) )
  156. {
  157. // then delete all of our member-list of domains
  158. for(DOMAINLIST::iterator iter = m_lDomains.begin(); iter != m_lDomains.end(); iter++)
  159. {
  160. delete (*iter);
  161. }
  162. m_lDomains.clear();
  163. }
  164. if( FAILED(hr) || !bExpand )
  165. {
  166. // Error, or we are Contracting
  167. return S_OK;
  168. }
  169. // Expanding
  170. // Fill in our list of domains
  171. CComPtr<IP3Domains> spDomains;
  172. CComPtr<IEnumVARIANT> spDomainEnum;
  173. // Get the Domains
  174. hr = m_spConfig->get_Domains( &spDomains );
  175. // Get an Enumerator for the Domains
  176. if( SUCCEEDED(hr) )
  177. {
  178. hr = spDomains->get__NewEnum( &spDomainEnum );
  179. }
  180. // Loop through the domains, and add each new domain
  181. if( SUCCEEDED(hr) )
  182. {
  183. CComVariant var;
  184. ULONG lResult = 0;
  185. VariantInit( &var );
  186. while ( spDomainEnum->Next(1, &var, &lResult) == S_OK )
  187. {
  188. if ( lResult == 1 )
  189. {
  190. CComQIPtr<IP3Domain> spDomain;
  191. spDomain = V_DISPATCH(&var);
  192. CDomainNode* spDomainNode = new CDomainNode(spDomain, this);
  193. if( spDomainNode )
  194. {
  195. m_lDomains.push_back(spDomainNode);
  196. }
  197. }
  198. VariantClear(&var);
  199. }
  200. }
  201. if( SUCCEEDED(hr) )
  202. {
  203. for(DOMAINLIST::iterator iter = m_lDomains.begin(); iter != m_lDomains.end(); iter++)
  204. {
  205. CDomainNode* pDomain = *iter;
  206. pDomain->m_scopeDataItem.mask |= SDI_PARENT;
  207. pDomain->m_scopeDataItem.relativeID = m_scopeDataItem.ID;
  208. hr = spConsoleNameSpace->InsertItem( &(pDomain->m_scopeDataItem) );
  209. if( FAILED(hr) ) return hr;
  210. }
  211. }
  212. if( SUCCEEDED(hr) )
  213. {
  214. CComQIPtr<IConsole2> spCons2 = pConsole;
  215. if( spCons2 )
  216. {
  217. // Output the number of servers we added
  218. tstring strMessage = StrLoadString(IDS_SERVER_STATUSBAR);
  219. OLECHAR pszStatus[1024] = {0};
  220. _sntprintf( pszStatus, 1023, strMessage.c_str(), m_lDomains.size() );
  221. spCons2->SetStatusText( pszStatus );
  222. }
  223. }
  224. return hr;
  225. }
  226. /////////////////////////////////////////////////////////////////////////
  227. //
  228. // SnapInItemImpl
  229. //
  230. /////////////////////////////////////////////////////////////////////////
  231. /////////////////////////////////////////////////////////////////////////
  232. // CServerNode::GetScopePaneInfo
  233. //
  234. // Callback used to get Scope-Pane display information by MMC
  235. HRESULT CServerNode::GetScopePaneInfo(SCOPEDATAITEM *pScopeDataItem)
  236. {
  237. if( !pScopeDataItem ) return E_INVALIDARG;
  238. if( pScopeDataItem->mask & SDI_STR )
  239. pScopeDataItem->displayname = m_bstrDisplayName;
  240. if( pScopeDataItem->mask & SDI_IMAGE )
  241. pScopeDataItem->nImage = m_scopeDataItem.nImage;
  242. if( pScopeDataItem->mask & SDI_OPENIMAGE )
  243. pScopeDataItem->nOpenImage = m_scopeDataItem.nOpenImage;
  244. if( pScopeDataItem->mask & SDI_PARAM )
  245. pScopeDataItem->lParam = m_scopeDataItem.lParam;
  246. if( pScopeDataItem->mask & SDI_STATE )
  247. pScopeDataItem->nState = m_scopeDataItem.nState;
  248. return S_OK;
  249. }
  250. /////////////////////////////////////////////////////////////////////////
  251. // CServerNode::GetResultPaneInfo
  252. //
  253. // Callback used to get Result Pane display information by MMC
  254. HRESULT CServerNode::GetResultPaneInfo(RESULTDATAITEM *pResultDataItem)
  255. {
  256. if( !pResultDataItem ) return E_INVALIDARG;
  257. if( pResultDataItem->bScopeItem )
  258. {
  259. if( pResultDataItem->mask & RDI_STR )
  260. pResultDataItem->str = GetResultPaneColInfo(pResultDataItem->nCol);
  261. if( pResultDataItem->mask & RDI_IMAGE )
  262. pResultDataItem->nImage = m_scopeDataItem.nImage;
  263. if( pResultDataItem->mask & RDI_PARAM )
  264. pResultDataItem->lParam = m_scopeDataItem.lParam;
  265. return S_OK;
  266. }
  267. if( pResultDataItem->mask & RDI_STR )
  268. pResultDataItem->str = GetResultPaneColInfo(pResultDataItem->nCol);
  269. if( pResultDataItem->mask & RDI_IMAGE )
  270. pResultDataItem->nImage = m_resultDataItem.nImage;
  271. if( pResultDataItem->mask & RDI_PARAM )
  272. pResultDataItem->lParam = m_resultDataItem.lParam;
  273. if( pResultDataItem->mask & RDI_INDEX )
  274. pResultDataItem->nIndex = m_resultDataItem.nIndex;
  275. return S_OK;
  276. }
  277. /////////////////////////////////////////////////////////////////////////
  278. // CServerNode::GetResultPaneColInfo
  279. //
  280. // Helper function used as part of the GetResultPaneInfo. This function
  281. // will supply the text for the different columns.
  282. LPOLESTR CServerNode::GetResultPaneColInfo(int nCol)
  283. {
  284. if( !m_spConfig ) return L"";
  285. switch( nCol )
  286. {
  287. case 0: // Name
  288. {
  289. return m_bstrDisplayName;
  290. }
  291. case 1: // Authentication Type
  292. {
  293. CComPtr<IAuthMethods> spMethods;
  294. CComPtr<IAuthMethod> spAuth;
  295. CComVariant var;
  296. HRESULT hr = m_spConfig->get_Authentication( &spMethods );
  297. if( SUCCEEDED(hr) )
  298. {
  299. hr = spMethods->get_CurrentAuthMethod( &var );
  300. }
  301. if( SUCCEEDED(hr) )
  302. {
  303. hr = spMethods->get_Item( var, &spAuth );
  304. }
  305. if( SUCCEEDED(hr) )
  306. {
  307. hr = spAuth->get_Name( &m_bstrAuthentication );
  308. }
  309. if( FAILED(hr) )
  310. {
  311. #if DBG
  312. m_bstrAuthentication = _T("Unknown");
  313. #else
  314. m_bstrAuthentication = _T("");
  315. #endif
  316. }
  317. return m_bstrAuthentication;
  318. }
  319. case 2: // Root Mail Directory
  320. {
  321. HRESULT hr = m_spConfig->get_MailRoot( &m_bstrMailRoot );
  322. if( FAILED(hr) )
  323. {
  324. #if DBG
  325. m_bstrMailRoot = _T("Unknown");
  326. #else
  327. m_bstrMailRoot = _T("");
  328. #endif
  329. }
  330. return m_bstrMailRoot;
  331. }
  332. case 3: // Port
  333. {
  334. long lPort = 0;
  335. CComPtr<IP3Service> spService;
  336. HRESULT hr = m_spConfig->get_Service( &spService );
  337. if( SUCCEEDED(hr) )
  338. {
  339. hr = spService->get_Port( &lPort );
  340. if( FAILED(hr) )
  341. {
  342. lPort = 0;
  343. }
  344. }
  345. // 1K buffer: Not likely we'll exceed that many digits
  346. TCHAR szNum[1024] = {0};
  347. _sntprintf( szNum, 1023, _T("%d"), lPort );
  348. m_bstrPort = szNum;
  349. return m_bstrPort;
  350. }
  351. case 4: // Logging Level
  352. {
  353. long lLevel = 0;
  354. HRESULT hr = m_spConfig->get_LoggingLevel( &lLevel );
  355. switch( lLevel )
  356. {
  357. case 0:
  358. {
  359. m_bstrLogLevel = StrLoadString(IDS_SERVERPROP_LOG_0).c_str();
  360. break;
  361. }
  362. case 1:
  363. {
  364. m_bstrLogLevel = StrLoadString(IDS_SERVERPROP_LOG_1).c_str();
  365. break;
  366. }
  367. case 2:
  368. {
  369. m_bstrLogLevel = StrLoadString(IDS_SERVERPROP_LOG_2).c_str();
  370. break;
  371. }
  372. case 3:
  373. {
  374. m_bstrLogLevel = StrLoadString(IDS_SERVERPROP_LOG_3).c_str();
  375. break;
  376. }
  377. default:
  378. {
  379. m_bstrLogLevel = StrLoadString(IDS_SERVERPROP_LOG_0).c_str();
  380. break;
  381. }
  382. }
  383. return m_bstrLogLevel;
  384. }
  385. case 5: // Service Status
  386. {
  387. CComPtr<IP3Service> spService = NULL;
  388. long lServiceStatus = 0;
  389. HRESULT hr = m_spConfig->get_Service( &spService );
  390. if( SUCCEEDED(hr) )
  391. {
  392. hr = spService->get_POP3ServiceStatus( &lServiceStatus );
  393. }
  394. switch( lServiceStatus )
  395. {
  396. case SERVICE_STOPPED:
  397. {
  398. m_bstrServiceStatus = StrLoadString(IDS_STATE_STOPPED).c_str();
  399. break;
  400. }
  401. case SERVICE_RUNNING:
  402. {
  403. m_bstrServiceStatus = StrLoadString(IDS_STATE_RUNNING).c_str();
  404. break;
  405. }
  406. case SERVICE_PAUSED:
  407. {
  408. m_bstrServiceStatus = StrLoadString(IDS_STATE_PAUSED).c_str();
  409. break;
  410. }
  411. default:
  412. {
  413. m_bstrServiceStatus = StrLoadString(IDS_STATE_PENDING).c_str();
  414. break;
  415. }
  416. }
  417. return m_bstrServiceStatus;
  418. }
  419. default:
  420. {
  421. #if DBG
  422. return L"No Information";
  423. #else
  424. return L"";
  425. #endif
  426. }
  427. }
  428. }
  429. /////////////////////////////////////////////////////////////////////////
  430. // CServerNode::GetResultViewType
  431. //
  432. // Sets the Result Pane to be:
  433. // 0 Domains : Message View
  434. // Non-0 Domains : List View
  435. HRESULT CServerNode::GetResultViewType( LPOLESTR* ppViewType, long* pViewOptions )
  436. {
  437. // Get the Count of Domains
  438. CComPtr<IP3Domains> spDomains = NULL;
  439. long lDomains = 0;
  440. // Get the Domains
  441. HRESULT hr = m_spConfig->get_Domains( &spDomains );
  442. if( SUCCEEDED(hr) )
  443. {
  444. spDomains->get_Count( &lDomains );
  445. }
  446. if( lDomains == 0 )
  447. {
  448. // Message View
  449. return StringFromCLSID(CLSID_MessageView, ppViewType);
  450. }
  451. return S_FALSE; // Default List View
  452. }
  453. /////////////////////////////////////////////////////////////////////////
  454. // CServerNode::Notify
  455. //
  456. // Core callback functionality of this Node. MMC will use this function
  457. // for all MMC provided functionality, such as Expanding, Renaming, and
  458. // Context Help
  459. HRESULT CServerNode::Notify( MMC_NOTIFY_TYPE event,
  460. LPARAM arg,
  461. LPARAM param,
  462. IComponentData* pComponentData,
  463. IComponent* pComponent,
  464. DATA_OBJECT_TYPES type)
  465. {
  466. HRESULT hr = S_FALSE;
  467. _ASSERTE(pComponentData != NULL || pComponent != NULL);
  468. CComPtr<IConsole> spConsole = NULL;
  469. if( pComponentData )
  470. {
  471. spConsole = ((CPOP3ServerSnapData*)pComponentData)->m_spConsole;
  472. }
  473. else if( pComponent )
  474. {
  475. spConsole = ((CPOP3ServerSnapComponent*)pComponent)->m_spConsole;
  476. }
  477. if( !spConsole ) return E_INVALIDARG;
  478. switch( event )
  479. {
  480. case MMCN_SHOW:
  481. {
  482. tstring strHeader;
  483. CComQIPtr<IHeaderCtrl2> spHeaderCtrl = spConsole;
  484. CComQIPtr<IResultData> spResultData = spConsole;
  485. if( !spHeaderCtrl || !spResultData ) return E_NOINTERFACE;
  486. hr = spResultData->DeleteAllRsltItems();
  487. if( arg )
  488. {
  489. if( m_lDomains.empty() )
  490. {
  491. // configure the ocx message in the result pane
  492. IMessageView* pIMessageView = NULL;
  493. LPUNKNOWN pIUnk = NULL;
  494. hr = spConsole->QueryResultView(&pIUnk);
  495. if( SUCCEEDED(hr) )
  496. {
  497. hr = pIUnk->QueryInterface(_uuidof(IMessageView), reinterpret_cast<void**>(&pIMessageView));
  498. }
  499. if( SUCCEEDED(hr) )
  500. {
  501. hr = pIMessageView->SetIcon(Icon_Information);
  502. }
  503. if( SUCCEEDED(hr) )
  504. {
  505. tstring strTitle = StrLoadString( IDS_SNAPINNAME );
  506. hr = pIMessageView->SetTitleText( strTitle.c_str() );
  507. }
  508. if( SUCCEEDED(hr) )
  509. {
  510. tstring strMessage = StrLoadString( IDS_ERROR_NODOMAIN );
  511. hr = pIMessageView->SetBodyText( strMessage.c_str() );
  512. }
  513. if( pIMessageView )
  514. {
  515. pIMessageView->Release();
  516. pIMessageView = NULL;
  517. }
  518. if( pIUnk )
  519. {
  520. pIUnk->Release();
  521. pIUnk = NULL;
  522. }
  523. return hr;
  524. }
  525. else
  526. {
  527. if( SUCCEEDED(hr) )
  528. {
  529. strHeader = StrLoadString(IDS_HEADER_DOMAIN_NAME);
  530. hr = spHeaderCtrl->InsertColumn(0, strHeader.c_str(), LVCFMT_LEFT, 100);
  531. }
  532. if( SUCCEEDED(hr) )
  533. {
  534. strHeader = StrLoadString(IDS_HEADER_DOMAIN_NUMBOX);
  535. hr = spHeaderCtrl->InsertColumn(1, strHeader.c_str(), LVCFMT_LEFT, 100);
  536. }
  537. if( SUCCEEDED(hr) )
  538. {
  539. strHeader = StrLoadString(IDS_HEADER_DOMAIN_SIZE);
  540. hr = spHeaderCtrl->InsertColumn(2, strHeader.c_str(), LVCFMT_LEFT, 100);
  541. }
  542. if( SUCCEEDED(hr) )
  543. {
  544. strHeader = StrLoadString(IDS_HEADER_DOMAIN_NUMMES);
  545. hr = spHeaderCtrl->InsertColumn(3, strHeader.c_str(), LVCFMT_LEFT, 100);
  546. }
  547. if( SUCCEEDED(hr) )
  548. {
  549. strHeader = StrLoadString(IDS_HEADER_DOMAIN_LOCKED);
  550. hr = spHeaderCtrl->InsertColumn(4, strHeader.c_str(), LVCFMT_LEFT, 100);
  551. }
  552. if( SUCCEEDED(hr) )
  553. {
  554. CComQIPtr<IConsole2> spCons2 = spConsole;
  555. if( spCons2 )
  556. {
  557. // Output the number of servers we added
  558. tstring strMessage = StrLoadString(IDS_SERVER_STATUSBAR);
  559. OLECHAR pszStatus[1024] = {0};
  560. _sntprintf( pszStatus, 1023, strMessage.c_str(), m_lDomains.size() );
  561. spCons2->SetStatusText( pszStatus );
  562. }
  563. }
  564. }
  565. }
  566. break;
  567. }
  568. case MMCN_EXPAND:
  569. {
  570. hr = OnExpand(arg, m_scopeDataItem.ID, spConsole);
  571. break;
  572. }
  573. case MMCN_ADD_IMAGES:
  574. {
  575. IImageList* pImageList = (IImageList*)arg;
  576. if( !pImageList ) return E_INVALIDARG;
  577. hr = LoadImages(pImageList);
  578. break;
  579. }
  580. case MMCN_REFRESH:
  581. {
  582. hr = OnExpand(TRUE, m_scopeDataItem.ID, spConsole);
  583. if( SUCCEEDED(hr) )
  584. {
  585. CComQIPtr<IConsole2> spCons2 = spConsole;
  586. if( spCons2 )
  587. {
  588. // Output the number of servers we added
  589. tstring strMessage = StrLoadString(IDS_SERVER_STATUSBAR);
  590. OLECHAR pszStatus[1024] = {0};
  591. _sntprintf( pszStatus, 1023, strMessage.c_str(), m_lDomains.size() );
  592. spCons2->SetStatusText( pszStatus );
  593. }
  594. }
  595. break;
  596. }
  597. case MMCN_SELECT:
  598. {
  599. // if selecting node
  600. if( HIWORD(arg) )
  601. {
  602. hr = S_OK;
  603. // get the verb interface and enable rename
  604. CComPtr<IConsoleVerb> spConsVerb;
  605. if( spConsole->QueryConsoleVerb(&spConsVerb) == S_OK )
  606. {
  607. // Enable the Properties Menu
  608. hr = spConsVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE);
  609. if( FAILED(hr) ) return hr;
  610. hr = spConsVerb->SetVerbState(MMC_VERB_PROPERTIES, HIDDEN, FALSE);
  611. if( FAILED(hr) ) return hr;
  612. // Enable the Refresh Menu
  613. hr = spConsVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, TRUE);
  614. if( FAILED(hr) ) return hr;
  615. hr = spConsVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, FALSE);
  616. if( FAILED(hr) ) return hr;
  617. }
  618. }
  619. break;
  620. }
  621. case MMCN_VIEW_CHANGE:
  622. {
  623. if( (param == NAV_ADD) ||
  624. (param == NAV_DELETE) )
  625. {
  626. CComQIPtr<IConsole2> spCons2 = spConsole;
  627. if( spCons2 )
  628. {
  629. hr = spCons2->SelectScopeItem( m_scopeDataItem.ID );
  630. }
  631. }
  632. break;
  633. }
  634. case MMCN_CONTEXTHELP:
  635. {
  636. hr = S_OK;
  637. TCHAR szWindowsDir[MAX_PATH+1] = {0};
  638. tstring strHelpFile = _T("");
  639. tstring strHelpFileName = StrLoadString(IDS_HELPFILE);
  640. tstring strHelpTopicName = StrLoadString(IDS_HELPTOPIC);
  641. if( strHelpFileName.empty() || strHelpTopicName.empty() )
  642. {
  643. return E_FAIL;
  644. }
  645. // Build path to d:\windows\help
  646. UINT nSize = GetSystemWindowsDirectory( szWindowsDir, MAX_PATH );
  647. if( nSize == 0 || nSize > MAX_PATH )
  648. {
  649. return E_FAIL;
  650. }
  651. strHelpFile = szWindowsDir; // D:\windows
  652. strHelpFile += _T("\\Help\\"); // \help
  653. strHelpFile += strHelpFileName; // \filename.chm
  654. strHelpFile += _T("::/"); // ::/
  655. strHelpFile += strHelpTopicName; // index.htm
  656. // Show the Help topic
  657. CComQIPtr<IDisplayHelp> spHelp = spConsole;
  658. if( !spHelp ) return E_NOINTERFACE;
  659. hr = spHelp->ShowTopic( (LPTSTR)strHelpFile.c_str() );
  660. break;
  661. }
  662. }// switch
  663. return hr;
  664. }
  665. /////////////////////////////////////////////////////////////////////////
  666. //
  667. // ContextMenuImpl
  668. //
  669. /////////////////////////////////////////////////////////////////////////
  670. /////////////////////////////////////////////////////////////////////////
  671. // CServerNode::AddMenuItems
  672. //
  673. // Adds our context menus into the appropriate MMC provided menu
  674. // locations.
  675. HRESULT CServerNode::AddMenuItems(LPCONTEXTMENUCALLBACK piCallback, long* pInsertionAllowed, DATA_OBJECT_TYPES type )
  676. {
  677. if( !piCallback || !pInsertionAllowed ) return E_INVALIDARG;
  678. if( !m_spConfig ) return E_FAIL;
  679. HRESULT hr = S_OK;
  680. tstring strMenu = _T("");
  681. tstring strDesc = _T("");
  682. CComQIPtr<IContextMenuCallback2> spContext2 = piCallback;
  683. if( !spContext2 ) return E_NOINTERFACE;
  684. CONTEXTMENUITEM2 singleMenuItem;
  685. ZeroMemory(&singleMenuItem, sizeof(CONTEXTMENUITEM2));
  686. singleMenuItem.fFlags = MF_ENABLED;
  687. // Add the Disconnect Menu to the "Top" part of the MMC Context Menu
  688. if( *pInsertionAllowed & CCM_INSERTIONALLOWED_TOP )
  689. {
  690. strMenu = StrLoadString(IDS_MENU_SERVER_DISCON);
  691. strDesc = StrLoadString(IDS_MENU_SERVER_DISCON_DESC);
  692. singleMenuItem.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TOP;
  693. singleMenuItem.strName = (LPWSTR)strMenu.c_str();
  694. singleMenuItem.strStatusBarText = (LPWSTR)strDesc.c_str();
  695. singleMenuItem.strLanguageIndependentName = L"SERVER_DISCONNECT";
  696. singleMenuItem.lCommandID = IDM_SERVER_TOP_DISCONNECT;
  697. if( !strMenu.empty() )
  698. {
  699. hr = spContext2->AddItem( &singleMenuItem );
  700. if( FAILED(hr) ) return hr;
  701. }
  702. }
  703. // Add the Domain Menu to the "New" part of the MMC Context Menu
  704. if( (*pInsertionAllowed & CCM_INSERTIONALLOWED_NEW) )
  705. {
  706. strMenu = StrLoadString(IDS_MENU_SERVER_NEWDOM);
  707. strDesc = StrLoadString(IDS_MENU_SERVER_NEWDOM_DESC);
  708. singleMenuItem.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_NEW;
  709. singleMenuItem.strName = (LPWSTR)strMenu.c_str();
  710. singleMenuItem.strStatusBarText = (LPWSTR)strDesc.c_str();
  711. singleMenuItem.strLanguageIndependentName = L"NEW_DOMAIN";
  712. singleMenuItem.lCommandID = IDM_SERVER_NEW_DOMAIN;
  713. if( !strMenu.empty() )
  714. {
  715. hr = spContext2->AddItem( &singleMenuItem );
  716. if( FAILED(hr) ) return hr;
  717. }
  718. }
  719. // Add the Service Operation Menus to the "Task" part of the MMC Context Menu
  720. if( *pInsertionAllowed & CCM_INSERTIONALLOWED_TASK )
  721. {
  722. CComPtr<IP3Service> spService;
  723. hr = m_spConfig->get_Service( &spService );
  724. if( FAILED(hr) ) return hr;
  725. long lServiceStatus = 0;
  726. hr = spService->get_POP3ServiceStatus( &lServiceStatus );
  727. if( FAILED(hr) ) return hr;
  728. singleMenuItem.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TASK;
  729. if( lServiceStatus == SERVICE_STOPPED )
  730. {
  731. strMenu = StrLoadString(IDS_MENU_SERVER_START);
  732. strDesc = StrLoadString(IDS_MENU_SERVER_START_DESC);
  733. singleMenuItem.strName = (LPWSTR)strMenu.c_str();
  734. singleMenuItem.strStatusBarText = (LPWSTR)strDesc.c_str();
  735. singleMenuItem.strLanguageIndependentName = L"SERVER_START";
  736. singleMenuItem.lCommandID = IDM_SERVER_TASK_START;
  737. if( !strMenu.empty() )
  738. {
  739. hr = spContext2->AddItem( &singleMenuItem );
  740. if( FAILED(hr) ) return hr;
  741. }
  742. }
  743. if( lServiceStatus == SERVICE_PAUSED )
  744. {
  745. strMenu = StrLoadString(IDS_MENU_SERVER_RESUME);
  746. strDesc = StrLoadString(IDS_MENU_SERVER_RESUME_DESC);
  747. singleMenuItem.strName = (LPWSTR)strMenu.c_str();
  748. singleMenuItem.strStatusBarText = (LPWSTR)strDesc.c_str();
  749. singleMenuItem.strLanguageIndependentName = L"SERVER_RESUME";
  750. singleMenuItem.lCommandID = IDM_SERVER_TASK_RESUME;
  751. if( !strMenu.empty() )
  752. {
  753. hr = spContext2->AddItem( &singleMenuItem );
  754. if( FAILED(hr) ) return hr;
  755. }
  756. }
  757. if( lServiceStatus == SERVICE_RUNNING )
  758. {
  759. strMenu = StrLoadString(IDS_MENU_SERVER_PAUSE);
  760. strDesc = StrLoadString(IDS_MENU_SERVER_PAUSE_DESC);
  761. singleMenuItem.strName = (LPWSTR)strMenu.c_str();
  762. singleMenuItem.strStatusBarText = (LPWSTR)strDesc.c_str();
  763. singleMenuItem.strLanguageIndependentName = L"SERVER_PAUSE";
  764. singleMenuItem.lCommandID = IDM_SERVER_TASK_PAUSE;
  765. if( !strMenu.empty() )
  766. {
  767. hr = spContext2->AddItem( &singleMenuItem );
  768. if( FAILED(hr) ) return hr;
  769. }
  770. }
  771. if( (lServiceStatus == SERVICE_RUNNING) ||
  772. (lServiceStatus == SERVICE_PAUSED) )
  773. {
  774. strMenu = StrLoadString(IDS_MENU_SERVER_STOP);
  775. strDesc = StrLoadString(IDS_MENU_SERVER_STOP_DESC);
  776. singleMenuItem.strName = (LPWSTR)strMenu.c_str();
  777. singleMenuItem.strStatusBarText = (LPWSTR)strDesc.c_str();
  778. singleMenuItem.strLanguageIndependentName = L"SERVER_STOP";
  779. singleMenuItem.lCommandID = IDM_SERVER_TASK_STOP;
  780. if( !strMenu.empty() )
  781. {
  782. hr = spContext2->AddItem( &singleMenuItem );
  783. if( FAILED(hr) ) return hr;
  784. }
  785. }
  786. if( (lServiceStatus == SERVICE_RUNNING) ||
  787. (lServiceStatus == SERVICE_PAUSED) )
  788. {
  789. strMenu = StrLoadString(IDS_MENU_SERVER_RESTART);
  790. strDesc = StrLoadString(IDS_MENU_SERVER_RESTART_DESC);
  791. singleMenuItem.strName = (LPWSTR)strMenu.c_str();
  792. singleMenuItem.strStatusBarText = (LPWSTR)strDesc.c_str();
  793. singleMenuItem.strLanguageIndependentName = L"SERVER_RESTART";
  794. singleMenuItem.lCommandID = IDM_SERVER_TASK_RESTART;
  795. if( !strMenu.empty() )
  796. {
  797. hr = spContext2->AddItem( &singleMenuItem );
  798. if( FAILED(hr) ) return hr;
  799. }
  800. }
  801. }
  802. return hr;
  803. }
  804. /////////////////////////////////////////////////////////////////////////
  805. // CServerNode::OnNewDomain
  806. //
  807. // Display a NewDomain dialog, and add the new domain
  808. HRESULT CServerNode::OnNewDomain( bool& bHandled, CSnapInObjectRootBase* pObj )
  809. {
  810. if( !pObj ) return E_INVALIDARG;
  811. if( !m_spConfig ) return E_FAIL;
  812. bHandled = true;
  813. HRESULT hr = S_OK;
  814. // Load a dialog that asks for a Domain Name
  815. CNewDomainDlg dlg;
  816. if( dlg.DoModal() == IDOK )
  817. {
  818. HWND hWnd = NULL;
  819. CComPtr<IConsole> spConsole = NULL;
  820. // Get a window handle
  821. hr = GetConsole( pObj, &spConsole );
  822. if( FAILED(hr) || !spConsole ) return E_NOINTERFACE;
  823. spConsole->GetMainWindow(&hWnd);
  824. // Access our POP3 Domain list
  825. CComPtr<IP3Domains> spDomains;
  826. hr = m_spConfig->get_Domains( &spDomains );
  827. // Add our domain to the POP3 Admin domainlist
  828. if( SUCCEEDED(hr) )
  829. {
  830. CComBSTR bstrName = dlg.m_strName.c_str();
  831. hr = spDomains->Add( bstrName );
  832. }
  833. // Check for weird pre-existance condition
  834. if( hr == ERROR_FILE_EXISTS )
  835. {
  836. tstring strMessage = StrLoadString( IDS_WARNING_DOMAINEXISTS );
  837. tstring strTitle = StrLoadString(IDS_SNAPINNAME);
  838. MessageBox( hWnd, strMessage.c_str(), strTitle.c_str(), MB_OK | MB_ICONWARNING );
  839. }
  840. if( SUCCEEDED(hr) )
  841. {
  842. CComVariant var;
  843. CComPtr<IP3Domain> spDomain = NULL;
  844. CDomainNode* pDomainNode = NULL;
  845. // Get a grasp of the Domain interface to pass to the node
  846. VariantInit(&var);
  847. var = dlg.m_strName.c_str();
  848. hr = spDomains->get_Item( var, &spDomain );
  849. if( SUCCEEDED(hr) )
  850. {
  851. // Add the new Domain to our list of domains
  852. pDomainNode = new CDomainNode( spDomain, this );
  853. if( !pDomainNode ) hr = E_OUTOFMEMORY;
  854. }
  855. if( SUCCEEDED(hr) )
  856. {
  857. pDomainNode->m_scopeDataItem.mask |= SDI_PARENT;
  858. pDomainNode->m_scopeDataItem.relativeID = m_scopeDataItem.ID;
  859. m_lDomains.push_back( pDomainNode );
  860. // Add the new domain into the namespace
  861. // Insert it into the result tree
  862. CComQIPtr<IConsoleNameSpace2> spNameSpace = spConsole;
  863. if( !spNameSpace ) return E_NOINTERFACE;
  864. hr = spNameSpace->InsertItem( &(pDomainNode->m_scopeDataItem) );
  865. }
  866. if( SUCCEEDED(hr) )
  867. {
  868. // Get our Data Object
  869. CComPtr<IDataObject> spDataObject = NULL;
  870. GetDataObject(&spDataObject, CCT_SCOPE);
  871. if( !spDataObject ) return E_FAIL;
  872. // Call the Update, but don't update return result
  873. spConsole->UpdateAllViews( spDataObject, 0, (LONG_PTR)NAV_ADD );
  874. }
  875. }
  876. if( FAILED(hr) )
  877. {
  878. // Failed to add the Domain
  879. tstring strMessage = StrLoadString(IDS_ERROR_CREATEDOMAIN);
  880. tstring strTitle = StrLoadString(IDS_SNAPINNAME);
  881. DisplayError( hWnd, strMessage.c_str(), strTitle.c_str(), hr );
  882. }
  883. }
  884. return hr;
  885. }
  886. /////////////////////////////////////////////////////////////////////////
  887. // CServerNode::OnDisconnect
  888. //
  889. // Disconnect is essentially deleting ourselves from the list of servers
  890. HRESULT CServerNode::OnDisconnect( bool& bHandled, CSnapInObjectRootBase* pObj )
  891. {
  892. if( !pObj ) return E_INVALIDARG;
  893. if( !m_pParent ) return E_FAIL;
  894. bHandled = true;
  895. HRESULT hr = S_OK;
  896. // Get the Window Handle
  897. HWND hWnd = NULL;
  898. CComPtr<IConsole> spConsole = NULL;
  899. hr = GetConsole( pObj, &spConsole );
  900. if( FAILED(hr) || !spConsole ) return E_NOINTERFACE;
  901. spConsole->GetMainWindow(&hWnd);
  902. // Load the message box
  903. tstring strDeleteWarning = StrLoadString( IDS_SERVER_CONFIRMDISCONNECT );
  904. tstring strTitle = StrLoadString( IDS_SNAPINNAME );
  905. tstring strPropPageOpen = StrLoadString( IDS_WARNING_PROP_PAGE_OPEN );
  906. if(1!=m_lRefCount)
  907. {
  908. MessageBox(hWnd, strPropPageOpen.c_str(),strTitle.c_str(),MB_OK);
  909. return hr; //Not error case
  910. }
  911. if( MessageBox(hWnd, strDeleteWarning.c_str(), strTitle.c_str(), MB_YESNO | MB_ICONWARNING ) == IDYES )
  912. {
  913. // Remove ourselves from the tree
  914. CComQIPtr<IConsoleNameSpace2> spNameSpace = spConsole;
  915. if( !spNameSpace ) return E_NOINTERFACE;
  916. hr = spNameSpace->DeleteItem( m_scopeDataItem.ID, TRUE );
  917. // The parent needs to do the deletion
  918. if( SUCCEEDED(hr) )
  919. {
  920. hr = m_pParent->DeleteServer(this);
  921. }
  922. if( SUCCEEDED(hr) )
  923. {
  924. delete this;
  925. }
  926. }
  927. return hr;
  928. }
  929. /////////////////////////////////////////////////////////////////////////
  930. // CServerNode::OnServerService
  931. //
  932. // Function to handle the Start/Stop/Pause/Restart of the POP3 Service
  933. // on this computer
  934. HRESULT CServerNode::OnServerService( UINT nID, bool& bHandled, CSnapInObjectRootBase* pObj )
  935. {
  936. if( !m_spConfig ) return E_FAIL;
  937. bHandled = true;
  938. HCURSOR hOldCursor = NULL;
  939. HCURSOR hWaitCursor = ::LoadCursor(NULL, IDC_WAIT);
  940. if (hWaitCursor)
  941. {
  942. hOldCursor = ::SetCursor(hWaitCursor);
  943. }
  944. // Get the Window Handle
  945. HWND hWnd = NULL;
  946. CComPtr<IConsole> spConsole = NULL;
  947. tstring strTitle = StrLoadString( IDS_SNAPINNAME );
  948. tstring strMessage = _T("");
  949. HRESULT hr = GetConsole( pObj, &spConsole );
  950. if( FAILED(hr) || !spConsole ) return E_NOINTERFACE;
  951. spConsole->GetMainWindow(&hWnd);
  952. // Get the POP3 Service
  953. CComPtr<IP3Service> spService = NULL;
  954. hr = m_spConfig->get_Service( &spService );
  955. // Do the appropriate service operation
  956. switch( nID )
  957. {
  958. case IDM_SERVER_TASK_START:
  959. {
  960. if( SUCCEEDED(hr) )
  961. {
  962. hr = spService->StartPOP3Service();
  963. }
  964. // Used for both Start failure, and Service retreival failure
  965. if( FAILED(hr) )
  966. {
  967. strMessage = StrLoadString( IDS_ERROR_STARTSERVICE );
  968. DisplayError( hWnd, strMessage.c_str(), strTitle.c_str(), hr );
  969. }
  970. break;
  971. }
  972. case IDM_SERVER_TASK_RESUME:
  973. {
  974. if( SUCCEEDED(hr) )
  975. {
  976. hr = spService->ResumePOP3Service();
  977. }
  978. // Used for both Start failure, and Service retreival failure
  979. if( FAILED(hr) )
  980. {
  981. strMessage = StrLoadString( IDS_ERROR_RESUMESERVICE );
  982. DisplayError( hWnd, strMessage.c_str(), strTitle.c_str(), hr );
  983. }
  984. break;
  985. }
  986. case IDM_SERVER_TASK_STOP:
  987. {
  988. if( SUCCEEDED(hr) )
  989. {
  990. hr = spService->StopPOP3Service();
  991. }
  992. // Used for both Start failure, and Service retreival failure
  993. if( FAILED(hr) )
  994. {
  995. strMessage = StrLoadString( IDS_ERROR_STOPSERVICE );
  996. DisplayError( hWnd, strMessage.c_str(), strTitle.c_str(), hr );
  997. }
  998. break;
  999. }
  1000. case IDM_SERVER_TASK_PAUSE:
  1001. {
  1002. if( SUCCEEDED(hr) )
  1003. {
  1004. hr = spService->PausePOP3Service();
  1005. }
  1006. if( FAILED(hr) )
  1007. {
  1008. strMessage = StrLoadString( IDS_ERROR_PAUSESERVICE );
  1009. DisplayError( hWnd, strMessage.c_str(), strTitle.c_str(), hr );
  1010. }
  1011. break;
  1012. }
  1013. case IDM_SERVER_TASK_RESTART:
  1014. {
  1015. if( SUCCEEDED(hr) )
  1016. {
  1017. hr = spService->StopPOP3Service();
  1018. }
  1019. if( SUCCEEDED(hr) )
  1020. {
  1021. hr = spService->StartPOP3Service();
  1022. }
  1023. // Used for both Start failure, and Service retreival failure
  1024. if( FAILED(hr) )
  1025. {
  1026. strMessage = StrLoadString( IDS_ERROR_RESTARTSERVICE );
  1027. DisplayError( hWnd, strMessage.c_str(), strTitle.c_str(), hr );
  1028. }
  1029. break;
  1030. }
  1031. }
  1032. ::SetCursor(hOldCursor);
  1033. if( SUCCEEDED(hr) )
  1034. {
  1035. CComQIPtr<IConsoleNameSpace2> spNameSpace = spConsole;
  1036. if( spNameSpace )
  1037. {
  1038. spNameSpace->SetItem( &m_scopeDataItem );
  1039. }
  1040. }
  1041. return hr;
  1042. }
  1043. /////////////////////////////////////////////////////////////////////////
  1044. //
  1045. // PropertyPageImpl
  1046. //
  1047. /////////////////////////////////////////////////////////////////////////
  1048. /////////////////////////////////////////////////////////////////////////
  1049. // CServerNode::CreatePropertyPages
  1050. //
  1051. // Fills MMC's callback with our property pages
  1052. HRESULT CServerNode::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider, LONG_PTR handle, IUnknown* pUnk, DATA_OBJECT_TYPES type)
  1053. {
  1054. if( !lpProvider ) return E_INVALIDARG;
  1055. if( !m_spConfig ) return E_FAIL;
  1056. HRESULT hr = E_FAIL;
  1057. // Load our Server's General page
  1058. HPROPSHEETPAGE hpageGen = NULL;
  1059. InterlockedIncrement(&m_lRefCount);
  1060. CServerGeneralPage* pGenPage = new CServerGeneralPage(m_spConfig, handle, this);
  1061. if( pGenPage != NULL )
  1062. {
  1063. hpageGen = pGenPage->Create();
  1064. }
  1065. // Add it to the list of pages
  1066. if( hpageGen )
  1067. {
  1068. hr = lpProvider->AddPage(hpageGen);
  1069. }
  1070. // Destruct correctly if failure results
  1071. if( FAILED(hr) )
  1072. {
  1073. InterlockedDecrement(&m_lRefCount);
  1074. if( hpageGen )
  1075. {
  1076. DestroyPropertySheetPage(hpageGen);
  1077. }
  1078. else if (pGenPage)
  1079. {
  1080. delete pGenPage;
  1081. pGenPage = NULL;
  1082. }
  1083. }
  1084. return hr;
  1085. }
  1086. /////////////////////////////////////////////////////////////////////////
  1087. //
  1088. // Helper Functions
  1089. //
  1090. /////////////////////////////////////////////////////////////////////////
  1091. /////////////////////////////////////////////////////////////////////////
  1092. // CServerNode::GetAuth
  1093. //
  1094. // pbHashPW : Return Boolean for Hash Password Authentication
  1095. // pbSAM : Return Boolean for Local SAM Authentication
  1096. HRESULT CServerNode::GetAuth(BOOL* pbHashPW, BOOL* pbSAM)
  1097. {
  1098. if( !m_spConfig ) return E_FAIL;
  1099. CComPtr<IAuthMethods> spMethods;
  1100. CComPtr<IAuthMethod> spAuth;
  1101. CComVariant var;
  1102. CComBSTR bstrID;
  1103. long lCurrent = 0L;
  1104. HRESULT hr = m_spConfig->get_Authentication( &spMethods );
  1105. if ( SUCCEEDED(hr) )
  1106. {
  1107. hr = spMethods->get_CurrentAuthMethod( &var );
  1108. }
  1109. if ( SUCCEEDED(hr) )
  1110. {
  1111. hr = spMethods->get_Item( var, &spAuth );
  1112. }
  1113. if( SUCCEEDED(hr) )
  1114. {
  1115. hr = spAuth->get_ID( &bstrID );
  1116. }
  1117. if( SUCCEEDED(hr) && pbHashPW )
  1118. {
  1119. *pbHashPW = (_tcsicmp(bstrID, SZ_AUTH_ID_MD5_HASH) == 0);
  1120. }
  1121. if( SUCCEEDED(hr) && pbSAM )
  1122. {
  1123. *pbSAM = (_tcsicmp(bstrID, SZ_AUTH_ID_LOCAL_SAM) == 0);
  1124. }
  1125. return hr;
  1126. }
  1127. /////////////////////////////////////////////////////////////////////////
  1128. // CServerNode::GetConfirmAddUser
  1129. //
  1130. // pbConfirm : Return Boolean for User Add Confirmation
  1131. HRESULT CServerNode::GetConfirmAddUser( BOOL *pbConfirm )
  1132. {
  1133. if( !m_spConfig ) return E_POINTER;
  1134. return m_spConfig->get_ConfirmAddUser( pbConfirm );
  1135. }
  1136. /////////////////////////////////////////////////////////////////////////
  1137. // CServerNode::SetConfirmAddUser
  1138. //
  1139. // pbConfirm : New Boolean Value for User Add Confirmation
  1140. HRESULT CServerNode::SetConfirmAddUser( BOOL bConfirm )
  1141. {
  1142. if( !m_spConfig ) return E_POINTER;
  1143. return m_spConfig->put_ConfirmAddUser( bConfirm );
  1144. }
  1145. void CServerNode::Release()
  1146. {
  1147. InterlockedDecrement(&m_lRefCount);
  1148. if(m_lRefCount<1)
  1149. InterlockedIncrement(&m_lRefCount);
  1150. }