diff options
Diffstat (limited to '')
-rw-r--r-- | private/nw/svcdlls/nwwks/client/nwshui.cxx | 1630 |
1 files changed, 1630 insertions, 0 deletions
diff --git a/private/nw/svcdlls/nwwks/client/nwshui.cxx b/private/nw/svcdlls/nwwks/client/nwshui.cxx new file mode 100644 index 000000000..48dea8f96 --- /dev/null +++ b/private/nw/svcdlls/nwwks/client/nwshui.cxx @@ -0,0 +1,1630 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + nwshui.cxx + +Abstract: + + This module implements the context menu actions of shell extension classes. + +Author: + + Yi-Hsin Sung (yihsins) 25-Oct-1995 + +--*/ + +extern "C" +{ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +#include <commctrl.h> +#include <shellapi.h> +#include <shlobj.h> +#define DONT_WANT_SHELLDEBUG +#include <shsemip.h> +#include <winnetwk.h> +#include <npapi.h> +#include <ntddnwfs.h> +#include <ndsapi32.h> +#include <nwapi.h> +#include <nwwks.h> +#include <nwmisc.h> +#include "nwutil.h" +} + +#include "nwshcmn.h" +#include "nwshrc.h" + +extern "C" +{ +NTSTATUS +NwNdsOpenRdrHandle( + OUT PHANDLE phandleRdr ); +} + +#define MAX_ONE_CONN_INFORMATION_SIZE 512 +#define NW_ENUM_EXTRA_BYTES 256 +#define GLOBAL_WHOAMI_REFRESH_INTERVAL 30000 // in milliseconds, Win95 uses 10000 + +DWORD +LogoutFromServer( + LPWSTR pszServer, + PBOOL pfDisconnected +); + +BOOL +CALLBACK +GlobalWhoAmIDlgProc( + HWND hwndDlg, + UINT msg, + WPARAM wParam, + LPARAM lParam ); + +VOID +GetConnectionStatusString( + PCONN_STATUS pConnStatus, + LPBYTE Buffer, + DWORD nSize +); + +HRESULT +NWUIWhoAmI( + HWND hParent, + LPNETRESOURCE pNetRes +) +{ + DWORD err = NO_ERROR; + DWORD ResumeKey = 0; + LPBYTE pBuffer = NULL; + DWORD EntriesRead = 0; + DWORD dwMessageId; + WCHAR szUserName[MAX_PATH+1] = L""; + WCHAR szConnType[128]; + WCHAR szRemoteName[MAX_PATH + 1]; + + szConnType[0] = 0; + + if ( pNetRes->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER ) + { + // Need to extract the server name from full UNC path + NwExtractServerName( pNetRes->lpRemoteName, szRemoteName ); + dwMessageId = IDS_MESSAGE_NOT_ATTACHED; + } + else // NDS container name + { + // Need to extract the tree name from the full UNC path + szRemoteName[0] = TREECHAR; + NwExtractTreeName( pNetRes->lpRemoteName, szRemoteName+1); + dwMessageId = IDS_MESSAGE_NOT_ATTACHED_TO_TREE; + } + + err = NwGetConnectionStatus( szRemoteName, + &ResumeKey, + &pBuffer, + &EntriesRead ); + + if ( err == NO_ERROR && EntriesRead > 0 ) + // For trees, we'll get more than one entry + { + PCONN_STATUS pConnStatus = (PCONN_STATUS) pBuffer; + LPWSTR pszStart = szConnType; + DWORD nSize = sizeof(szConnType)/sizeof(WCHAR); + + if ( EntriesRead > 1 && szRemoteName[0] == TREECHAR ) + { + // If there is more than one entry for trees, + // then we need to find one entry where username is not null + // and the login type is NDS. + // If we cannot find one, then just use the first one. + + DWORD i; + PCONN_STATUS pConnStatusTmp = pConnStatus; + PCONN_STATUS pConnStatusUser = NULL; + PCONN_STATUS pConnStatusNoUser = NULL; + + for ( i = 0; i < EntriesRead ; i++ ) + { + if ( pConnStatusTmp->fNds ) + { + pConnStatusNoUser = pConnStatusTmp; + + if ( ( pConnStatusTmp->pszUserName != NULL ) + && ( ( pConnStatusTmp->dwConnType == NW_CONN_NDS_AUTHENTICATED_NO_LICENSE ) + || ( pConnStatusTmp->dwConnType == NW_CONN_NDS_AUTHENTICATED_LICENSED ) + ) + ) + { + // Found it + pConnStatusUser = pConnStatusTmp; + break; + } + } + + // Continue with the next item + pConnStatusTmp = (PCONN_STATUS) ( (DWORD) pConnStatusTmp + + pConnStatusTmp->dwTotalLength); + } + + if ( pConnStatusUser ) // found one nds entry with a user name + pConnStatus = pConnStatusUser; + else if ( pConnStatusNoUser ) // use an nds entry with no user name + pConnStatus = pConnStatusNoUser; + // else use the first entry + + } + + if ( szRemoteName[0] == TREECHAR // A tree + || !pConnStatus->fPreferred // A server but not preferred + ) + { + // Show this conneciton only if this is a tree or if this is + // not a implicit connection to the preferred server. + + dwMessageId = pNetRes->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER ? + IDS_MESSAGE_ATTACHED : IDS_MESSAGE_ATTACHED_TO_TREE; + + if ( pConnStatus->pszUserName ) + { + wcscpy( szUserName, pConnStatus->pszUserName ); + } + + if ( pConnStatus->fNds ) // NDS + { + LoadString( ::hmodNW, IDS_LOGIN_TYPE_NDS, pszStart, nSize ); + nSize -= wcslen( pszStart ); + pszStart += wcslen( pszStart); + + } + else // Bindery + { + LoadString( ::hmodNW, IDS_LOGIN_TYPE_BINDERY, pszStart, nSize ); + nSize -= wcslen( pszStart ); + pszStart += wcslen( pszStart); + } + + LoadString( ::hmodNW, IDS_LOGIN_STATUS_SEPARATOR, pszStart, nSize ); + nSize -= wcslen( pszStart ); + pszStart += wcslen( pszStart); + + GetConnectionStatusString( pConnStatus, (LPBYTE) pszStart, nSize ); + } + } + + if ( err == NO_ERROR ) + { + // Popup the message now. + ::MsgBoxPrintf( hParent, + dwMessageId, + IDS_TITLE_WHOAMI, + MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION, + szRemoteName[0] == TREECHAR? szRemoteName + 1 : szRemoteName, + szUserName, + szConnType ); + } + else // error occurred + { + ::MsgBoxErrorPrintf( hParent, + IDS_MESSAGE_CONNINFO_ERROR, + IDS_TITLE_WHOAMI, + MB_OK | MB_SETFOREGROUND | MB_ICONSTOP, + err, + NULL ); + } + + if ( pBuffer != NULL ) + { + LocalFree( pBuffer ); + pBuffer = NULL; + } + + return NOERROR; +} + +VOID +GetConnectionStatusString( + PCONN_STATUS pConnStatus, + LPBYTE Buffer, + DWORD nSize +) +{ + LPWSTR pszStart = (LPWSTR) Buffer; + DWORD dwMessageId = 0; + + if ( pConnStatus->fNds ) // NDS + { + if ( pConnStatus->dwConnType == NW_CONN_NOT_AUTHENTICATED ) + { + dwMessageId = IDS_LOGIN_STATUS_NOT_AUTHENTICATED; + } + else if ( pConnStatus->dwConnType == NW_CONN_DISCONNECTED ) + { + dwMessageId = IDS_LOGIN_STATUS_NOT_ATTACHED; + } + else // authenticated, licensed or unlicensed + { + LoadString( ::hmodNW, IDS_LOGIN_STATUS_AUTHENTICATED, + pszStart, nSize ); + nSize -= wcslen( pszStart ); + pszStart += wcslen( pszStart); + + if ( pConnStatus->dwConnType == NW_CONN_NDS_AUTHENTICATED_LICENSED ) + dwMessageId = IDS_LOGIN_STATUS_LICENSED; + else // NW_CONN_NDS_AUTHENTICATED_NO_LICENSE + dwMessageId = IDS_LOGIN_STATUS_NOT_LICENSED; + } + } + else // Bindery + { + if ( pConnStatus->dwConnType == NW_CONN_BINDERY_LOGIN ) + dwMessageId = IDS_LOGIN_STATUS_LOGGED_IN; + else if ( pConnStatus->dwConnType == NW_CONN_DISCONNECTED ) + dwMessageId = IDS_LOGIN_STATUS_NOT_ATTACHED; + else + dwMessageId = IDS_LOGIN_STATUS_ATTACHED_ONLY; + } + + LoadString( ::hmodNW, dwMessageId, pszStart, nSize ); +} + +HRESULT +NWUIGlobalWhoAmI( + HWND hParent +) +{ + ::DialogBoxParam( ::hmodNW, + MAKEINTRESOURCE(DLG_GLOBAL_WHOAMI), + hParent, + (DLGPROC) ::GlobalWhoAmIDlgProc, + NULL ); + + return NOERROR; +} + +HRESULT +NWUILogOut( + HWND hParent, + LPNETRESOURCE pNetRes, + PBOOL pfDisconnected +) +{ + DWORD err = NO_ERROR; + WCHAR szServer[MAX_PATH+1]; + BOOL fAttached; + BOOL fAuthenticated; + DWORD dwMessageId; + + *pfDisconnected = FALSE; + + // Need to extract the server name from full UNC path + NwExtractServerName( pNetRes->lpRemoteName, szServer ); + + err = NwIsServerOrTreeAttached( szServer, &fAttached, &fAuthenticated ); + + if ( err == NO_ERROR && !fAttached ) + { + dwMessageId = IDS_MESSAGE_NOT_ATTACHED; + } + else if ( err == NO_ERROR ) // attached + { + int nRet = ::MsgBoxPrintf( hParent, + IDS_MESSAGE_LOGOUT_CONFIRM, + IDS_TITLE_LOGOUT, + MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION); + + if ( nRet != IDYES ) + return NOERROR; + + err = LogoutFromServer( szServer, pfDisconnected ); + + if ( err == NO_ERROR ) + dwMessageId = IDS_MESSAGE_DETACHED; + else + dwMessageId = IDS_MESSAGE_LOGOUT_FAILED; + } + else // error occurred + { + ::MsgBoxErrorPrintf( hParent, + IDS_MESSAGE_CONNINFO_ERROR, + IDS_TITLE_LOGOUT, + MB_OK | MB_SETFOREGROUND | MB_ICONSTOP, + err, + NULL ); + + return NOERROR; + } + + ::MsgBoxPrintf( hParent, + dwMessageId, + IDS_TITLE_LOGOUT, + MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION ); + + return NOERROR; +} + +DWORD +LogoutFromServer( + LPWSTR pszServer, + PBOOL pfDisconnected +) +{ + DWORD err = NO_ERROR; + HANDLE EnumHandle = (HANDLE) NULL; + + LPNETRESOURCE NetR = NULL; + LPNETRESOURCEW SavePtr; + + DWORD BytesNeeded = MAX_ONE_NETRES_SIZE; + DWORD EntriesRead = 0; + DWORD i; + + *pfDisconnected = FALSE; + + err = NPOpenEnum( RESOURCE_CONNECTED, + 0, + 0, + NULL, + &EnumHandle ); + + if ( err != NO_ERROR) + { + EnumHandle = (HANDLE) NULL; + goto CleanExit; + } + + // + // Allocate buffer to get server list. + // + if ((NetR = (LPNETRESOURCE) LocalAlloc( 0, BytesNeeded )) == NULL) + { + err = ERROR_NOT_ENOUGH_MEMORY; + goto CleanExit; + } + + do { + + EntriesRead = 0xFFFFFFFF; // Read as many as possible + + err = NwEnumConnections( EnumHandle, + &EntriesRead, + (LPVOID) NetR, + &BytesNeeded, + TRUE ); + + + if ( err == WN_SUCCESS) + { + SavePtr = NetR; + + for (i = 0; i < EntriesRead; i++, NetR++) + { + BYTE Buffer[MAX_ONE_CONN_INFORMATION_SIZE]; + BOOL fImplicit; + LPWSTR pszCurrentServer; + + fImplicit = FALSE; + + if ( NwIsNdsSyntax( NetR->lpRemoteName)) + { + // For Nds name, the server name might not be in the full UNC name. + // Hence we need to get the server name from the Rdr. + + DWORD err1 = NwGetConnectionInformation( + NetR->lpLocalName? NetR->lpLocalName : NetR->lpRemoteName, + Buffer, + sizeof(Buffer)); + + if ( err1 != NO_ERROR ) + continue; // continue with the next entry if error occurred + + pszCurrentServer = ((PCONN_INFORMATION) Buffer)->HostServer; + + // Need to NULL terminate the server name, this will probably used the space + // occupied by UserName but since we are not using it, it is probably ok. + LPWSTR pszTemp = (LPWSTR) ((DWORD) pszCurrentServer + + ((PCONN_INFORMATION) Buffer)->HostServerLength ); + *pszTemp = 0; + + } + else // in the form \\server\sys + { + LPWSTR pszTemp; + wcscpy( (LPWSTR) Buffer, NetR->lpRemoteName + 2 ); // go past two backslashes + + if ( pszTemp = wcschr( (LPWSTR) Buffer, L'\\' )) + *pszTemp = 0; + else + { + // The remote name contains only \\server, hence if the local name + // is null, this is a implicit connection + if ( NetR->lpLocalName == NULL ) + fImplicit = TRUE; + } + + pszCurrentServer = (LPWSTR) Buffer; + } + + + if ( _wcsicmp( pszCurrentServer, pszServer ) == 0 ) + { + + do { + + // for implicit connections, we need to try and disconnect until + // we deleted all the implicit connections, i.e. until we + // get the invalid handle error + + // NOTE: If we don't pass in CONNECT_UPDATE_PROFILE, shell won't update + // the windows that got disconnected. What do we want to do here? + err = WNetCancelConnection2( + NetR->lpLocalName? NetR->lpLocalName : NetR->lpRemoteName, + 0, // CONNECT_UPDATE_PROFILE, + TRUE ); + + if ( err == NO_ERROR ) + *pfDisconnected = TRUE; + + } while ( fImplicit && ( err == NO_ERROR)); + + if ( err == ERROR_INVALID_HANDLE ) + { + // implicit connection will sometimes return this if the explicit connection + // is already disconnected + err = NO_ERROR; + } + + if ( err != NO_ERROR ) + { + NetR = SavePtr; + goto CleanExit; + } + } + } + + NetR = SavePtr; + } + else if ( err != WN_NO_MORE_ENTRIES) + { + if ( err == WN_MORE_DATA) + { + + // + // Original buffer was too small. Free it and allocate + // the recommended size and then some to get as many + // entries as possible. + // + + (void) LocalFree((HLOCAL) NetR); + + BytesNeeded += NW_ENUM_EXTRA_BYTES; + + if ((NetR = (LPNETRESOURCE) LocalAlloc( 0, BytesNeeded )) == NULL) + { + err = ERROR_NOT_ENOUGH_MEMORY; + goto CleanExit; + } + } + else + { + goto CleanExit; + } + } + + } while (err != WN_NO_MORE_ENTRIES); + + if ( err == WN_NO_MORE_ENTRIES) + err = NO_ERROR; + +CleanExit: + + if (EnumHandle != (HANDLE) NULL) + (void) NPCloseEnum( EnumHandle); + + if (NetR != NULL) + { + (void) LocalFree( (HLOCAL) NetR); + NetR = NULL; + } + + return err; +} + +HRESULT +NWUIAttachAs( + HWND hParent, + LPNETRESOURCE pNetRes +) +{ + DWORD err = NO_ERROR; + WCHAR szServerName[MAX_PATH+1]; + BOOL fAttached; + BOOL fAuthenticated; + + // First, see if we are attached to the server. + // Note, Attach as menu will be disabled on the NDS servers that we are already logged into. + + // Need to extract the server name from full UNC path + szServerName[0] = szServerName[1] = L'\\'; + NwExtractServerName( pNetRes->lpRemoteName, szServerName + 2 ); + + err = NwIsServerOrTreeAttached( szServerName + 2, &fAttached, &fAuthenticated ); + + if ( err == NO_ERROR && fAttached && fAuthenticated ) + { + // Already attached and authenticated to the server. + // So, ask the user if he wants to log out first. + + int nRet = ::MsgBoxPrintf( hParent, + IDS_MESSAGE_LOGOUT_QUESTION, + IDS_TITLE_LOGOUT, + MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION ); + + if ( nRet != IDYES ) + return NOERROR; + + BOOL fDisconnected = FALSE; // can be used to refresh the shell if needed + err = LogoutFromServer( szServerName + 2, &fDisconnected ); + + if ( err != NO_ERROR ) + { + ::MsgBoxPrintf( hParent, + IDS_MESSAGE_LOGOUT_FAILED, + IDS_TITLE_LOGOUT, + MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ); + + return NOERROR; + } + } + + // If error occurred, just assume we are not attached to the server and continue on + // to login to the server. + + DWORD dwConnFlags = CONNECT_INTERACTIVE | CONNECT_PROMPT; + + // See if the server is in the default context tree. + // If yes, then we don't need to prompt the password first before connecting + // in WNetAddConnection3. + + BOOL fInDefaultTree = FALSE; + err = NwIsServerInDefaultTree( pNetRes->lpRemoteName, &fInDefaultTree ); + + if ( (err == NO_ERROR ) && fInDefaultTree ) + dwConnFlags = CONNECT_INTERACTIVE; + + // + // Now call WNetAddConnection3 + // + + // NOTE: net use \\mars_srv0 will succeed + // but net use \\marsdev\cn=mars_srv0... will failed + // Hence, just use the server name to connect. + LPWSTR pszSave = pNetRes->lpRemoteName; + pNetRes->lpRemoteName = szServerName; + + err = WNetAddConnection3( hParent, + pNetRes, + NULL, + NULL, + dwConnFlags ); + + if ( err != WN_SUCCESS && err != WN_CANCEL ) + { + ::MsgBoxErrorPrintf( hParent, + IDS_MESSAGE_ADDCONN_ERROR, + IDS_NETWARE_TITLE, + MB_OK | MB_SETFOREGROUND | MB_ICONSTOP, + err, + pNetRes->lpRemoteName ); + } + + pNetRes->lpRemoteName = pszSave; // restore the original remote name just in case + + return NOERROR; +} + + +#if 0 +HRESULT +NWUISetDefaultContext( + HWND hParent, + LPNETRESOURCE pNetRes +) +{ + DWORD dwPrintOptions; + LPWSTR pszCurrentContext = NULL; + WCHAR szNewContext[MAX_PATH+1]; + + DWORD err = NO_ERROR; + HANDLE handleRdr = NULL; + + UNICODE_STRING uTree; + UNICODE_STRING uContext; + LPWSTR pszContext = NULL; + + // Open a handle to the redirector + err = RtlNtStatusToDosError( ::NwNdsOpenRdrHandle( &handleRdr )); + + if ( err != NO_ERROR ) + goto CleanExit; + + // Get the print option so that we can use it later + err = ::NwQueryInfo( &dwPrintOptions, &pszCurrentContext ); + + if ( err != NO_ERROR ) + goto CleanExit; + + wcscpy( szNewContext, pNetRes->lpRemoteName + 1 ); // get past 1st '\\' + szNewContext[0] = TREECHAR; // in the format "*TREE\CONTEXT" + + if ( (pszContext = wcschr( szNewContext, L'\\' )) != NULL ) + { + *pszContext = 0; + RtlInitUnicodeString( &uContext, pszContext + 1 ); + } + else + RtlInitUnicodeString( &uContext, L""); + + RtlInitUnicodeString( &uTree, szNewContext+1 ); + + if ( (err = RtlNtStatusToDosError( ::NwNdsSetTreeContext( handleRdr, &uTree, &uContext))) + == NO_ERROR ) + { + *pszContext = L'\\'; + + if ((err = ::NwSetInfoInRegistry( dwPrintOptions, szNewContext )) == NO_ERROR ) + { + ::MsgBoxPrintf( hParent, + IDS_MESSAGE_CONTEXT_CHANGED, + IDS_NETWARE_TITLE, + MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION, + pszCurrentContext + ? ( *pszCurrentContext == TREECHAR + ? pszCurrentContext + 1 + : pszCurrentContext ) + : L"", + szNewContext+1 ); + } + } + +CleanExit: + + if ( err != NO_ERROR ) + { + ::MsgBoxErrorPrintf( hParent, + IDS_MESSAGE_CONTEXT_ERROR, + IDS_NETWARE_TITLE, + MB_OK | MB_SETFOREGROUND | MB_ICONSTOP, + err, + szNewContext+1); + } + + if ( pszCurrentContext != NULL ) + { + LocalFree( pszCurrentContext ); + pszCurrentContext = NULL; + } + + if ( handleRdr != NULL ) + { + ::NtClose( handleRdr ); + handleRdr = NULL; + } + + return NOERROR; +} +#endif + +HRESULT +NWUIMapNetworkDrive( + HWND hParent, + LPNETRESOURCE pNetRes +) +{ + HRESULT hres; + CONNECTDLGSTRUCT cds; + + cds.cbStructure = sizeof(cds); + cds.hwndOwner = hParent; + cds.lpConnRes = pNetRes; + cds.dwFlags = CONNDLG_RO_PATH; + + if ( (( hres = WNetConnectionDialog1( &cds )) == WN_SUCCESS ) + && ( g_pFuncSHChangeNotify ) + ) + { + WCHAR szPath[4]; + + szPath[0] = ((USHORT) cds.dwDevNum) - 1 + L'A'; + szPath[1] = L':'; + szPath[2] = L'\\'; + szPath[3] = 0; + + // Notify shell about added redirection + (*g_pFuncSHChangeNotify)( SHCNE_DRIVEADD, + SHCNF_FLUSH | SHCNF_PATH, + szPath, + NULL ); + + // And we need to open shell window on this path + if (g_pFuncSHExecuteEx) + { + SHELLEXECUTEINFO ExecInfo; + + ::memset(&ExecInfo,0,sizeof(ExecInfo)); + + ExecInfo.hwnd = hParent; + ExecInfo.lpVerb = 0; + ExecInfo.lpFile = szPath; + ExecInfo.lpParameters = NULL; + ExecInfo.lpDirectory = NULL; + ExecInfo.nShow = SW_NORMAL | SW_SHOW; + ExecInfo.fMask = SEE_MASK_CLASSNAME; + ExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); + ExecInfo.lpClass = (LPWSTR) L"Folder"; + ExecInfo.hkeyClass = NULL; + + (*g_pFuncSHExecuteEx)(&ExecInfo); + } + } + + return hres; +} + + + +#define LB_PCT_NAME 25 +#define LB_PCT_TYPE 11 +#define LB_PCT_CONN 11 +#define LB_PCT_USER 25 +#define LB_PCT_STATUS 27 + +#define BITMAP_WIDTH 16 +#define BITMAP_HEIGHT 16 + +#define MAPCOLOR RGB(0, 255, 0) + +static UINT uiNDSIconIndex = 0; +static UINT uiServerIconIndex = 0; + +/* + * FillConnectionsListView + * ----------------------- + * + * Fill list box with information on active connections + */ +VOID +FillConnectionsListView( + HWND hwndDlg +) +{ + HWND hwndLV = ::GetDlgItem(hwndDlg,IDD_GLOBAL_SERVERLIST); + LV_ITEM lvI; + WCHAR szSubItemText[MAX_PATH+1]; + UINT uiInsertedIndex; + + DWORD ResumeKey = 0; + LPBYTE pConnBuffer = NULL; + DWORD EntriesRead = 0; + DWORD err = NO_ERROR; + + // Prepare ListView structure + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvI.state = 0; + lvI.stateMask = 0; + + do { + + if ( pConnBuffer != NULL ) + { + LocalFree( pConnBuffer ); + pConnBuffer = NULL; + } + + err = NwGetConnectionStatus( NULL, + &ResumeKey, + &pConnBuffer, + &EntriesRead ); + + + if ( ( err != NO_ERROR ) + || ( EntriesRead == 0 ) + ) + { + goto CleanExit; + } + + PCONN_STATUS pConnStatus = (PCONN_STATUS) pConnBuffer; + + for ( DWORD i = 0; i < EntriesRead; i++) + { + // Allocate and initialize new item structure for use in the listbox + + DWORD dwSize; + + // + // Don't need to show preferred server with only implicit + // connections since we can't disconnect from it. + // + if ( pConnStatus->fPreferred ) + { + // Continue with the next item + pConnStatus = (PCONN_STATUS) ( (DWORD) pConnStatus + + pConnStatus->dwTotalLength); + continue; + } + + // + // Allocate and copy the connection information to be store with + // the listbox + // + PCONN_STATUS pConnStatusKeep = + (PCONN_STATUS) LocalAlloc( LMEM_ZEROINIT, pConnStatus->dwTotalLength ); + if ( pConnStatusKeep == NULL ) + { + err = ERROR_NOT_ENOUGH_MEMORY; + goto CleanExit; + } + + memcpy( pConnStatusKeep, pConnStatus, pConnStatus->dwTotalLength ); + + dwSize = sizeof(CONN_STATUS); + + if ( pConnStatus->pszServerName ) + { + pConnStatusKeep->pszServerName = + (LPWSTR) ((DWORD)pConnStatusKeep + dwSize ); + + NwMakePrettyDisplayName( pConnStatusKeep->pszServerName ); + + dwSize += (wcslen(pConnStatus->pszServerName)+1)*sizeof(WCHAR); + } + + if ( pConnStatus->pszUserName ) + { + pConnStatusKeep->pszUserName = + (LPWSTR) ((DWORD)pConnStatusKeep + dwSize ); + + dwSize += (wcslen(pConnStatus->pszUserName)+1) * sizeof(WCHAR); + + NwAbbreviateUserName( pConnStatus->pszUserName, + pConnStatusKeep->pszUserName ); + + NwMakePrettyDisplayName( pConnStatusKeep->pszUserName ); + } + + if ( pConnStatus->pszTreeName ) + { + pConnStatusKeep->pszTreeName = + (LPWSTR) ((DWORD)pConnStatusKeep + dwSize ); + } + + // + // Construct the item to add to the listbox + // + lvI.iItem = i; + lvI.iSubItem = 0; + lvI.pszText = szSubItemText; + lvI.cchTextMax = sizeof(szSubItemText); + + // Select proper icon + lvI.iImage = pConnStatusKeep->fNds? uiNDSIconIndex + : uiServerIconIndex; + + lvI.lParam = (LPARAM) pConnStatusKeep; + + wcscpy( szSubItemText, pConnStatusKeep->pszServerName ); + + // Insert the item + uiInsertedIndex = ListView_InsertItem( hwndLV, &lvI); + + if ( uiInsertedIndex != -1 ) + { + // Added item itself - now for specific columns + + // First, add the column indicating bindery or nds connection + if ( pConnStatusKeep->fNds ) + { + LoadString( ::hmodNW, IDS_LOGIN_TYPE_NDS, szSubItemText, + sizeof(szSubItemText)/sizeof(szSubItemText[0])); + } + else + { + LoadString( ::hmodNW, IDS_LOGIN_TYPE_BINDERY, szSubItemText, + sizeof(szSubItemText)/sizeof(szSubItemText[0])); + } + + ListView_SetItemText( hwndLV, + uiInsertedIndex, + 1, // SubItem id + szSubItemText ); + + // Next, Add the column indicating the connection number + + if ( ( pConnStatusKeep->pszServerName[0] != TREECHAR ) + && ( pConnStatusKeep->dwConnType != NW_CONN_DISCONNECTED ) + ) + { + // Add connection number only if it is a connection + // to a server and not a tree. + // A connection number only makes sense when not disconnected + ::wsprintf(szSubItemText,L"%4d",pConnStatusKeep->nConnNum ); + ListView_SetItemText( hwndLV, + uiInsertedIndex, + 2, // SubItem id + szSubItemText ); + } + + // Then, add the column indicating the user name + + *szSubItemText = L'\0'; + if ( pConnStatusKeep->pszUserName ) + { + wcscpy( szSubItemText, pConnStatusKeep->pszUserName ); + + ListView_SetItemText( hwndLV, + uiInsertedIndex, + 3, // SubItem id + szSubItemText ); + } + + // Last of all, add the column indicating the connection status + + *szSubItemText = L'\0'; + GetConnectionStatusString( pConnStatusKeep, + (LPBYTE) szSubItemText, + sizeof(szSubItemText)/sizeof(szSubItemText[0])); + + ListView_SetItemText( hwndLV, + uiInsertedIndex, + 4, // SubItem id + szSubItemText ); + + } + else + { + // Failed inserting item in the list, + // need to delete the allocated CONN_STATUS + ASSERT( FALSE ); + LocalFree( pConnStatusKeep ); + pConnStatusKeep = NULL; + } + + // Continue with the next item + pConnStatus = (PCONN_STATUS) ( (DWORD) pConnStatus + + pConnStatus->dwTotalLength); + } + + } while ( ResumeKey != 0 ); + +CleanExit: + + if ( pConnBuffer != NULL ) + { + LocalFree( pConnBuffer ); + pConnBuffer = NULL; + } + + if ( err != NO_ERROR ) + { + // If error occurred, we will end the dialog + + ::MsgBoxErrorPrintf( hwndDlg, + IDS_MESSAGE_CONNINFO_ERROR, + IDS_NETWARE_TITLE, + MB_OK | MB_SETFOREGROUND | MB_ICONSTOP, + err, + NULL ); + + ::EndDialog( hwndDlg, FALSE); + } +} + + +/* + * CreateConnectionsListView + * ------------------------- + * + * Initialize the column headers of the list box + */ +VOID +CreateConnectionsListView( + HWND hwndDlg +) +{ + HWND hwndLV; + HIMAGELIST hSmall; + UINT uiLBoxWidth; + + InitCommonControls(); + + // Get the handle of the listbox + hwndLV = ::GetDlgItem(hwndDlg,IDD_GLOBAL_SERVERLIST); + + RECT rc; + ::GetWindowRect( ::GetDlgItem( hwndDlg, IDD_GLOBAL_SERVERLIST ), &rc ); + uiLBoxWidth = rc.right - rc.left; + + // Load image list + hSmall = ::ImageList_Create(BITMAP_WIDTH,BITMAP_HEIGHT,ILC_MASK,4,0); + + // Load bitmap of the tree/server icon + HBITMAP hbm; + hbm = ::LoadBitmap(::hmodNW,MAKEINTRESOURCE(IDB_TREE_ICON)); + if ((uiNDSIconIndex = ImageList_AddMasked(hSmall,hbm,MAPCOLOR)) == -1) + ASSERT(FALSE); + + hbm = ::LoadBitmap(::hmodNW,MAKEINTRESOURCE(IDB_SERVER_ICON)); + if ((uiServerIconIndex = ImageList_AddMasked(hSmall,hbm,MAPCOLOR)) == -1) + ASSERT(FALSE); + + ImageList_SetBkColor(hSmall, CLR_NONE); + + // Associate image list with list view control + ListView_SetImageList(hwndLV,hSmall,LVSIL_SMALL); + + // Initialize columns in header + LV_COLUMN lvC; + UINT uiColumnIndex = 0; + WCHAR szColumnName[128]; + + lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + lvC.fmt = LVCFMT_LEFT; + lvC.cx = (uiLBoxWidth*LB_PCT_NAME)/100; + lvC.pszText = szColumnName; + + // Add the column header representing the server name + *szColumnName = L'\0'; + ::LoadString( ::hmodNW, + IDS_COLUMN_NAME, + szColumnName, + sizeof(szColumnName)/sizeof(szColumnName[0])); + if ( ListView_InsertColumn(hwndLV,uiColumnIndex++,&lvC) == -1) + ASSERT(FALSE); + + + // Add the column header representing the conneciton type + *szColumnName = L'\0'; + lvC.cx = (uiLBoxWidth*LB_PCT_TYPE)/100; + ::LoadString( ::hmodNW, + IDS_COLUMN_CONN_TYPE, + szColumnName, + sizeof(szColumnName)/sizeof(szColumnName[0])); + if ( ListView_InsertColumn(hwndLV,uiColumnIndex++,&lvC) == -1) + ASSERT(FALSE); + + // Add the column header representing the connection number + *szColumnName = L'\0'; + lvC.cx = (uiLBoxWidth*LB_PCT_CONN)/100; + lvC.fmt = LVCFMT_RIGHT; + + ::LoadString( ::hmodNW, + IDS_COLUMN_CONN_NUMBER, + szColumnName, + sizeof(szColumnName)/sizeof(szColumnName[0])); + if ( ListView_InsertColumn(hwndLV,uiColumnIndex++,&lvC) == -1) + ASSERT(FALSE); + + // Add the column header representing the name of the user + *szColumnName = L'\0'; + lvC.cx = (uiLBoxWidth*LB_PCT_USER)/100; + lvC.fmt = LVCFMT_LEFT; + + ::LoadString( ::hmodNW, + IDS_COLUMN_USER, + szColumnName, + sizeof(szColumnName)/sizeof(szColumnName[0])); + + if ( ListView_InsertColumn(hwndLV,uiColumnIndex++,&lvC) == -1) + ASSERT(FALSE); + + // Add the column header representing the status of the connection + *szColumnName = L'\0'; + lvC.cx = (uiLBoxWidth*LB_PCT_STATUS)/100; + lvC.fmt = LVCFMT_LEFT; + + ::LoadString( ::hmodNW, + IDS_COLUMN_STATUS, + szColumnName, + sizeof(szColumnName)/sizeof(szColumnName[0])); + + if ( ListView_InsertColumn(hwndLV,uiColumnIndex++,&lvC) == -1) + ASSERT(FALSE); + + // Now fill list view window with connection information + FillConnectionsListView( hwndDlg ); + +} /* endproc CreateConnectionsListView */ + + +/* + * GlobalWhoAmI_ListViewCompareProc + * -------------------------------- + * + */ +LRESULT CALLBACK +GlobalWhoAmI_ListViewCompareProc( + LPARAM lParam1, + LPARAM lParam2, + LPARAM lParamSort +) +{ + PCONN_STATUS pConnItem1 = (PCONN_STATUS)lParam1; + PCONN_STATUS pConnItem2 = (PCONN_STATUS)lParam2; + + int iResult = 0; + + if ( pConnItem1 && pConnItem2 ) + { + switch(lParamSort) + { + case 0: + iResult = ::_wcsicmp( pConnItem1->pszServerName, + pConnItem2->pszServerName); + break; + + case 1: + iResult = pConnItem1->fNds - pConnItem2->fNds; + break; + + case 2: + iResult = pConnItem1->nConnNum - pConnItem2->nConnNum; + break; + + case 3: + { + // pszUserName might be NULL, so we need to be careful when + // comparing them. + if ( pConnItem1->pszUserName ) + { + if ( pConnItem2->pszUserName ) + { + iResult = ::_wcsicmp( pConnItem1->pszUserName, + pConnItem2->pszUserName); + } + else + { + iResult = 1; + } + } + else + { + iResult = -1; + } + break; + } + + case 4: + iResult = pConnItem1->dwConnType - pConnItem2->dwConnType; + break; + + default: + iResult = 0; + break; + } + } + + return (iResult); + +} + +LRESULT +NotifyHandler( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +) +{ + NM_LISTVIEW *lpNm = (NM_LISTVIEW *)lParam; + NMHDR *lphdr = &lpNm->hdr; + + HWND hwndLV = ::GetDlgItem(hwndDlg,IDD_GLOBAL_SERVERLIST); + + switch(lphdr->code) + { + case LVN_ITEMCHANGED: + // Check for change in item state, make sure item has received focus + if (lpNm->uChanged & LVIF_STATE) + { + UINT uiSelectedItems = 0; + + uiSelectedItems = ListView_GetSelectedCount(hwndLV); + + EnableWindow( GetDlgItem(hwndDlg, IDD_DETACH), + uiSelectedItems? TRUE : FALSE); + + return TRUE; + } + break; + + case LVN_COLUMNCLICK: + ListView_SortItems( hwndLV, + GlobalWhoAmI_ListViewCompareProc, + (LPARAM)(lpNm->iSubItem)); + return TRUE; /* we processed a message */ + + case LVN_DELETEITEM: + // Free memory + LocalFree( (HLOCAL) lpNm->lParam ); + lpNm->lParam = NULL; + break; + + default: + break; + } + + return FALSE; +} + + +BOOL +DetachResourceProc( + HWND hwndDlg +) +{ + BOOL fDetached = FALSE; + LV_ITEM lvitem; + int index; + DWORD err; + + HWND hwndLV = ::GetDlgItem( hwndDlg, IDD_GLOBAL_SERVERLIST); + + index = -1; // Start at beginning of item list. + + while ((index = ListView_GetNextItem(hwndLV, index, LVNI_SELECTED)) != -1) + { + lvitem.iItem = index; + lvitem.mask = LVIF_PARAM; + lvitem.iSubItem = 0; + + if ( ListView_GetItem( hwndLV, &lvitem )) + { + PCONN_STATUS pConnStatus = (PCONN_STATUS) lvitem.lParam; + BOOL fDisconnected = FALSE; // Can be used to refresh + // the shell if needed + + err = LogoutFromServer( pConnStatus->pszServerName, + &fDisconnected ); + + if ( err == NO_ERROR ) + { + fDetached = TRUE; + } + else + { + NwMakePrettyDisplayName(pConnStatus->pszServerName); + ::MsgBoxPrintf( hwndDlg, + IDS_MESSAGE_LOGOUT_FROM_SERVER_FAILED, + IDS_TITLE_LOGOUT, + MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION, + pConnStatus->pszServerName ); + } + } + } + + return fDetached; +} + +static DWORD aWhoAmIIds[] = { IDC_LOGOFRAME, NO_HELP, + IDD_GLOBAL_SERVERLIST_T,IDH_GLOBAL_SERVERLIST, + IDD_GLOBAL_SERVERLIST, IDH_GLOBAL_SERVERLIST, + IDD_DETACH, IDH_GLOBAL_DETACH, + IDD_GLOBAL_SVRLIST_DESC,IDH_GLOBAL_SERVERLIST, + 0, 0 }; + +/* + * GlobalWhoAmIDlgProc + * ------------------- + * + * WhoAmI information for list of attached servers + */ +BOOL +CALLBACK +GlobalWhoAmIDlgProc( + HWND hwndDlg, + UINT msg, + WPARAM wParam, + LPARAM lParam +) +{ + switch (msg) + { + case WM_INITDIALOG: + { + LPWSTR pszCurrentContext = NULL; + DWORD dwPrintOptions; + + // Get the current default tree or server name + DWORD err = ::NwQueryInfo( &dwPrintOptions, &pszCurrentContext ); + if ( err == NO_ERROR ) + { + LPWSTR pszName; + WCHAR szUserName[MAX_PATH+1] = L""; + WCHAR szNoName[2] = L""; + DWORD ResumeKey = 0; + LPBYTE pBuffer = NULL; + DWORD EntriesRead = 0; + + DWORD dwMessageId; + + UNICODE_STRING uContext; + WCHAR szContext[MAX_PATH+1]; + + szContext[0] = 0; + uContext.Buffer = szContext; + uContext.Length = uContext.MaximumLength + = sizeof(szContext)/sizeof(szContext[0]); + + if ( pszCurrentContext ) + { + pszName = pszCurrentContext; + } + else + { + pszName = szNoName; + } + + if ( pszName[0] == TREECHAR ) + { + // Get the tree name from the full name *TREE\CONTEXT + + LPWSTR pszTemp; + if ( pszTemp = wcschr( pszName, L'\\' )) + *pszTemp = 0; + + dwMessageId = IDS_MESSAGE_NOT_LOGGED_IN_TREE; + } + else + { + dwMessageId = IDS_MESSAGE_NOT_LOGGED_IN_SERVER; + } + + if ( pszName[0] != 0 ) // there is preferred server/tree + { + err = NwGetConnectionStatus( pszName, + &ResumeKey, + &pBuffer, + &EntriesRead ); + } + + if ( err == NO_ERROR && EntriesRead > 0 ) + // For trees, we'll get more than one entry + { + PCONN_STATUS pConnStatus = (PCONN_STATUS) pBuffer; + + if ( EntriesRead > 1 && pszName[0] == TREECHAR ) + { + // If there is more than one entry for trees, + // then we need to find one entry where username is not null. + // If we cannot find one, then just use the first one. + + DWORD i; + PCONN_STATUS pConnStatusTmp = pConnStatus; + PCONN_STATUS pConnStatusUser = NULL; + PCONN_STATUS pConnStatusNoUser = NULL; + + for ( i = 0; i < EntriesRead ; i++ ) + { + if ( pConnStatusTmp->fNds ) + { + pConnStatusNoUser = pConnStatusTmp; + + if ( ( pConnStatusTmp->pszUserName != NULL ) + && ( ( pConnStatusTmp->dwConnType + == NW_CONN_NDS_AUTHENTICATED_NO_LICENSE ) + || ( pConnStatusTmp->dwConnType + == NW_CONN_NDS_AUTHENTICATED_LICENSED ) + ) + ) + { + // Found it + pConnStatusUser = pConnStatusTmp; + break; + } + } + + // Continue with the next item + pConnStatusTmp = (PCONN_STATUS) + ( (DWORD) pConnStatusTmp + + pConnStatusTmp->dwTotalLength); + } + + if ( pConnStatusUser ) + { + // found one nds entry with a user name + pConnStatus = pConnStatusUser; + } + else if ( pConnStatusNoUser ) + { + // use an nds entry with no user name + pConnStatus = pConnStatusNoUser; + } + // else use the first entry + } + + if ( ( pConnStatus->pszUserName ) + && ( pConnStatus->pszUserName[0] != 0 ) + ) + { + NwAbbreviateUserName( pConnStatus->pszUserName, + szUserName); + + NwMakePrettyDisplayName( szUserName ); + + if ( pszName[0] != TREECHAR ) + { + dwMessageId = IDS_MESSAGE_LOGGED_IN_SERVER; + } + else + { + dwMessageId = IDS_MESSAGE_LOGGED_IN_TREE; + } + } + + if ( pszName[0] == TREECHAR ) + { + // For trees, we need to get the current context + + // Open a handle to the redirector + HANDLE handleRdr = NULL; + err = RtlNtStatusToDosError( + ::NwNdsOpenRdrHandle( &handleRdr )); + + if ( err == NO_ERROR ) + { + UNICODE_STRING uTree; + RtlInitUnicodeString( &uTree, pszName+1 ); // get past '*' + + // Get the current context in the default tree + err = RtlNtStatusToDosError( + ::NwNdsGetTreeContext( handleRdr, + &uTree, + &uContext)); + } + + if ( handleRdr != NULL ) + ::NtClose( handleRdr ); + } + } + + if ( !err ) + { + LPWSTR pszText = NULL; + err = ::LoadMsgPrintf( &pszText, + dwMessageId, + pszName[0] == TREECHAR? + pszName + 1 : pszName, + szUserName, + szContext ); + + if ( err == NO_ERROR ) + { + ::SetDlgItemText( hwndDlg, IDD_GLOBAL_SERVERLIST_T, + pszText); + ::LocalFree( pszText ); + } + } + + if ( pBuffer != NULL ) + { + LocalFree( pBuffer ); + pBuffer = NULL; + } + } + + if ( pszCurrentContext != NULL ) + { + LocalFree( pszCurrentContext ); + pszCurrentContext = NULL; + } + + if ( err != NO_ERROR ) + { + ::MsgBoxErrorPrintf( hwndDlg, + IDS_MESSAGE_CONNINFO_ERROR, + IDS_NETWARE_TITLE, + MB_OK | MB_SETFOREGROUND | MB_ICONSTOP, + err, + NULL ); + ::EndDialog( hwndDlg, FALSE); + return TRUE; + } + + // Fill listview control with connection parameters + CreateConnectionsListView(hwndDlg); + + UnHideControl( hwndDlg, IDD_DETACH); + + // List view fill defaults to no selected server, disable Detach. + EnableWindow( GetDlgItem( hwndDlg, IDD_DETACH), FALSE); + + // Set up timer for automatic refresh interval + ::SetTimer( hwndDlg, 1, GLOBAL_WHOAMI_REFRESH_INTERVAL, NULL); + + // Set focus to list box + ::SetFocus( ::GetDlgItem( hwndDlg, IDD_GLOBAL_SERVERLIST)); + + return FALSE; /* we set the focus */ + } + + case WM_DESTROY: + ::KillTimer( hwndDlg, 1); + break; + + case WM_COMMAND: + + switch (wParam) + { + case IDOK: + case IDCANCEL: + ::EndDialog( hwndDlg, FALSE); + return TRUE; /* we processed a message */ + + case IDD_DETACH: + // Attempt to detach server connection currently selected + if ( DetachResourceProc( hwndDlg )) + { + // If succeeded - refresh window + ::SendMessage(hwndDlg,WM_COMMAND,IDD_REFRESH,0L); + } + + return TRUE; /* we processed a message */ + + case IDD_REFRESH: + { + // Refresh connection listbox + + HWND hwndLV = ::GetDlgItem( hwndDlg, IDD_GLOBAL_SERVERLIST); + + ::SetFocus( hwndLV ); + + // Clear list + ListView_DeleteAllItems( hwndLV ); + + // Now refill list view window + FillConnectionsListView( hwndDlg ); + + // List view refill unsets selected server focus, disable Detach. + EnableWindow( GetDlgItem( hwndDlg, IDD_DETACH ), FALSE ); + + return TRUE; /* we processed a message */ + } + + default: + break; + } + break; + + case WM_NOTIFY: + // Handle notifications + if ( NotifyHandler( hwndDlg, msg, wParam, lParam)) + return TRUE; /* we processed a message */ + break; + + case WM_TIMER: + ::SendMessage( hwndDlg, WM_COMMAND, IDD_REFRESH, 0L); + break; + + case WM_HELP: + ::WinHelp( (HWND) ((LPHELPINFO)lParam)->hItemHandle, + NW_HELP_FILE, + HELP_WM_HELP, + (DWORD) (LPVOID) aWhoAmIIds ); + return TRUE; + + case WM_CONTEXTMENU: + ::WinHelp( (HWND) wParam, + NW_HELP_FILE, + HELP_CONTEXTMENU, + (DWORD) (LPVOID) aWhoAmIIds ); + return TRUE; + + } + + return FALSE; /* we didn't process the message */ + +} |