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.

1642 lines
51 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. nwshui.cxx
  5. Abstract:
  6. This module implements the context menu actions of shell extension classes.
  7. Author:
  8. Yi-Hsin Sung (yihsins) 25-Oct-1995
  9. --*/
  10. #include <nt.h>
  11. #include <ntrtl.h>
  12. #include <nturtl.h>
  13. #include <windows.h>
  14. #include <commctrl.h>
  15. #include <shellapi.h>
  16. #include <shlobj.h>
  17. #define DONT_WANT_SHELLDEBUG
  18. #include <shlobjp.h>
  19. #include <winnetwk.h>
  20. #include <npapi.h>
  21. #include <ntddnwfs.h>
  22. #include <ndsapi32.h>
  23. #include <nwapi.h>
  24. #include <nwwks.h>
  25. #include <nwmisc.h>
  26. //extern "C"
  27. //{
  28. #include "nwutil.h"
  29. //}
  30. #include "nwshcmn.h"
  31. #include "nwshrc.h"
  32. extern "C"
  33. {
  34. NTSTATUS
  35. NwNdsOpenRdrHandle(
  36. OUT PHANDLE phandleRdr );
  37. }
  38. #define MAX_ONE_CONN_INFORMATION_SIZE 512
  39. #define NW_ENUM_EXTRA_BYTES 256
  40. #define GLOBAL_WHOAMI_REFRESH_INTERVAL 30000 // in milliseconds, Win95 uses 10000
  41. DWORD
  42. LogoutFromServer(
  43. LPWSTR pszServer,
  44. PBOOL pfDisconnected
  45. );
  46. INT_PTR
  47. CALLBACK
  48. GlobalWhoAmIDlgProc(
  49. HWND hwndDlg,
  50. UINT msg,
  51. WPARAM wParam,
  52. LPARAM lParam );
  53. VOID
  54. GetConnectionStatusString(
  55. PCONN_STATUS pConnStatus,
  56. LPBYTE Buffer,
  57. DWORD nSize
  58. );
  59. HRESULT
  60. NWUIWhoAmI(
  61. HWND hParent,
  62. LPNETRESOURCE pNetRes
  63. )
  64. {
  65. DWORD err = NO_ERROR;
  66. DWORD_PTR ResumeKey = 0;
  67. LPBYTE pBuffer = NULL;
  68. DWORD EntriesRead = 0;
  69. DWORD dwMessageId;
  70. WCHAR szUserName[MAX_PATH+1] = L"";
  71. WCHAR szConnType[128];
  72. WCHAR szRemoteName[MAX_PATH + 1];
  73. szConnType[0] = 0;
  74. if ( pNetRes->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER )
  75. {
  76. // Need to extract the server name from full UNC path
  77. NwExtractServerName( pNetRes->lpRemoteName, szRemoteName );
  78. dwMessageId = IDS_MESSAGE_NOT_ATTACHED;
  79. }
  80. else // NDS container name
  81. {
  82. // Need to extract the tree name from the full UNC path
  83. szRemoteName[0] = TREECHAR;
  84. NwExtractTreeName( pNetRes->lpRemoteName, szRemoteName+1);
  85. dwMessageId = IDS_MESSAGE_NOT_ATTACHED_TO_TREE;
  86. }
  87. err = NwGetConnectionStatus( szRemoteName,
  88. &ResumeKey,
  89. &pBuffer,
  90. &EntriesRead );
  91. if ( err == NO_ERROR && EntriesRead > 0 )
  92. // For trees, we'll get more than one entry
  93. {
  94. PCONN_STATUS pConnStatus = (PCONN_STATUS) pBuffer;
  95. LPWSTR pszStart = szConnType;
  96. DWORD nSize = sizeof(szConnType)/sizeof(WCHAR);
  97. if ( EntriesRead > 1 && szRemoteName[0] == TREECHAR )
  98. {
  99. // If there is more than one entry for trees,
  100. // then we need to find one entry where username is not null
  101. // and the login type is NDS.
  102. // If we cannot find one, then just use the first one.
  103. DWORD i;
  104. PCONN_STATUS pConnStatusTmp = pConnStatus;
  105. PCONN_STATUS pConnStatusUser = NULL;
  106. PCONN_STATUS pConnStatusNoUser = NULL;
  107. for ( i = 0; i < EntriesRead ; i++ )
  108. {
  109. if ( pConnStatusTmp->fNds )
  110. {
  111. pConnStatusNoUser = pConnStatusTmp;
  112. if ( ( pConnStatusTmp->pszUserName != NULL )
  113. && ( ( pConnStatusTmp->dwConnType == NW_CONN_NDS_AUTHENTICATED_NO_LICENSE )
  114. || ( pConnStatusTmp->dwConnType == NW_CONN_NDS_AUTHENTICATED_LICENSED )
  115. )
  116. )
  117. {
  118. // Found it
  119. pConnStatusUser = pConnStatusTmp;
  120. break;
  121. }
  122. }
  123. // Continue with the next item
  124. pConnStatusTmp = (PCONN_STATUS) ( (DWORD_PTR) pConnStatusTmp
  125. + pConnStatusTmp->dwTotalLength);
  126. }
  127. if ( pConnStatusUser ) // found one nds entry with a user name
  128. pConnStatus = pConnStatusUser;
  129. else if ( pConnStatusNoUser ) // use an nds entry with no user name
  130. pConnStatus = pConnStatusNoUser;
  131. // else use the first entry
  132. }
  133. if ( szRemoteName[0] == TREECHAR // A tree
  134. || !pConnStatus->fPreferred // A server but not preferred
  135. )
  136. {
  137. // Show this conneciton only if this is a tree or if this is
  138. // not a implicit connection to the preferred server.
  139. dwMessageId = pNetRes->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER ?
  140. IDS_MESSAGE_ATTACHED : IDS_MESSAGE_ATTACHED_TO_TREE;
  141. if ( pConnStatus->pszUserName )
  142. {
  143. wcscpy( szUserName, pConnStatus->pszUserName );
  144. }
  145. if ( pConnStatus->fNds ) // NDS
  146. {
  147. LoadString( ::hmodNW, IDS_LOGIN_TYPE_NDS, pszStart, nSize );
  148. nSize -= wcslen( pszStart );
  149. pszStart += wcslen( pszStart);
  150. }
  151. else // Bindery
  152. {
  153. LoadString( ::hmodNW, IDS_LOGIN_TYPE_BINDERY, pszStart, nSize );
  154. nSize -= wcslen( pszStart );
  155. pszStart += wcslen( pszStart);
  156. }
  157. LoadString( ::hmodNW, IDS_LOGIN_STATUS_SEPARATOR, pszStart, nSize );
  158. nSize -= wcslen( pszStart );
  159. pszStart += wcslen( pszStart);
  160. GetConnectionStatusString( pConnStatus, (LPBYTE) pszStart, nSize );
  161. }
  162. }
  163. if ( err == NO_ERROR )
  164. {
  165. // Popup the message now.
  166. ::MsgBoxPrintf( hParent,
  167. dwMessageId,
  168. IDS_TITLE_WHOAMI,
  169. MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION,
  170. szRemoteName[0] == TREECHAR? szRemoteName + 1 : szRemoteName,
  171. szUserName,
  172. szConnType );
  173. }
  174. else // error occurred
  175. {
  176. ::MsgBoxErrorPrintf( hParent,
  177. IDS_MESSAGE_CONNINFO_ERROR,
  178. IDS_TITLE_WHOAMI,
  179. MB_OK | MB_SETFOREGROUND | MB_ICONSTOP,
  180. err,
  181. NULL );
  182. }
  183. if ( pBuffer != NULL )
  184. {
  185. LocalFree( pBuffer );
  186. pBuffer = NULL;
  187. }
  188. return NOERROR;
  189. }
  190. VOID
  191. GetConnectionStatusString(
  192. PCONN_STATUS pConnStatus,
  193. LPBYTE Buffer,
  194. DWORD nSize
  195. )
  196. {
  197. LPWSTR pszStart = (LPWSTR) Buffer;
  198. DWORD dwMessageId = 0;
  199. if ( pConnStatus->fNds ) // NDS
  200. {
  201. if ( pConnStatus->dwConnType == NW_CONN_NOT_AUTHENTICATED )
  202. {
  203. dwMessageId = IDS_LOGIN_STATUS_NOT_AUTHENTICATED;
  204. }
  205. else if ( pConnStatus->dwConnType == NW_CONN_DISCONNECTED )
  206. {
  207. dwMessageId = IDS_LOGIN_STATUS_NOT_ATTACHED;
  208. }
  209. else // authenticated, licensed or unlicensed
  210. {
  211. LoadString( ::hmodNW, IDS_LOGIN_STATUS_AUTHENTICATED,
  212. pszStart, nSize );
  213. nSize -= wcslen( pszStart );
  214. pszStart += wcslen( pszStart);
  215. if ( pConnStatus->dwConnType == NW_CONN_NDS_AUTHENTICATED_LICENSED )
  216. dwMessageId = IDS_LOGIN_STATUS_LICENSED;
  217. else // NW_CONN_NDS_AUTHENTICATED_NO_LICENSE
  218. dwMessageId = IDS_LOGIN_STATUS_NOT_LICENSED;
  219. }
  220. }
  221. else // Bindery
  222. {
  223. if ( pConnStatus->dwConnType == NW_CONN_BINDERY_LOGIN )
  224. dwMessageId = IDS_LOGIN_STATUS_LOGGED_IN;
  225. else if ( pConnStatus->dwConnType == NW_CONN_DISCONNECTED )
  226. dwMessageId = IDS_LOGIN_STATUS_NOT_ATTACHED;
  227. else
  228. dwMessageId = IDS_LOGIN_STATUS_ATTACHED_ONLY;
  229. }
  230. LoadString( ::hmodNW, dwMessageId, pszStart, nSize );
  231. }
  232. HRESULT
  233. NWUIGlobalWhoAmI(
  234. HWND hParent
  235. )
  236. {
  237. ::DialogBoxParam( ::hmodNW,
  238. MAKEINTRESOURCE(DLG_GLOBAL_WHOAMI),
  239. hParent,
  240. ::GlobalWhoAmIDlgProc,
  241. NULL );
  242. return NOERROR;
  243. }
  244. HRESULT
  245. NWUILogOut(
  246. HWND hParent,
  247. LPNETRESOURCE pNetRes,
  248. PBOOL pfDisconnected
  249. )
  250. {
  251. DWORD err = NO_ERROR;
  252. WCHAR szServer[MAX_PATH+1];
  253. BOOL fAttached;
  254. BOOL fAuthenticated;
  255. DWORD dwMessageId;
  256. *pfDisconnected = FALSE;
  257. // Need to extract the server name from full UNC path
  258. NwExtractServerName( pNetRes->lpRemoteName, szServer );
  259. err = NwIsServerOrTreeAttached( szServer, &fAttached, &fAuthenticated );
  260. if ( err == NO_ERROR && !fAttached )
  261. {
  262. dwMessageId = IDS_MESSAGE_NOT_ATTACHED;
  263. }
  264. else if ( err == NO_ERROR ) // attached
  265. {
  266. int nRet = ::MsgBoxPrintf( hParent,
  267. IDS_MESSAGE_LOGOUT_CONFIRM,
  268. IDS_TITLE_LOGOUT,
  269. MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION);
  270. if ( nRet != IDYES )
  271. return NOERROR;
  272. err = LogoutFromServer( szServer, pfDisconnected );
  273. if ( err == NO_ERROR )
  274. dwMessageId = IDS_MESSAGE_DETACHED;
  275. else
  276. dwMessageId = IDS_MESSAGE_LOGOUT_FAILED;
  277. }
  278. else // error occurred
  279. {
  280. ::MsgBoxErrorPrintf( hParent,
  281. IDS_MESSAGE_CONNINFO_ERROR,
  282. IDS_TITLE_LOGOUT,
  283. MB_OK | MB_SETFOREGROUND | MB_ICONSTOP,
  284. err,
  285. NULL );
  286. return NOERROR;
  287. }
  288. ::MsgBoxPrintf( hParent,
  289. dwMessageId,
  290. IDS_TITLE_LOGOUT,
  291. MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION );
  292. return NOERROR;
  293. }
  294. DWORD
  295. LogoutFromServer(
  296. LPWSTR pszServer,
  297. PBOOL pfDisconnected
  298. )
  299. {
  300. DWORD err = NO_ERROR;
  301. HANDLE EnumHandle = (HANDLE) NULL;
  302. LPNETRESOURCE NetR = NULL;
  303. LPNETRESOURCEW SavePtr;
  304. DWORD BytesNeeded = MAX_ONE_NETRES_SIZE;
  305. DWORD EntriesRead = 0;
  306. DWORD i;
  307. *pfDisconnected = FALSE;
  308. err = NPOpenEnum( RESOURCE_CONNECTED,
  309. 0,
  310. 0,
  311. NULL,
  312. &EnumHandle );
  313. if ( err != NO_ERROR)
  314. {
  315. EnumHandle = (HANDLE) NULL;
  316. goto CleanExit;
  317. }
  318. //
  319. // Allocate buffer to get server list.
  320. //
  321. if ((NetR = (LPNETRESOURCE) LocalAlloc( 0, BytesNeeded )) == NULL)
  322. {
  323. err = ERROR_NOT_ENOUGH_MEMORY;
  324. goto CleanExit;
  325. }
  326. do {
  327. EntriesRead = 0xFFFFFFFF; // Read as many as possible
  328. err = NwEnumConnections( EnumHandle,
  329. &EntriesRead,
  330. (LPVOID) NetR,
  331. &BytesNeeded,
  332. TRUE );
  333. if ( err == WN_SUCCESS)
  334. {
  335. SavePtr = NetR;
  336. for (i = 0; i < EntriesRead; i++, NetR++)
  337. {
  338. BYTE Buffer[MAX_ONE_CONN_INFORMATION_SIZE];
  339. BOOL fImplicit;
  340. LPWSTR pszCurrentServer;
  341. fImplicit = FALSE;
  342. if ( NwIsNdsSyntax( NetR->lpRemoteName))
  343. {
  344. // For Nds name, the server name might not be in the full UNC name.
  345. // Hence we need to get the server name from the Rdr.
  346. DWORD err1 = NwGetConnectionInformation(
  347. NetR->lpLocalName? NetR->lpLocalName : NetR->lpRemoteName,
  348. Buffer,
  349. sizeof(Buffer));
  350. if ( err1 != NO_ERROR )
  351. continue; // continue with the next entry if error occurred
  352. pszCurrentServer = ((PCONN_INFORMATION) Buffer)->HostServer;
  353. // Need to NULL terminate the server name, this will probably used the space
  354. // occupied by UserName but since we are not using it, it is probably ok.
  355. LPWSTR pszTemp = (LPWSTR) ((DWORD_PTR) pszCurrentServer
  356. + ((PCONN_INFORMATION) Buffer)->HostServerLength );
  357. *pszTemp = 0;
  358. }
  359. else // in the form \\server\sys
  360. {
  361. LPWSTR pszTemp;
  362. wcscpy( (LPWSTR) Buffer, NetR->lpRemoteName + 2 ); // go past two backslashes
  363. if ( pszTemp = wcschr( (LPWSTR) Buffer, L'\\' ))
  364. *pszTemp = 0;
  365. else
  366. {
  367. // The remote name contains only \\server, hence if the local name
  368. // is null, this is a implicit connection
  369. if ( NetR->lpLocalName == NULL )
  370. fImplicit = TRUE;
  371. }
  372. pszCurrentServer = (LPWSTR) Buffer;
  373. }
  374. if ( _wcsicmp( pszCurrentServer, pszServer ) == 0 )
  375. {
  376. do {
  377. // for implicit connections, we need to try and disconnect until
  378. // we deleted all the implicit connections, i.e. until we
  379. // get the invalid handle error
  380. // NOTE: If we don't pass in CONNECT_UPDATE_PROFILE, shell won't update
  381. // the windows that got disconnected. What do we want to do here?
  382. err = WNetCancelConnection2(
  383. NetR->lpLocalName? NetR->lpLocalName : NetR->lpRemoteName,
  384. 0, // CONNECT_UPDATE_PROFILE,
  385. TRUE );
  386. if ( err == NO_ERROR )
  387. *pfDisconnected = TRUE;
  388. } while ( fImplicit && ( err == NO_ERROR));
  389. if ( err == ERROR_INVALID_HANDLE )
  390. {
  391. // implicit connection will sometimes return this if the explicit connection
  392. // is already disconnected
  393. err = NO_ERROR;
  394. }
  395. if ( err != NO_ERROR )
  396. {
  397. NetR = SavePtr;
  398. goto CleanExit;
  399. }
  400. }
  401. }
  402. NetR = SavePtr;
  403. }
  404. else if ( err != WN_NO_MORE_ENTRIES)
  405. {
  406. if ( err == WN_MORE_DATA)
  407. {
  408. //
  409. // Original buffer was too small. Free it and allocate
  410. // the recommended size and then some to get as many
  411. // entries as possible.
  412. //
  413. (void) LocalFree((HLOCAL) NetR);
  414. BytesNeeded += NW_ENUM_EXTRA_BYTES;
  415. if ((NetR = (LPNETRESOURCE) LocalAlloc( 0, BytesNeeded )) == NULL)
  416. {
  417. err = ERROR_NOT_ENOUGH_MEMORY;
  418. goto CleanExit;
  419. }
  420. }
  421. else
  422. {
  423. goto CleanExit;
  424. }
  425. }
  426. } while (err != WN_NO_MORE_ENTRIES);
  427. if ( err == WN_NO_MORE_ENTRIES)
  428. err = NO_ERROR;
  429. CleanExit:
  430. if (EnumHandle != (HANDLE) NULL)
  431. (void) NPCloseEnum( EnumHandle);
  432. if (NetR != NULL)
  433. {
  434. (void) LocalFree( (HLOCAL) NetR);
  435. NetR = NULL;
  436. }
  437. return err;
  438. }
  439. HRESULT
  440. NWUIAttachAs(
  441. HWND hParent,
  442. LPNETRESOURCE pNetRes
  443. )
  444. {
  445. DWORD err = NO_ERROR;
  446. WCHAR szServerName[MAX_PATH+1];
  447. BOOL fAttached;
  448. BOOL fAuthenticated;
  449. // First, see if we are attached to the server.
  450. // Note, Attach as menu will be disabled on the NDS servers that we are already logged into.
  451. // Need to extract the server name from full UNC path
  452. szServerName[0] = szServerName[1] = L'\\';
  453. NwExtractServerName( pNetRes->lpRemoteName, szServerName + 2 );
  454. err = NwIsServerOrTreeAttached( szServerName + 2, &fAttached, &fAuthenticated );
  455. if ( err == NO_ERROR && fAttached && fAuthenticated )
  456. {
  457. // Already attached and authenticated to the server.
  458. // So, ask the user if he wants to log out first.
  459. int nRet = ::MsgBoxPrintf( hParent,
  460. IDS_MESSAGE_LOGOUT_QUESTION,
  461. IDS_TITLE_LOGOUT,
  462. MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION );
  463. if ( nRet != IDYES )
  464. return NOERROR;
  465. BOOL fDisconnected = FALSE; // can be used to refresh the shell if needed
  466. err = LogoutFromServer( szServerName + 2, &fDisconnected );
  467. if ( err != NO_ERROR )
  468. {
  469. ::MsgBoxPrintf( hParent,
  470. IDS_MESSAGE_LOGOUT_FAILED,
  471. IDS_TITLE_LOGOUT,
  472. MB_OK | MB_SETFOREGROUND | MB_ICONSTOP );
  473. return NOERROR;
  474. }
  475. }
  476. // If error occurred, just assume we are not attached to the server and continue on
  477. // to login to the server.
  478. DWORD dwConnFlags = CONNECT_INTERACTIVE | CONNECT_PROMPT;
  479. // See if the server is in the default context tree.
  480. // If yes, then we don't need to prompt the password first before connecting
  481. // in WNetAddConnection3.
  482. BOOL fInDefaultTree = FALSE;
  483. err = NwIsServerInDefaultTree( pNetRes->lpRemoteName, &fInDefaultTree );
  484. if ( (err == NO_ERROR ) && fInDefaultTree )
  485. dwConnFlags = CONNECT_INTERACTIVE;
  486. //
  487. // Now call WNetAddConnection3
  488. //
  489. // NOTE: net use \\mars_srv0 will succeed
  490. // but net use \\marsdev\cn=mars_srv0... will failed
  491. // Hence, just use the server name to connect.
  492. LPWSTR pszSave = pNetRes->lpRemoteName;
  493. pNetRes->lpRemoteName = szServerName;
  494. err = WNetAddConnection3( hParent,
  495. pNetRes,
  496. NULL,
  497. NULL,
  498. dwConnFlags );
  499. if ( err != WN_SUCCESS && err != WN_CANCEL )
  500. {
  501. ::MsgBoxErrorPrintf( hParent,
  502. IDS_MESSAGE_ADDCONN_ERROR,
  503. IDS_NETWARE_TITLE,
  504. MB_OK | MB_SETFOREGROUND | MB_ICONSTOP,
  505. err,
  506. pNetRes->lpRemoteName );
  507. }
  508. pNetRes->lpRemoteName = pszSave; // restore the original remote name just in case
  509. return NOERROR;
  510. }
  511. #if 0
  512. HRESULT
  513. NWUISetDefaultContext(
  514. HWND hParent,
  515. LPNETRESOURCE pNetRes
  516. )
  517. {
  518. DWORD dwPrintOptions;
  519. LPWSTR pszCurrentContext = NULL;
  520. WCHAR szNewContext[MAX_PATH+1];
  521. DWORD err = NO_ERROR;
  522. HANDLE handleRdr = NULL;
  523. UNICODE_STRING uTree;
  524. UNICODE_STRING uContext;
  525. LPWSTR pszContext = NULL;
  526. // Open a handle to the redirector
  527. err = RtlNtStatusToDosError( ::NwNdsOpenRdrHandle( &handleRdr ));
  528. if ( err != NO_ERROR )
  529. goto CleanExit;
  530. // Get the print option so that we can use it later
  531. err = ::NwQueryInfo( &dwPrintOptions, &pszCurrentContext );
  532. if ( err != NO_ERROR )
  533. goto CleanExit;
  534. wcscpy( szNewContext, pNetRes->lpRemoteName + 1 ); // get past 1st '\\'
  535. szNewContext[0] = TREECHAR; // in the format "*TREE\CONTEXT"
  536. if ( (pszContext = wcschr( szNewContext, L'\\' )) != NULL )
  537. {
  538. *pszContext = 0;
  539. RtlInitUnicodeString( &uContext, pszContext + 1 );
  540. }
  541. else
  542. RtlInitUnicodeString( &uContext, L"");
  543. RtlInitUnicodeString( &uTree, szNewContext+1 );
  544. if ( (err = RtlNtStatusToDosError( ::NwNdsSetTreeContext( handleRdr, &uTree, &uContext)))
  545. == NO_ERROR )
  546. {
  547. *pszContext = L'\\';
  548. if ((err = ::NwSetInfoInRegistry( dwPrintOptions, szNewContext )) == NO_ERROR )
  549. {
  550. ::MsgBoxPrintf( hParent,
  551. IDS_MESSAGE_CONTEXT_CHANGED,
  552. IDS_NETWARE_TITLE,
  553. MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION,
  554. pszCurrentContext
  555. ? ( *pszCurrentContext == TREECHAR
  556. ? pszCurrentContext + 1
  557. : pszCurrentContext )
  558. : L"",
  559. szNewContext+1 );
  560. }
  561. }
  562. CleanExit:
  563. if ( err != NO_ERROR )
  564. {
  565. ::MsgBoxErrorPrintf( hParent,
  566. IDS_MESSAGE_CONTEXT_ERROR,
  567. IDS_NETWARE_TITLE,
  568. MB_OK | MB_SETFOREGROUND | MB_ICONSTOP,
  569. err,
  570. szNewContext+1);
  571. }
  572. if ( pszCurrentContext != NULL )
  573. {
  574. LocalFree( pszCurrentContext );
  575. pszCurrentContext = NULL;
  576. }
  577. if ( handleRdr != NULL )
  578. {
  579. ::NtClose( handleRdr );
  580. handleRdr = NULL;
  581. }
  582. return NOERROR;
  583. }
  584. #endif
  585. HRESULT
  586. NWUIMapNetworkDrive(
  587. HWND hParent,
  588. LPNETRESOURCE pNetRes
  589. )
  590. {
  591. HRESULT hres;
  592. CONNECTDLGSTRUCT cds;
  593. cds.cbStructure = sizeof(cds);
  594. cds.hwndOwner = hParent;
  595. cds.lpConnRes = pNetRes;
  596. cds.dwFlags = CONNDLG_RO_PATH;
  597. if ( (( hres = WNetConnectionDialog1( &cds )) == WN_SUCCESS )
  598. && ( g_pFuncSHChangeNotify )
  599. )
  600. {
  601. WCHAR szPath[4];
  602. szPath[0] = ((USHORT) cds.dwDevNum) - 1 + L'A';
  603. szPath[1] = L':';
  604. szPath[2] = L'\\';
  605. szPath[3] = 0;
  606. // Notify shell about added redirection
  607. (*g_pFuncSHChangeNotify)( SHCNE_DRIVEADD,
  608. SHCNF_FLUSH | SHCNF_PATH | SHCNF_FLUSHNOWAIT,
  609. szPath,
  610. NULL );
  611. Sleep(1000); // short delay to make sure Shell has updated drive table
  612. // And we need to open shell window on this path
  613. if (g_pFuncSHExecuteEx)
  614. {
  615. SHELLEXECUTEINFO ExecInfo;
  616. ::memset(&ExecInfo,0,sizeof(ExecInfo));
  617. ExecInfo.hwnd = hParent;
  618. ExecInfo.lpVerb = 0;
  619. ExecInfo.lpFile = szPath;
  620. ExecInfo.lpParameters = NULL;
  621. ExecInfo.lpDirectory = NULL;
  622. ExecInfo.nShow = SW_NORMAL | SW_SHOW;
  623. ExecInfo.fMask = SEE_MASK_CLASSNAME;
  624. ExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
  625. ExecInfo.lpClass = (LPWSTR) L"Folder";
  626. ExecInfo.hkeyClass = NULL;
  627. (*g_pFuncSHExecuteEx)(&ExecInfo);
  628. }
  629. }
  630. return hres;
  631. }
  632. #define LB_PCT_NAME 25
  633. #define LB_PCT_TYPE 11
  634. #define LB_PCT_CONN 11
  635. #define LB_PCT_USER 25
  636. #define LB_PCT_STATUS 27
  637. #define BITMAP_WIDTH 16
  638. #define BITMAP_HEIGHT 16
  639. #define MAPCOLOR RGB(0, 255, 0)
  640. static UINT uiNDSIconIndex = 0;
  641. static UINT uiServerIconIndex = 0;
  642. /*
  643. * FillConnectionsListView
  644. * -----------------------
  645. *
  646. * Fill list box with information on active connections
  647. */
  648. VOID
  649. FillConnectionsListView(
  650. HWND hwndDlg
  651. )
  652. {
  653. HWND hwndLV = ::GetDlgItem(hwndDlg,IDD_GLOBAL_SERVERLIST);
  654. LV_ITEM lvI;
  655. WCHAR szSubItemText[MAX_PATH+1];
  656. UINT uiInsertedIndex;
  657. DWORD_PTR ResumeKey = 0;
  658. LPBYTE pConnBuffer = NULL;
  659. DWORD EntriesRead = 0;
  660. DWORD err = NO_ERROR;
  661. // Prepare ListView structure
  662. lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
  663. lvI.state = 0;
  664. lvI.stateMask = 0;
  665. do {
  666. if ( pConnBuffer != NULL )
  667. {
  668. LocalFree( pConnBuffer );
  669. pConnBuffer = NULL;
  670. }
  671. err = NwGetConnectionStatus( NULL,
  672. &ResumeKey,
  673. &pConnBuffer,
  674. &EntriesRead );
  675. if ( ( err != NO_ERROR )
  676. || ( EntriesRead == 0 )
  677. )
  678. {
  679. goto CleanExit;
  680. }
  681. PCONN_STATUS pConnStatus = (PCONN_STATUS) pConnBuffer;
  682. for ( DWORD i = 0; i < EntriesRead; i++)
  683. {
  684. // Allocate and initialize new item structure for use in the listbox
  685. DWORD dwSize;
  686. //
  687. // Don't need to show preferred server with only implicit
  688. // connections since we can't disconnect from it.
  689. //
  690. if ( pConnStatus->fPreferred )
  691. {
  692. // Continue with the next item
  693. pConnStatus = (PCONN_STATUS) ( (DWORD_PTR) pConnStatus
  694. + pConnStatus->dwTotalLength);
  695. continue;
  696. }
  697. //
  698. // Allocate and copy the connection information to be store with
  699. // the listbox
  700. //
  701. PCONN_STATUS pConnStatusKeep =
  702. (PCONN_STATUS) LocalAlloc( LMEM_ZEROINIT, pConnStatus->dwTotalLength );
  703. if ( pConnStatusKeep == NULL )
  704. {
  705. err = ERROR_NOT_ENOUGH_MEMORY;
  706. goto CleanExit;
  707. }
  708. memcpy( pConnStatusKeep, pConnStatus, pConnStatus->dwTotalLength );
  709. dwSize = sizeof(CONN_STATUS);
  710. if ( pConnStatus->pszServerName )
  711. {
  712. pConnStatusKeep->pszServerName =
  713. (LPWSTR) ((DWORD_PTR)pConnStatusKeep + dwSize );
  714. NwMakePrettyDisplayName( pConnStatusKeep->pszServerName );
  715. dwSize += (wcslen(pConnStatus->pszServerName)+1)*sizeof(WCHAR);
  716. }
  717. if ( pConnStatus->pszUserName )
  718. {
  719. pConnStatusKeep->pszUserName =
  720. (LPWSTR) ((DWORD_PTR)pConnStatusKeep + dwSize );
  721. dwSize += (wcslen(pConnStatus->pszUserName)+1) * sizeof(WCHAR);
  722. NwAbbreviateUserName( pConnStatus->pszUserName,
  723. pConnStatusKeep->pszUserName );
  724. NwMakePrettyDisplayName( pConnStatusKeep->pszUserName );
  725. }
  726. if ( pConnStatus->pszTreeName )
  727. {
  728. pConnStatusKeep->pszTreeName =
  729. (LPWSTR) ((DWORD_PTR)pConnStatusKeep + dwSize );
  730. }
  731. //
  732. // Construct the item to add to the listbox
  733. //
  734. lvI.iItem = i;
  735. lvI.iSubItem = 0;
  736. lvI.pszText = szSubItemText;
  737. lvI.cchTextMax = sizeof(szSubItemText);
  738. // Select proper icon
  739. lvI.iImage = pConnStatusKeep->fNds? uiNDSIconIndex
  740. : uiServerIconIndex;
  741. lvI.lParam = (LPARAM) pConnStatusKeep;
  742. wcscpy( szSubItemText, pConnStatusKeep->pszServerName );
  743. // Insert the item
  744. uiInsertedIndex = ListView_InsertItem( hwndLV, &lvI);
  745. if ( uiInsertedIndex != -1 )
  746. {
  747. // Added item itself - now for specific columns
  748. // First, add the column indicating bindery or nds connection
  749. if ( pConnStatusKeep->fNds )
  750. {
  751. LoadString( ::hmodNW, IDS_LOGIN_TYPE_NDS, szSubItemText,
  752. sizeof(szSubItemText)/sizeof(szSubItemText[0]));
  753. }
  754. else
  755. {
  756. LoadString( ::hmodNW, IDS_LOGIN_TYPE_BINDERY, szSubItemText,
  757. sizeof(szSubItemText)/sizeof(szSubItemText[0]));
  758. }
  759. ListView_SetItemText( hwndLV,
  760. uiInsertedIndex,
  761. 1, // SubItem id
  762. szSubItemText );
  763. // Next, Add the column indicating the connection number
  764. if ( ( pConnStatusKeep->pszServerName[0] != TREECHAR )
  765. && ( pConnStatusKeep->dwConnType != NW_CONN_DISCONNECTED )
  766. )
  767. {
  768. // Add connection number only if it is a connection
  769. // to a server and not a tree.
  770. // A connection number only makes sense when not disconnected
  771. ::wsprintf(szSubItemText,L"%4d",pConnStatusKeep->nConnNum );
  772. ListView_SetItemText( hwndLV,
  773. uiInsertedIndex,
  774. 2, // SubItem id
  775. szSubItemText );
  776. }
  777. // Then, add the column indicating the user name
  778. *szSubItemText = L'\0';
  779. if ( pConnStatusKeep->pszUserName )
  780. {
  781. wcscpy( szSubItemText, pConnStatusKeep->pszUserName );
  782. ListView_SetItemText( hwndLV,
  783. uiInsertedIndex,
  784. 3, // SubItem id
  785. szSubItemText );
  786. }
  787. // Last of all, add the column indicating the connection status
  788. *szSubItemText = L'\0';
  789. GetConnectionStatusString( pConnStatusKeep,
  790. (LPBYTE) szSubItemText,
  791. sizeof(szSubItemText)/sizeof(szSubItemText[0]));
  792. ListView_SetItemText( hwndLV,
  793. uiInsertedIndex,
  794. 4, // SubItem id
  795. szSubItemText );
  796. }
  797. else
  798. {
  799. // Failed inserting item in the list,
  800. // need to delete the allocated CONN_STATUS
  801. ASSERT( FALSE );
  802. LocalFree( pConnStatusKeep );
  803. pConnStatusKeep = NULL;
  804. }
  805. // Continue with the next item
  806. pConnStatus = (PCONN_STATUS) ( (DWORD_PTR) pConnStatus
  807. + pConnStatus->dwTotalLength);
  808. }
  809. } while ( ResumeKey != 0 );
  810. CleanExit:
  811. if ( pConnBuffer != NULL )
  812. {
  813. LocalFree( pConnBuffer );
  814. pConnBuffer = NULL;
  815. }
  816. if ( err != NO_ERROR )
  817. {
  818. // If error occurred, we will end the dialog
  819. ::MsgBoxErrorPrintf( hwndDlg,
  820. IDS_MESSAGE_CONNINFO_ERROR,
  821. IDS_NETWARE_TITLE,
  822. MB_OK | MB_SETFOREGROUND | MB_ICONSTOP,
  823. err,
  824. NULL );
  825. ::EndDialog( hwndDlg, FALSE);
  826. }
  827. }
  828. /*
  829. * CreateConnectionsListView
  830. * -------------------------
  831. *
  832. * Initialize the column headers of the list box
  833. */
  834. VOID
  835. CreateConnectionsListView(
  836. HWND hwndDlg
  837. )
  838. {
  839. HWND hwndLV;
  840. HIMAGELIST hSmall;
  841. UINT uiLBoxWidth;
  842. InitCommonControls();
  843. // Get the handle of the listbox
  844. hwndLV = ::GetDlgItem(hwndDlg,IDD_GLOBAL_SERVERLIST);
  845. RECT rc;
  846. ::GetWindowRect( ::GetDlgItem( hwndDlg, IDD_GLOBAL_SERVERLIST ), &rc );
  847. uiLBoxWidth = rc.right - rc.left;
  848. // Load image list
  849. hSmall = ::ImageList_Create(BITMAP_WIDTH,BITMAP_HEIGHT,ILC_MASK,4,0);
  850. // Load bitmap of the tree/server icon
  851. HBITMAP hbm;
  852. hbm = ::LoadBitmap(::hmodNW,MAKEINTRESOURCE(IDB_TREE_ICON));
  853. if ((uiNDSIconIndex = ImageList_AddMasked(hSmall,hbm,MAPCOLOR)) == -1) {
  854. ASSERT(FALSE);
  855. }
  856. hbm = ::LoadBitmap(::hmodNW,MAKEINTRESOURCE(IDB_SERVER_ICON));
  857. if ((uiServerIconIndex = ImageList_AddMasked(hSmall,hbm,MAPCOLOR)) == -1) {
  858. ASSERT(FALSE);
  859. }
  860. ImageList_SetBkColor(hSmall, CLR_NONE);
  861. // Associate image list with list view control
  862. ListView_SetImageList(hwndLV,hSmall,LVSIL_SMALL);
  863. // Initialize columns in header
  864. LV_COLUMN lvC;
  865. UINT uiColumnIndex = 0;
  866. WCHAR szColumnName[128];
  867. lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  868. lvC.fmt = LVCFMT_LEFT;
  869. lvC.cx = (uiLBoxWidth*LB_PCT_NAME)/100;
  870. lvC.pszText = szColumnName;
  871. // Add the column header representing the server name
  872. *szColumnName = L'\0';
  873. ::LoadString( ::hmodNW,
  874. IDS_COLUMN_NAME,
  875. szColumnName,
  876. sizeof(szColumnName)/sizeof(szColumnName[0]));
  877. if ( ListView_InsertColumn(hwndLV,uiColumnIndex++,&lvC) == -1) {
  878. ASSERT(FALSE);
  879. }
  880. // Add the column header representing the conneciton type
  881. *szColumnName = L'\0';
  882. lvC.cx = (uiLBoxWidth*LB_PCT_TYPE)/100;
  883. ::LoadString( ::hmodNW,
  884. IDS_COLUMN_CONN_TYPE,
  885. szColumnName,
  886. sizeof(szColumnName)/sizeof(szColumnName[0]));
  887. if ( ListView_InsertColumn(hwndLV,uiColumnIndex++,&lvC) == -1) {
  888. ASSERT(FALSE);
  889. }
  890. // Add the column header representing the connection number
  891. *szColumnName = L'\0';
  892. lvC.cx = (uiLBoxWidth*LB_PCT_CONN)/100;
  893. lvC.fmt = LVCFMT_RIGHT;
  894. ::LoadString( ::hmodNW,
  895. IDS_COLUMN_CONN_NUMBER,
  896. szColumnName,
  897. sizeof(szColumnName)/sizeof(szColumnName[0]));
  898. if ( ListView_InsertColumn(hwndLV,uiColumnIndex++,&lvC) == -1) {
  899. ASSERT(FALSE);
  900. }
  901. // Add the column header representing the name of the user
  902. *szColumnName = L'\0';
  903. lvC.cx = (uiLBoxWidth*LB_PCT_USER)/100;
  904. lvC.fmt = LVCFMT_LEFT;
  905. ::LoadString( ::hmodNW,
  906. IDS_COLUMN_USER,
  907. szColumnName,
  908. sizeof(szColumnName)/sizeof(szColumnName[0]));
  909. if ( ListView_InsertColumn(hwndLV,uiColumnIndex++,&lvC) == -1) {
  910. ASSERT(FALSE);
  911. }
  912. // Add the column header representing the status of the connection
  913. *szColumnName = L'\0';
  914. lvC.cx = (uiLBoxWidth*LB_PCT_STATUS)/100;
  915. lvC.fmt = LVCFMT_LEFT;
  916. ::LoadString( ::hmodNW,
  917. IDS_COLUMN_STATUS,
  918. szColumnName,
  919. sizeof(szColumnName)/sizeof(szColumnName[0]));
  920. if ( ListView_InsertColumn(hwndLV,uiColumnIndex++,&lvC) == -1) {
  921. ASSERT(FALSE);
  922. }
  923. // Now fill list view window with connection information
  924. FillConnectionsListView( hwndDlg );
  925. } /* endproc CreateConnectionsListView */
  926. /*
  927. * GlobalWhoAmI_ListViewCompareProc
  928. * --------------------------------
  929. *
  930. */
  931. LRESULT CALLBACK
  932. GlobalWhoAmI_ListViewCompareProc(
  933. LPARAM lParam1,
  934. LPARAM lParam2,
  935. LPARAM lParamSort
  936. )
  937. {
  938. PCONN_STATUS pConnItem1 = (PCONN_STATUS)lParam1;
  939. PCONN_STATUS pConnItem2 = (PCONN_STATUS)lParam2;
  940. int iResult = 0;
  941. if ( pConnItem1 && pConnItem2 )
  942. {
  943. switch(lParamSort)
  944. {
  945. case 0:
  946. iResult = ::_wcsicmp( pConnItem1->pszServerName,
  947. pConnItem2->pszServerName);
  948. break;
  949. case 1:
  950. iResult = pConnItem1->fNds - pConnItem2->fNds;
  951. break;
  952. case 2:
  953. iResult = pConnItem1->nConnNum - pConnItem2->nConnNum;
  954. break;
  955. case 3:
  956. {
  957. // pszUserName might be NULL, so we need to be careful when
  958. // comparing them.
  959. if ( pConnItem1->pszUserName )
  960. {
  961. if ( pConnItem2->pszUserName )
  962. {
  963. iResult = ::_wcsicmp( pConnItem1->pszUserName,
  964. pConnItem2->pszUserName);
  965. }
  966. else
  967. {
  968. iResult = 1;
  969. }
  970. }
  971. else
  972. {
  973. iResult = -1;
  974. }
  975. break;
  976. }
  977. case 4:
  978. iResult = pConnItem1->dwConnType - pConnItem2->dwConnType;
  979. break;
  980. default:
  981. iResult = 0;
  982. break;
  983. }
  984. }
  985. return (iResult);
  986. }
  987. LRESULT
  988. NotifyHandler(
  989. HWND hwndDlg,
  990. UINT uMsg,
  991. WPARAM wParam,
  992. LPARAM lParam
  993. )
  994. {
  995. NM_LISTVIEW *lpNm = (NM_LISTVIEW *)lParam;
  996. NMHDR *lphdr = &lpNm->hdr;
  997. HWND hwndLV = ::GetDlgItem(hwndDlg,IDD_GLOBAL_SERVERLIST);
  998. switch(lphdr->code)
  999. {
  1000. case LVN_ITEMCHANGED:
  1001. // Check for change in item state, make sure item has received focus
  1002. if (lpNm->uChanged & LVIF_STATE)
  1003. {
  1004. UINT uiSelectedItems = 0;
  1005. uiSelectedItems = ListView_GetSelectedCount(hwndLV);
  1006. EnableWindow( GetDlgItem(hwndDlg, IDD_DETACH),
  1007. uiSelectedItems? TRUE : FALSE);
  1008. return TRUE;
  1009. }
  1010. break;
  1011. case LVN_COLUMNCLICK:
  1012. ListView_SortItems( hwndLV,
  1013. GlobalWhoAmI_ListViewCompareProc,
  1014. (LPARAM)(lpNm->iSubItem));
  1015. return TRUE; /* we processed a message */
  1016. case LVN_DELETEITEM:
  1017. // Free memory
  1018. LocalFree( (HLOCAL) lpNm->lParam );
  1019. lpNm->lParam = NULL;
  1020. break;
  1021. default:
  1022. break;
  1023. }
  1024. return FALSE;
  1025. }
  1026. BOOL
  1027. DetachResourceProc(
  1028. HWND hwndDlg
  1029. )
  1030. {
  1031. BOOL fDetached = FALSE;
  1032. LV_ITEM lvitem;
  1033. int index;
  1034. DWORD err;
  1035. HWND hwndLV = ::GetDlgItem( hwndDlg, IDD_GLOBAL_SERVERLIST);
  1036. index = -1; // Start at beginning of item list.
  1037. while ((index = ListView_GetNextItem(hwndLV, index, LVNI_SELECTED)) != -1)
  1038. {
  1039. lvitem.iItem = index;
  1040. lvitem.mask = LVIF_PARAM;
  1041. lvitem.iSubItem = 0;
  1042. if ( ListView_GetItem( hwndLV, &lvitem ))
  1043. {
  1044. PCONN_STATUS pConnStatus = (PCONN_STATUS) lvitem.lParam;
  1045. BOOL fDisconnected = FALSE; // Can be used to refresh
  1046. // the shell if needed
  1047. err = LogoutFromServer( pConnStatus->pszServerName,
  1048. &fDisconnected );
  1049. if ( err == NO_ERROR )
  1050. {
  1051. fDetached = TRUE;
  1052. }
  1053. else
  1054. {
  1055. NwMakePrettyDisplayName(pConnStatus->pszServerName);
  1056. ::MsgBoxPrintf( hwndDlg,
  1057. IDS_MESSAGE_LOGOUT_FROM_SERVER_FAILED,
  1058. IDS_TITLE_LOGOUT,
  1059. MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION,
  1060. pConnStatus->pszServerName );
  1061. }
  1062. }
  1063. }
  1064. return fDetached;
  1065. }
  1066. static DWORD aWhoAmIIds[] = { IDC_LOGOFRAME, NO_HELP,
  1067. IDD_GLOBAL_SERVERLIST_T,IDH_GLOBAL_SERVERLIST,
  1068. IDD_GLOBAL_SERVERLIST, IDH_GLOBAL_SERVERLIST,
  1069. IDD_DETACH, IDH_GLOBAL_DETACH,
  1070. IDD_GLOBAL_SVRLIST_DESC,IDH_GLOBAL_SERVERLIST,
  1071. 0, 0 };
  1072. /*
  1073. * GlobalWhoAmIDlgProc
  1074. * -------------------
  1075. *
  1076. * WhoAmI information for list of attached servers
  1077. */
  1078. INT_PTR
  1079. CALLBACK
  1080. GlobalWhoAmIDlgProc(
  1081. HWND hwndDlg,
  1082. UINT msg,
  1083. WPARAM wParam,
  1084. LPARAM lParam
  1085. )
  1086. {
  1087. switch (msg)
  1088. {
  1089. case WM_INITDIALOG:
  1090. {
  1091. LPWSTR pszCurrentContext = NULL;
  1092. DWORD dwPrintOptions;
  1093. // Get the current default tree or server name
  1094. DWORD err = ::NwQueryInfo( &dwPrintOptions, &pszCurrentContext );
  1095. if ( err == NO_ERROR )
  1096. {
  1097. LPWSTR pszName;
  1098. WCHAR szUserName[MAX_PATH+1] = L"";
  1099. WCHAR szNoName[2] = L"";
  1100. DWORD_PTR ResumeKey = 0;
  1101. LPBYTE pBuffer = NULL;
  1102. DWORD EntriesRead = 0;
  1103. DWORD dwMessageId;
  1104. UNICODE_STRING uContext;
  1105. WCHAR szContext[MAX_PATH+1];
  1106. szContext[0] = 0;
  1107. uContext.Buffer = szContext;
  1108. uContext.Length = uContext.MaximumLength
  1109. = sizeof(szContext)/sizeof(szContext[0]);
  1110. if ( pszCurrentContext )
  1111. {
  1112. pszName = pszCurrentContext;
  1113. }
  1114. else
  1115. {
  1116. pszName = szNoName;
  1117. }
  1118. if ( pszName[0] == TREECHAR )
  1119. {
  1120. // Get the tree name from the full name *TREE\CONTEXT
  1121. LPWSTR pszTemp;
  1122. if ( pszTemp = wcschr( pszName, L'\\' ))
  1123. *pszTemp = 0;
  1124. dwMessageId = IDS_MESSAGE_NOT_LOGGED_IN_TREE;
  1125. }
  1126. else
  1127. {
  1128. dwMessageId = IDS_MESSAGE_NOT_LOGGED_IN_SERVER;
  1129. }
  1130. if ( pszName[0] != 0 ) // there is preferred server/tree
  1131. {
  1132. err = NwGetConnectionStatus( pszName,
  1133. &ResumeKey,
  1134. &pBuffer,
  1135. &EntriesRead );
  1136. }
  1137. if ( err == NO_ERROR && EntriesRead > 0 )
  1138. // For trees, we'll get more than one entry
  1139. {
  1140. PCONN_STATUS pConnStatus = (PCONN_STATUS) pBuffer;
  1141. if ( EntriesRead > 1 && pszName[0] == TREECHAR )
  1142. {
  1143. // If there is more than one entry for trees,
  1144. // then we need to find one entry where username is not null.
  1145. // If we cannot find one, then just use the first one.
  1146. DWORD i;
  1147. PCONN_STATUS pConnStatusTmp = pConnStatus;
  1148. PCONN_STATUS pConnStatusUser = NULL;
  1149. PCONN_STATUS pConnStatusNoUser = NULL;
  1150. for ( i = 0; i < EntriesRead ; i++ )
  1151. {
  1152. if ( pConnStatusTmp->fNds )
  1153. {
  1154. pConnStatusNoUser = pConnStatusTmp;
  1155. if ( ( pConnStatusTmp->pszUserName != NULL )
  1156. && ( ( pConnStatusTmp->dwConnType
  1157. == NW_CONN_NDS_AUTHENTICATED_NO_LICENSE )
  1158. || ( pConnStatusTmp->dwConnType
  1159. == NW_CONN_NDS_AUTHENTICATED_LICENSED )
  1160. )
  1161. )
  1162. {
  1163. // Found it
  1164. pConnStatusUser = pConnStatusTmp;
  1165. break;
  1166. }
  1167. }
  1168. // Continue with the next item
  1169. pConnStatusTmp = (PCONN_STATUS)
  1170. ( (DWORD_PTR) pConnStatusTmp
  1171. + pConnStatusTmp->dwTotalLength);
  1172. }
  1173. if ( pConnStatusUser )
  1174. {
  1175. // found one nds entry with a user name
  1176. pConnStatus = pConnStatusUser;
  1177. }
  1178. else if ( pConnStatusNoUser )
  1179. {
  1180. // use an nds entry with no user name
  1181. pConnStatus = pConnStatusNoUser;
  1182. }
  1183. // else use the first entry
  1184. }
  1185. if ( ( pConnStatus->pszUserName )
  1186. && ( pConnStatus->pszUserName[0] != 0 )
  1187. )
  1188. {
  1189. NwAbbreviateUserName( pConnStatus->pszUserName,
  1190. szUserName);
  1191. NwMakePrettyDisplayName( szUserName );
  1192. if ( pszName[0] != TREECHAR )
  1193. {
  1194. dwMessageId = IDS_MESSAGE_LOGGED_IN_SERVER;
  1195. }
  1196. else
  1197. {
  1198. dwMessageId = IDS_MESSAGE_LOGGED_IN_TREE;
  1199. }
  1200. }
  1201. if ( pszName[0] == TREECHAR )
  1202. {
  1203. // For trees, we need to get the current context
  1204. // Open a handle to the redirector
  1205. HANDLE handleRdr = NULL;
  1206. err = RtlNtStatusToDosError(
  1207. ::NwNdsOpenRdrHandle( &handleRdr ));
  1208. if ( err == NO_ERROR )
  1209. {
  1210. UNICODE_STRING uTree;
  1211. RtlInitUnicodeString( &uTree, pszName+1 ); // get past '*'
  1212. // Get the current context in the default tree
  1213. err = RtlNtStatusToDosError(
  1214. ::NwNdsGetTreeContext( handleRdr,
  1215. &uTree,
  1216. &uContext));
  1217. }
  1218. if ( handleRdr != NULL )
  1219. ::NtClose( handleRdr );
  1220. }
  1221. }
  1222. if ( !err )
  1223. {
  1224. LPWSTR pszText = NULL;
  1225. err = ::LoadMsgPrintf( &pszText,
  1226. dwMessageId,
  1227. pszName[0] == TREECHAR?
  1228. pszName + 1 : pszName,
  1229. szUserName,
  1230. szContext );
  1231. if ( err == NO_ERROR )
  1232. {
  1233. ::SetDlgItemText( hwndDlg, IDD_GLOBAL_SERVERLIST_T,
  1234. pszText);
  1235. ::LocalFree( pszText );
  1236. }
  1237. }
  1238. if ( pBuffer != NULL )
  1239. {
  1240. LocalFree( pBuffer );
  1241. pBuffer = NULL;
  1242. }
  1243. }
  1244. if ( pszCurrentContext != NULL )
  1245. {
  1246. LocalFree( pszCurrentContext );
  1247. pszCurrentContext = NULL;
  1248. }
  1249. if ( err != NO_ERROR )
  1250. {
  1251. ::MsgBoxErrorPrintf( hwndDlg,
  1252. IDS_MESSAGE_CONNINFO_ERROR,
  1253. IDS_NETWARE_TITLE,
  1254. MB_OK | MB_SETFOREGROUND | MB_ICONSTOP,
  1255. err,
  1256. NULL );
  1257. ::EndDialog( hwndDlg, FALSE);
  1258. return TRUE;
  1259. }
  1260. // Fill listview control with connection parameters
  1261. CreateConnectionsListView(hwndDlg);
  1262. UnHideControl( hwndDlg, IDD_DETACH);
  1263. // List view fill defaults to no selected server, disable Detach.
  1264. EnableWindow( GetDlgItem( hwndDlg, IDD_DETACH), FALSE);
  1265. // Set up timer for automatic refresh interval
  1266. ::SetTimer( hwndDlg, 1, GLOBAL_WHOAMI_REFRESH_INTERVAL, NULL);
  1267. // Set focus to list box
  1268. ::SetFocus( ::GetDlgItem( hwndDlg, IDD_GLOBAL_SERVERLIST));
  1269. return FALSE; /* we set the focus */
  1270. }
  1271. case WM_DESTROY:
  1272. ::KillTimer( hwndDlg, 1);
  1273. break;
  1274. case WM_COMMAND:
  1275. switch (wParam)
  1276. {
  1277. case IDOK:
  1278. case IDCANCEL:
  1279. ::EndDialog( hwndDlg, FALSE);
  1280. return TRUE; /* we processed a message */
  1281. case IDD_DETACH:
  1282. // Attempt to detach server connection currently selected
  1283. if ( DetachResourceProc( hwndDlg ))
  1284. {
  1285. // If succeeded - refresh window
  1286. ::SendMessage(hwndDlg,WM_COMMAND,IDD_REFRESH,0L);
  1287. }
  1288. return TRUE; /* we processed a message */
  1289. case IDD_REFRESH:
  1290. {
  1291. // Refresh connection listbox
  1292. HWND hwndLV = ::GetDlgItem( hwndDlg, IDD_GLOBAL_SERVERLIST);
  1293. ::SetFocus( hwndLV );
  1294. // Clear list
  1295. ListView_DeleteAllItems( hwndLV );
  1296. // Now refill list view window
  1297. FillConnectionsListView( hwndDlg );
  1298. // List view refill unsets selected server focus, disable Detach.
  1299. EnableWindow( GetDlgItem( hwndDlg, IDD_DETACH ), FALSE );
  1300. return TRUE; /* we processed a message */
  1301. }
  1302. default:
  1303. break;
  1304. }
  1305. break;
  1306. case WM_NOTIFY:
  1307. // Handle notifications
  1308. if ( NotifyHandler( hwndDlg, msg, wParam, lParam))
  1309. return TRUE; /* we processed a message */
  1310. break;
  1311. case WM_TIMER:
  1312. ::SendMessage( hwndDlg, WM_COMMAND, IDD_REFRESH, 0L);
  1313. break;
  1314. case WM_HELP:
  1315. ::WinHelp( (HWND) ((LPHELPINFO)lParam)->hItemHandle,
  1316. NW_HELP_FILE,
  1317. HELP_WM_HELP,
  1318. (DWORD_PTR) (LPVOID) aWhoAmIIds );
  1319. return TRUE;
  1320. case WM_CONTEXTMENU:
  1321. ::WinHelp( (HWND) wParam,
  1322. NW_HELP_FILE,
  1323. HELP_CONTEXTMENU,
  1324. (DWORD_PTR) (LPVOID) aWhoAmIIds );
  1325. return TRUE;
  1326. }
  1327. return FALSE; /* we didn't process the message */
  1328. }