/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corp., 1995 **/ /**********************************************************************/ /* winsadmn.cpp FILE HISTORY: */ #include "stdafx.h" #include "winsadmn.h" #include "mainfrm.h" #include "winsadoc.h" #include "statisti.h" #include "selectwi.h" #include "addstati.h" #include "staticma.h" #include // For WSAStartup() #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW // // Typedef for the ShellAbout function // typedef void (WINAPI *LPFNSHELLABOUT)(HWND, LPTSTR, LPTSTR, HICON); // // CWinsadmnApp // BEGIN_MESSAGE_MAP(CWinsadmnApp, CWinApp) //{{AFX_MSG_MAP(CWinsadmnApp) ON_COMMAND(ID_APP_ABOUT, OnAppAbout) //}}AFX_MSG_MAP // Standard file based document commands ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) // Standard print setup command ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup) // Global help commands ON_COMMAND(ID_HELP_INDEX, CWinApp::OnHelpFinder) ON_COMMAND(ID_HELP_USING, CWinApp::OnHelpUsing) ON_COMMAND(ID_HELP, CWinApp::OnHelp) ON_COMMAND(ID_CONTEXT_HELP, CWinApp::OnContextHelp) ON_COMMAND(ID_DEFAULT_HELP, CWinApp::OnHelpIndex) END_MESSAGE_MAP() // // Name of NetBIOS named pipe for WINS servers. // const LPCSTR CWinsadmnApp::lpstrPipeName = "\\pipe\\WinsPipe"; // // CWinsadmnApp construction // CWinsadmnApp::CWinsadmnApp() #ifndef WIN32S : m_hmutStatistics(NULL), m_hmutScreenRefresh(NULL) #endif // WIN32S { #ifdef _TIGHTMEMCHECKING afxMemDF |= checkAlwaysMemDF; #endif //_TIGHTMEMCHECKING } // // CWinsadmnApp initialization // BOOL CWinsadmnApp::InitApplication() { // // Call base class. Default version does nothing. // CWinApp::InitApplication(); WNDCLASS wndcls; ::memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL defaults // // Get class information for default window class. // ::GetClassInfo(AfxGetInstanceHandle(),"AfxFrameOrView",&wndcls); // // Substitute unique class name for new class // wndcls.lpszClassName = WINSADMIN_CLASS_NAME; // // Register new class and return the result code // return ::RegisterClass(&wndcls); } BOOL CWinsadmnApp::FirstInstance() { CWnd *PrevCWnd, *ChildCWnd; // // Determine if another window with our class name exists... // if ((PrevCWnd = CWnd::FindWindow(WINSADMIN_CLASS_NAME,NULL)) == NULL) { // // First instance, proceed as normal // return TRUE; } // // Previous instance exists -- reactivate it. // ChildCWnd=PrevCWnd->GetLastActivePopup(); // if so, does it have any popups? #ifdef _WIN32 // BringWindowToTop() doesn't do it in WIN32 -- MFC bug? ::SetForegroundWindow(PrevCWnd->m_hWnd); #else PrevCWnd->BringWindowToTop(); // Bring the main window to the top #endif // _WIN32 if (PrevCWnd->IsIconic()) { // // If iconic, restore the main window // PrevCWnd->ShowWindow(SW_RESTORE); } if (PrevCWnd != ChildCWnd) { // // Restore popups // #ifdef _WIN32 ::SetForegroundWindow(ChildCWnd->m_hWnd); #else ChildCWnd->BringWindowToTop(); #endif // _WIN32 } return FALSE; } BOOL CWinsadmnApp::InitInstance() { // // If this isn't the first instance, return FALSE // immediately. FirstInstance() will have already // activated the previous instance. // if (!FirstInstance()) { return FALSE; } // // Initialize the CWndIpAddress control window class IPADDRESS // CWndIpAddress::CreateWindowClass( m_hInstance ) ; #ifdef _USE_3D Enable3dControls(); // Use CTRL3D #endif // _USE_3D #ifdef GRAYDLG SetDialogBkColor(); // set dialog background color to gray #endif // GRAYDLG // // Not connected to anyone at startup. // m_hBinding = INVALID_HANDLE_VALUE; // // load preferences and cache from the registry // LoadStdProfileSettings(); APIERR err; BeginWaitCursor(); if ((err = m_wpPreferences.Load()) || (err = m_wcWinssCache.Load(m_wpPreferences.IsValidateCache(), theApp.m_wpPreferences.m_nAddressDisplay == CPreferences::ADD_IP_ONLY || theApp.m_wpPreferences.m_nAddressDisplay == CPreferences::ADD_IP_NB)) ) { theApp.MessageBox(err); } EndWaitCursor(); WORD wVersionRequested = MAKEWORD(1, 1); WSADATA wsaData; err = WSAStartup(wVersionRequested, &wsaData); if (err) { //Tell the user that we couldn't find a useable winsock.dll TRACEEOLID("WSAStartup returned err=" << err ); return FALSE; } // // Register the application's document templates. Document templates // serve as the connection between documents, frame windows and views. // AddDocTemplate(new CSingleDocTemplate(IDR_MAINFRAME, RUNTIME_CLASS(CWinsadmnDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame window RUNTIME_CLASS(CStatistics))); // // Set up initial screen // OnFileNew(); if (!m_strEllipses.LoadString(IDS_ELLIPSES)) { m_strEllipses = _T("..."); // Just in case } // // Necessary for explicit import // BOOL fIpInit = IPAddrInit(NULL); TRACEEOLID("IPAddrInit returned " << fIpInit ); return TRUE; } int CWinsadmnApp::ExitInstance() { ASSERT(!IsConnected()); BeginWaitCursor(); APIERR err; if ((err = m_wpPreferences.Store()) || (err = m_wcWinssCache.Store())) { theApp.MessageBox(err); } EndWaitCursor(); #ifndef WIN32S if (m_hmutStatistics == NULL) { ::ReleaseMutex(m_hmutStatistics); ::CloseHandle(m_hmutStatistics); } #endif // WIN32S return 0; } // // Clean up the main window before putting on the hourglass and // freezing the display. // void CWinsadmnApp::DoWaitCursor( int nCode ) { if ( m_pMainWnd != NULL ) { m_pMainWnd->UpdateWindow(); } CWinApp::DoWaitCursor(nCode); } /*** * * CWinsadmnApp::GetSystemMessage * * Purpose: * * Given a message ID, determine where the message resides, * and load it into the buffer. * * Arguments: * * UINT nId Message ID number * char * chBuffer Character buffer to load into. * int cbBuffSize Size of buffer in characters * * Returns: * * API error return code, or ERROR_SUCCESS * */ APIERR CWinsadmnApp::GetSystemMessage( UINT nId, char * chBuffer, int cbBuffSize ) { char * pszText = NULL ; HINSTANCE hdll = NULL ; DWORD flags = FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK; // // Interpret the error. Need to special case // the lmerr & ntstatus ranges. // if( nId >= NERR_BASE && nId <= MAX_NERR ) { hdll = ::LoadLibrary( "netmsg.dll" ); } else if( nId >= 0x40000000L ) { hdll = ::LoadLibrary( "ntdll.dll" ); } if( hdll == NULL ) { flags |= FORMAT_MESSAGE_FROM_SYSTEM; } else { flags |= FORMAT_MESSAGE_FROM_HMODULE; } DWORD dwResult = ::FormatMessage( flags, (LPVOID) hdll, nId, 0, chBuffer, cbBuffSize, NULL ); if( hdll != NULL ) { LONG err = ::GetLastError(); ::FreeLibrary( hdll ); if ( dwResult == 0 ) { ::SetLastError( err ); } } return dwResult ? ERROR_SUCCESS : ::GetLastError(); } /*** * * CWinsadmnApp::MessageBox * * Purpose: * * Replacement for AfxMessageBox(). This function will call up the * appropriate message from wherever before displaying it * * Arguments: * * UINT nIdPrompt Message ID * UINT nType AfxMessageBox type (YESNO, OKCANCEL, etc) * UINT nHelpContext Help context ID for AfxMessageBox(); * * Notes: * * If an error occurs, a standard message (hard-coded in english) will * be shown that gives the error number. * */ int CWinsadmnApp::MessageBox ( UINT nIdPrompt, UINT nType, UINT nHelpContext ) { // // Substitute a friendly message for "RPC server not // available" and "No more endpoints available from // the endpoint mapper". // if (nIdPrompt == EPT_S_NOT_REGISTERED || nIdPrompt == RPC_S_SERVER_UNAVAILABLE) { nIdPrompt = IDS_ERR_WINS_DOWN; } // // If it's our error, the text is in our resource segment. // Otherwise, use FormatMessage() and the appropriate DLL> // if ((nIdPrompt >= IDS_ERR_BASE) && (nIdPrompt <= IDS_MSG_LAST)) { return ::AfxMessageBox(nIdPrompt, nType, nHelpContext); } char szMesg [1024] ; int nResult; if ((nResult = GetSystemMessage(nIdPrompt, szMesg, sizeof(szMesg))) == ERROR_SUCCESS) { return ::AfxMessageBox(szMesg, nType, nHelpContext); } TRACEEOLID("Message number " << nIdPrompt << " not found"); ASSERT(0 && "Error Message ID not handled"); // // Do something for the retail version // ::wsprintf ( szMesg, _T("Error: %lu"), nIdPrompt); ::AfxMessageBox(szMesg, nType, nHelpContext); return nResult; } // // Get the control rectangle coordinates relative // to its parent. This can then be used in // SetWindowPos() // void CWinsadmnApp::GetDlgCtlRect( HWND hWndParent, HWND hWndControl, LPRECT lprcControl ) { #define MapWindowRect(hwndFrom, hwndTo, lprc)\ MapWindowPoints((hwndFrom), (hwndTo), (POINT *)(lprc), 2) ::GetWindowRect(hWndControl, lprcControl); ::MapWindowRect(NULL, hWndParent, lprcControl); } /*** * * CWinsadmnApp::CleanString(CString& str) * * Purpose: * * Strip leading and trailing spaces from the string. * * Returns: * * A reference to the string * */ CString& CWinsadmnApp::CleanString( CString& str ) { if (str.IsEmpty()) { return str ; } int n = 0; while ((n < str.GetLength()) && (str[n] == ' ')) { ++n; } if (n) { str = str.Mid(n); } n = str.GetLength(); while (n && (str[--n] == ' ')) { str.ReleaseBuffer(n); } return str; } // // Convert the netbios name to a displayable format, with // beginning slashes, the unprintable characters converted // to '-' characters, and the 16th character displayed in brackets. // Convert the string to ANSI/Unicode before displaying it. // // CString& CWinsadmnApp::CleanNetBIOSName( LPCSTR lpSrc, BOOL fExpandChars, BOOL fTruncate, BOOL fLanmanCompatible, BOOL fOemName, BOOL fWackwack, int nLength ) { static CString strTarget; static TCHAR szWacks[] = _T("\\\\"); BYTE ch16 = 0; int nLen, nDisplayLen; int nMaxDisplayLen = fLanmanCompatible ? 15 : 16; if (!fWackwack && fLanmanCompatible) { // // Don't want backslahes, but if they do exist, // remove them. // if (!::strncmp(lpSrc, szWacks, ::strlen(szWacks))) { lpSrc += ::strlen(szWacks); if (nLength) { nLength -= 2; } } } if ((nDisplayLen = nLen = nLength ? nLength : ::lstrlen(lpSrc)) > 15) { ch16 = (BYTE)lpSrc[15]; nDisplayLen = fTruncate ? nMaxDisplayLen : nLen; } char * pTarget = strTarget.GetBuffer(256); if (fWackwack) { ::strcpy(pTarget, szWacks); pTarget += ::strlen(szWacks); } if (fOemName) { ::OemToCharBuff(lpSrc, pTarget, nLen); } else { ::memcpy(pTarget, lpSrc, nLen); } int n = 0; while (n < nDisplayLen) { if (fExpandChars) { if (!::IsCharAlphaNumeric(*pTarget) && !isprint(*pTarget)) { *pTarget = BADNAME_CHAR; } } ++n; ++pTarget; } if (nLen == 16) { if (fLanmanCompatible) { if (!fTruncate && nDisplayLen == nLen) { // // Back up over the 16th character // --pTarget; } // // Back up over the spaces. Then, attach the // 16th character string. // while (*(--pTarget) == ' ') /**/ ; pTarget += ::wsprintfA (++pTarget, "[%02Xh]", ch16); ++pTarget; } } else if (nLen > 16 && fTruncate) { pTarget += ::wsprintfA(pTarget, (LPCSTR)m_strEllipses); ++pTarget; } *pTarget = '\0'; strTarget.ReleaseBuffer(); return strTarget; } /*** * * CWinsadmnApp::IsValidNetBIOSName * * Purpose: * * Determine if the given netbios is valid, and pre-pend * a double backslash if not already present (and the address * is otherwise valid). * * Arguments: * * CString& strAddress Name to verify * * Returns: * * TRUE for a valid netbios name, FALSE otherwise * */ BOOL CWinsadmnApp::IsValidNetBIOSName( CString & strAddress, BOOL fLanmanCompatible, BOOL fWackwack // expand slashes if not present ) { TCHAR szWacks[] = _T("\\\\"); if (strAddress.IsEmpty()) { return FALSE; } if (strAddress[0] == _T('\\')) { if (strAddress.GetLength() < 3) { return FALSE; } if (strAddress[1] != _T('\\')) { // // One slash only? Not valid // return FALSE; } if (!fWackwack && fLanmanCompatible) { // // Don't want backslashes, but since they do exist, // remove them. // if (!::strncmp((LPCSTR)strAddress, szWacks, ::strlen(szWacks))) { strAddress = CString((LPCSTR)strAddress + ::strlen(szWacks)); } } } else { if (fWackwack) { // // Add the backslashes // strAddress = szWacks + strAddress; } } int nMaxAllowedLength = fLanmanCompatible ? LM_NAME_MAX_LENGTH : NB_NAME_MAX_LENGTH; if (fLanmanCompatible) { strAddress.MakeUpper(); } return strAddress.GetLength() <= nMaxAllowedLength + 2; } /*** * CWinsadmnApp::IsValidDomain * * Purpose: * * Determine if the given domain name address is valid, and clean * it up, if necessary * * Arguments: * * CString& strAddress Address to verify * * Returns: * * TRUE for a valid FQDN address, FALSE otherwise * */ BOOL CWinsadmnApp::IsValidDomain( CString & strDomain) { int nLen; if ((nLen = strDomain.GetLength()) != 0) { if (nLen < DOMAINNAME_LENGTH) // 255 { int i; int istr = 0; TCHAR ch; BOOL fLet_Dig = FALSE; BOOL fDot = FALSE; int cHostname = 0; for (i = 0; i < nLen; i++) { // check each character ch = strDomain[i]; BOOL fAlNum = iswalpha(ch) || iswdigit(ch); if (((i == 0) && !fAlNum) || // first letter must be a digit or a letter (fDot && !fAlNum) || // first letter after dot must be a digit or a letter ((i == (nLen - 1)) && !fAlNum) || // last letter must be a letter or a digit (!fAlNum && ( ch != _T('-') && ( ch != _T('.') && ( ch != _T('_'))))) || // must be letter, digit, - or "." (( ch == _T('.')) && ( !fLet_Dig ))) // must be letter or digit before '.' { return FALSE; } fLet_Dig = fAlNum; fDot = (ch == _T('.')); cHostname++; if ( cHostname > HOSTNAME_LENGTH ) { return FALSE; } if ( fDot ) { cHostname = 0; } } } } return TRUE; } /*** * CWinsadmnApp::IsValidIpAddress * * Purpose: * * Determine if the given IP address is valid, and clean * it up, if necessary * * Arguments: * * CString& strAddress Address to verify * * Returns: * * TRUE for a valid IP address, FALSE otherwise * */ BOOL CWinsadmnApp::IsValidIpAddress( CString & strAddress ) { if (strAddress.IsEmpty()) { return FALSE; } CIpAddress ia(strAddress); BOOL fValid = ia.IsValid(); if (fValid) { // // Fill out the IP address string for clarity // strAddress = ia; return TRUE; } return FALSE; } /*** * * CWinsadmnApp::IsValidAddress * * Purpose: * * Determine if the given address is a valid NetBIOS or * TCP/IP address, judging by the name only. Note that * validation may clean up the given string * * Arguments: * * CString& strAddress The address in question * BOOL * fIpAddress Returns TRUE if the address is an IP * address, FALSE is it's a NetBIOS name. * * Returns: * * TRUE for a valid name, FALSE otherwise. * * Notes: * * NetBIOS names not beginning with "\\" will have those characters * pre-pended, and otherwise valid IP Addresses are filled out to * 4 octets. * * Leading and trailing spaces are removed from the string. * */ BOOL CWinsadmnApp::IsValidAddress( CString& strAddress, BOOL * fIpAddress, BOOL fLanmanCompatible, BOOL fWackwack // expand netbios slashes ) { int i; // // Remove leading and trailing spaces // CleanString(strAddress); if (strAddress.IsEmpty()) { *fIpAddress = FALSE; return FALSE; } if (strAddress[0] == _T('\\')) { *fIpAddress = FALSE; return IsValidNetBIOSName(strAddress, fLanmanCompatible, fWackwack); } if (IsValidIpAddress(strAddress)) { *fIpAddress = TRUE; return TRUE; } else { *fIpAddress = FALSE; } if (IsValidDomain (strAddress)) { return TRUE; } // last chance, maybe its a NetBIOS name w/o wackwack return IsValidNetBIOSName(strAddress, fLanmanCompatible, fWackwack); /*----------------------------------------------------------- old code, being replaced. for (i=0; i < strAddress.GetLength(); ++i) { // // If a dot is encountered, we immediately assume // it's an IP address // if (strAddress[i] == _T('.')) { *fIpAddress = TRUE; return IsValidIpAddress(strAddress); } // // A non-digit (and non-period) immediately // makes us realise we have a NB name. // if (!isdigit(strAddress[i])) { *fIpAddress = FALSE; return IsValidNetBIOSName(strAddress, fLanmanCompatible, fWackwack); } } // // Having come this far without encountering a period, // we know this is a netbios name // *fIpAddress = FALSE; return IsValidNetBIOSName(strAddress, fLanmanCompatible, fWackwack); ---------------------------------------------------------------*/ } /*** * * CWinsadmnApp::ValidateNumberEditControl * * Purpose: * * Verify that the given edit control contains a valid number, otherwise * balk and set focus to it. * * Arguments: * * CEdit& edit The edit control to check * BOOL fEmptyOk If TRUE, allow blank entries * LONG lMin Minimum value to allow * LONG lMax Maximum value to allow * * Returns: * * TRUE or FALSE depending on whether validation succeeded or not. * * Notes: * * The contents of the edit control will be re-displayed after * validation, since they may have been cleaned up. * */ BOOL CWinsadmnApp::ValidateNumberEditControl( CEdit& edit, BOOL fEmptyOk, LONG lMin, LONG lMax ) { CString str; edit.GetWindowText(str); // // Kill Leading and Trailing Spaces. // CleanString(str); // // If empty is not ok, then it will fail later on. // if (str.IsEmpty() && fEmptyOk) { return TRUE; } CIntlNumber n(str); if (!n.IsValid() || ((LONG)n < lMin) || ((LONG)n > lMax)) { theApp.MessageBox(IDS_ERR_BAD_NUMBER); edit.SetFocus(); edit.SetSel(0,-1); return FALSE; } // // Re-display the number, which may have been // cleaned up in validation. // edit.SetWindowText((const CString)n); edit.UpdateWindow(); return TRUE; } BOOL CWinsadmnApp::ValidateTimeEditControl( CEdit& edit, BOOL fEmptyOk ) { CString str; edit.GetWindowText(str); // // Kill Leading and Trailing Spaces. // CleanString(str); // // If empty is not ok, then it will fail later on. // if (str.IsEmpty() && fEmptyOk) { return TRUE; } CIntlTime tm(str, CIntlTime::TFRQ_TIME_ONLY, NULL); if (!tm.IsValid()) { theApp.MessageBox(IDS_ERR_TIME_INVALID); edit.SetFocus(); edit.SetSel(0,-1); return FALSE; } // // Re-display the number, which may have been // cleaned up in validation. // edit.SetWindowText(tm.IntlFormat(CIntlTime::TFRQ_TIME_ONLY)); edit.UpdateWindow(); return TRUE; } // // Return the name of the server we're connected // to. Return the IP address if connected over ip, // and the netbios name if connected over netbios. // CString CWinsadmnApp::GetConnectedServerName() { if (m_wbdBindData.fTcpIp) { return m_iaIpAddress; } return m_strNetBIOSName; } // // Change the title on the given window. If the // window pointer is NULL, use the main application // window. // void CWinsadmnApp::SetTitle( CWnd * pWnd ) { CString strTitle; TRY { if (pWnd == NULL) { // // Setting the main title bar. Check to // make sure that there is a main app screen // visible. // ASSERT(theApp.m_pMainWnd != NULL); pWnd = theApp.m_pMainWnd; } pWnd->GetWindowText(strTitle); // // Check for existence of current title. If present, // remove it. // CString strDivider; int nPos; strDivider.LoadString(IDS_DIVIDER); if ((nPos = strTitle.Find(strDivider)) != -1) { // // Truncate to new length. // strTitle.ReleaseBuffer(nPos); } if (IsConnected()) { strTitle += strDivider; // // Append the address of the currently open // WINS server. // if (IsLocalConnection()) { CString strLocal; strLocal.LoadString(IDS_LOCAL); strTitle += strLocal; } else { strTitle += GetConnectedServerName(); } } pWnd->SetWindowText(strTitle); } CATCH_ALL(e) { theApp.MessageBox(::GetLastError()); } END_CATCH_ALL } void CWinsadmnApp::SetStatusBarText( UINT nId ) { ASSERT(m_pMainWnd != NULL); CString str; TRY { BOOL f = str.LoadString(nId) ; ASSERT(f); ((CMainFrame *)m_pMainWnd)->GetStatusBarHandle().SetWindowText(str); ((CMainFrame *)m_pMainWnd)->GetStatusBarHandle().UpdateWindow(); } CATCH_ALL(e) { theApp.MessageBox(::GetLastError()); } END_CATCH_ALL } void CWinsadmnApp::MessageBeep( UINT nType ) { ::MessageBeep(nType); } // // Get a temporary file on a remote drive // CHAR * CWinsadmnApp::RemoteTmp( CHAR * szDir, CHAR * szPrefix ) { static TCHAR sz[256]; int n = 0; while(1) { ::wsprintf (sz, _T("%s\\%s%d"), szDir, szPrefix, ++n); if (GetFileAttributes(sz) == -1) { return GetLastError() == ERROR_FILE_NOT_FOUND ? sz : NULL; } } } void CWinsadmnApp::DoImportStaticMappingsDlg( CWnd * pParentWindow ) { ASSERT(IsServiceRunning()); CString strTitle; if (!strTitle.LoadString(IDS_SELECT_STATIC_MAPPING_FILE)) { theApp.MessageBox(::GetLastError()); return; } CFileDialog dlgFile(TRUE, NULL, NULL, OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, " |*.||"); dlgFile.m_ofn.lpstrTitle = strTitle; if (dlgFile.DoModal() == IDOK) { // // If this is a local connection, we copy the file to // temporary name (the source may be on a remote drive // which is not accessible to the WINS service. // // If this is not a local connection, attempt to copy // the file to a temp name on C$ of the WINS server // // // Put up the informational dialog // CImportingDlg * pDlg = NULL; pDlg = new CImportingDlg(pParentWindow); APIERR err = 0; SetStatusBarText(IDS_STATUS_IMPORT); theApp.BeginWaitCursor(); CString strMappingFile(dlgFile.GetPathName()); do { if (IsLocalConnection()) { CString strTmpFile(_tempnam(NULL, _T("WINS"))); // // First copy file to a temporary name (since the file // could be remote), and then import and delete this file // if (!CopyFile(strMappingFile, strTmpFile, TRUE)) { err = ::GetLastError(); break; } // // Now import the temporary file, and delete the file // afterwards. // err = ImportStaticMappingsFile(strTmpFile, TRUE); } else { // // Try copying to the remote machine C: drive // CHAR szDir[1024]; ::wsprintf(szDir, "%s\\C$", (LPCSTR)GetConnectedNetBIOSName()); CHAR * pchTmp = RemoteTmp(szDir, "WINS"); if (pchTmp == NULL) { err = IDS_ERR_REMOTE_IMPORT; break; } CString strTmpFile(pchTmp); // // First copy file to a temporary name (since the file // could be remote), and then import and delete this file // if (!CopyFile(strMappingFile, strTmpFile, TRUE)) { err = ::GetLastError(); break; } CHAR * pch = strTmpFile.GetBuffer(256); // // Now replace the remote path with a local path // for the remote WINS server // while (*pch != '$') { ++pch; } *pch = ':'; --pch; CString strRemoteFile(pch); strTmpFile.ReleaseBuffer(); // // Now import the temporary file, and delete the file // afterwards. // err = ImportStaticMappingsFile(strRemoteFile, TRUE); } } while(FALSE); theApp.EndWaitCursor(); SetStatusBarText(); if (pDlg != NULL) { pDlg->Dismiss(); } if (err == ERROR_SUCCESS) { theApp.MessageBox(IDS_MSG_IMPORT, MB_ICONINFORMATION); } else { theApp.MessageBox(err); } GetFrameWnd()->GetStatistics(); } } int CWinsadmnApp::DoAddStaticMappingsDlg() { ASSERT(IsConnected()); ASSERT(IsServiceRunning()); CAddStaticMappingDlg dlgAdd; dlgAdd.DoModal(); GetFrameWnd()->GetStatistics(); return dlgAdd.QueryMappingsAdded(); } // // UI API Wrappers: // APIERR CWinsadmnApp::ConnectToWinsServer( CString strAddress, BOOL fIp, BOOL fAdd // Add to cache ) { // First attempt to bind to the new address m_wbdBindData.fTcpIp = fIp; m_wbdBindData.pPipeName = fIp ? NULL : (char *)CWinsadmnApp::lpstrPipeName; m_wbdBindData.pServerAdd = new char[strAddress.GetLength()+1]; if (m_wbdBindData.pServerAdd == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } ::lstrcpy(m_wbdBindData.pServerAdd, (LPCSTR)strAddress); if ((m_hBinding = ::WinsBind(&m_wbdBindData)) == NULL) { TRACEEOLID("Failed to bind to " << m_wbdBindData.pServerAdd); delete[] m_wbdBindData.pServerAdd; return ::GetLastError(); } // // Get the UNC name and IP address that we're currently connected to, // which also serves as a check that there really is a WINS server // at the other end. // m_iaPrimaryIpAddress = m_iaIpAddress = 0L; m_strNetBIOSName = "\\\\"; // Not provided by the API call. WINSINTF_ADD_T waWinsAddress; m_dwLastStatus = ::WinsGetNameAndAdd(&waWinsAddress, (BYTE *)m_strNetBIOSName.GetBuffer(128)+2); m_strNetBIOSName.ReleaseBuffer(); if (m_dwLastStatus != ERROR_SUCCESS) { TRACEEOLID("Failed to connect to " << m_wbdBindData.pServerAdd); DisconnectFromWinsServer(); return m_dwLastStatus; } // // If we're connected over TCPIP, regardless // of what the actual IP address is, we use // the ip address we used to connect // if (fIp) { m_iaIpAddress = (LPCTSTR)strAddress; } else { m_iaIpAddress = waWinsAddress.IPAdd; } m_iaPrimaryIpAddress = waWinsAddress.IPAdd; m_tmConnectedSince = CTime::GetCurrentTime(); #ifndef WIN32S // // Create the mutex // ASSERT(m_hmutStatistics == NULL); if ((m_hmutStatistics = ::CreateMutex(NULL, FALSE, STATMUTEXNAME)) == NULL) { MessageBox(::GetLastError()); return FALSE; } #endif // WIN32S // // Optionally add the WINS server to our cache of // "known" WINS server // if (fAdd) { m_wcWinssCache.Add(CIpNamePair( GetConnectedIpAddress(), (LPCSTR)m_strNetBIOSName+2), TRUE); } // // Determine if the connection is on the local machine // by comparing netbios names. // TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1]; DWORD dwSize = sizeof(szComputerName); if (::GetComputerName(szComputerName, &dwSize)) { // // Ignore the slashes // m_fLocalConnection = (::lstrcmpi((LPCSTR)m_strNetBIOSName+2, szComputerName)==0); } else { theApp.MessageBox(IDS_ERR_NO_COMPUTERNAME); m_fLocalConnection = FALSE; } // // Now try to get to the registry to determine access // rights. // m_cConfig.SetOwner(m_strNetBIOSName); m_nPrivilege = (m_cConfig.Touch() == ERROR_SUCCESS) ? CWinsadmnApp::PRIV_FULL : CWinsadmnApp::PRIV_READONLY; m_nServiceStatus = CWinsadmnApp::SRVC_RUNNING; return ERROR_SUCCESS; } // // Completely purge the database of all references to this WINS server // APIERR CWinsadmnApp::DeleteWinsServer( CIpNamePair * pipServer ) { WINSINTF_ADD_T WinsAdd; WinsAdd.Len = 4; WinsAdd.Type = 0; WinsAdd.IPAdd = (LONG)(pipServer->GetIpAddress()); return :: WinsDeleteWins(&WinsAdd); } // // Disconnect from current wins server // before calling this API // APIERR CWinsadmnApp::VerifyWinsServer( CIpNamePair & ipNamePair ) { if (IsConnected()) { return RPC_S_SERVER_UNAVAILABLE; } APIERR err = ERROR_SUCCESS; WINSINTF_BIND_DATA_T wbdBindData; WINSINTF_ADD_T waWinsAddress; CString strNetBIOSName; do { handle_t hBinding; // // First attempt to bind to the new address // wbdBindData.fTcpIp = ipNamePair.GetNetBIOSName().IsEmpty(); CString strAddress; if (wbdBindData.fTcpIp) { strAddress = ((CString)ipNamePair.GetIpAddress()); } else { strAddress = _T("\\\\") + ipNamePair.GetNetBIOSName(); } wbdBindData.pPipeName = wbdBindData.fTcpIp ? NULL : (char *)CWinsadmnApp::lpstrPipeName; wbdBindData.pServerAdd = new char[strAddress.GetLength()+1]; ::lstrcpy(wbdBindData.pServerAdd, (LPCSTR)strAddress); if ((hBinding = ::WinsBind(&wbdBindData)) == NULL) { TRACEEOLID("Failed to bind to " << wbdBindData.pServerAdd); err = ::GetLastError(); break; } err = ::WinsGetNameAndAdd( &waWinsAddress, (BYTE *)strNetBIOSName.GetBuffer(128)); strNetBIOSName.ReleaseBuffer(); if (err != ERROR_SUCCESS) { TRACEEOLID("Failed to connect to " << wbdBindData.pServerAdd); break; } } while(FALSE); if (err == ERROR_SUCCESS) { // // Always use the IP address used for connection // if we went over tcpip (not the address returned // by the WINS service. // if (wbdBindData.fTcpIp) { CIpNamePair ip(ipNamePair.GetIpAddress(), (LPCSTR)strNetBIOSName); ipNamePair = ip; } else { CIpNamePair ip(waWinsAddress.IPAdd, (LPCSTR)strNetBIOSName); ipNamePair = ip; } } delete[] wbdBindData.pServerAdd; return err; } APIERR CWinsadmnApp::DisconnectFromWinsServer() { ASSERT((m_hBinding != INVALID_HANDLE_VALUE) && (m_hBinding != NULL)); ::WinsUnbind(&m_wbdBindData, m_hBinding); delete[] m_wbdBindData.pServerAdd; m_hBinding = INVALID_HANDLE_VALUE; m_nServiceStatus = CWinsadmnApp::SRVC_NOT_RUNNING; if (m_hmutStatistics != NULL) { ::ReleaseMutex(m_hmutStatistics); ::CloseHandle(m_hmutStatistics); m_hmutStatistics = NULL; } return ERROR_SUCCESS; } void CWinsadmnApp::SetServiceStatus() { // // Update the service status appropriately, based on the result // of the last API call. // m_nServiceStatus = (m_dwLastStatus != EPT_S_NOT_REGISTERED && m_dwLastStatus != RPC_S_SERVER_UNAVAILABLE) ? CWinsadmnApp::SRVC_RUNNING : CWinsadmnApp::SRVC_NOT_RUNNING; } /*** * * CWinsadmnApp::GetStatistics * * Purpose: * * UI Wrapper for WINS Api call * */ APIERR CWinsadmnApp::GetStatistics( WINSINTF_RESULTS_T * pwrResults ) { #ifndef WIN32S DWORD dw = ::WaitForSingleObject(m_hmutStatistics, 2000L); if (dw != WAIT_OBJECT_0) { TRACEEOLID( "(app) Failed to get the mutex"); return ERROR_SEM_TIMEOUT; } #endif // WIN32S TRY { pwrResults->WinsStat.NoOfPnrs = 0; pwrResults->WinsStat.pRplPnrs = 0; pwrResults->NoOfWorkerThds = 1; m_dwLastStatus = ::WinsStatus(WINSINTF_E_STAT, pwrResults); if (pwrResults->WinsStat.NoOfPnrs) { ::WinsFreeMem(pwrResults->WinsStat.pRplPnrs); } } CATCH_ALL(e) { m_dwLastStatus = ::GetLastError(); } END_CATCH_ALL #ifndef WIN32S if (!::ReleaseMutex(m_hmutStatistics)) { m_dwLastStatus = ::GetLastError(); } #endif // WIN32S SetServiceStatus(); return m_dwLastStatus; } APIERR CWinsadmnApp::ClearStatistics() { m_dwLastStatus = ::WinsResetCounters(); SetServiceStatus(); return m_dwLastStatus; } APIERR CWinsadmnApp::SendTrigger( CWinsServer & ws, BOOL fPush, BOOL fPropagate ) { WINSINTF_ADD_T WinsAdd; WinsAdd.Len = 4; WinsAdd.Type = 0; WinsAdd.IPAdd = (LONG)ws.GetIpAddress(); m_dwLastStatus = ::WinsTrigger(&WinsAdd, fPush ? fPropagate ? WINSINTF_E_PUSH_PROP : WINSINTF_E_PUSH : WINSINTF_E_PULL); SetServiceStatus(); return m_dwLastStatus; } APIERR CWinsadmnApp::GetConfig( WINSINTF_RESULTS_T * pwrResults ) { pwrResults->WinsStat.NoOfPnrs = 0; pwrResults->WinsStat.pRplPnrs = NULL; pwrResults->NoOfWorkerThds = 1; m_dwLastStatus = ::WinsStatus(WINSINTF_E_CONFIG, pwrResults); SetServiceStatus(); return m_dwLastStatus; } // // Same as above, but calling the new API. // APIERR CWinsadmnApp::GetNewConfig( WINSINTF_RESULTS_NEW_T * pwrResults ) { pwrResults->WinsStat.NoOfPnrs = 0; pwrResults->WinsStat.pRplPnrs = NULL; pwrResults->NoOfWorkerThds = 1; pwrResults->pAddVersMaps = NULL; m_dwLastStatus = ::WinsStatusNew(WINSINTF_E_CONFIG, pwrResults); SetServiceStatus(); return m_dwLastStatus; } APIERR CWinsadmnApp::ImportStaticMappingsFile( CString strFile, BOOL fDelete ) { // CODEWORK:: Change this when we're UNICODE ourselves WCHAR ws[256]; ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPCSTR)strFile, -1, ws, 255); m_dwLastStatus = ::WinsDoStaticInit(ws, fDelete); // End of UNICODE SetServiceStatus(); return m_dwLastStatus; } APIERR CWinsadmnApp::DoScavenging() { m_dwLastStatus = ::WinsDoScavenging(); SetServiceStatus(); return m_dwLastStatus; } APIERR CWinsadmnApp::BackupDatabase( CString strPath, BOOL fIncremental ) { m_dwLastStatus = ::WinsBackup((unsigned char *)(LPCSTR)strPath, (short)fIncremental); SetServiceStatus(); return m_dwLastStatus; } // // Only works on a local WINS, with the service not running. // APIERR CWinsadmnApp::RestoreDatabase( CString strPath ) { APIERR err; ASSERT(!IsConnected()); ASSERT(HasStoppedWins()); err = ::WinsRestore((unsigned char *)(LPCSTR)strPath); return err; } // // Register a static mapping // APIERR CWinsadmnApp::AddMapping( int nType, int nCount, CMultipleIpNamePair& mipnp, BOOL fEdit // Editing existing mapping? ) { WINSINTF_RECORD_ACTION_T RecAction; PWINSINTF_RECORD_ACTION_T pRecAction; ASSERT(nType >= WINSINTF_E_UNIQUE && nType <= WINSINTF_E_MULTIHOMED); RecAction.TypOfRec_e = nType; RecAction.Cmd_e = WINSINTF_E_INSERT; RecAction.pAdd = NULL; RecAction.pName = NULL; pRecAction = &RecAction; if (nType == WINSINTF_E_UNIQUE || nType == WINSINTF_E_NORM_GROUP) { RecAction.NoOfAdds = 1; RecAction.Add.IPAdd = (LONG)mipnp.GetIpAddress(); RecAction.Add.Type = 0; RecAction.Add.Len = 4; } else { ASSERT(nCount <= WINSINTF_MAX_MEM); RecAction.pAdd = (WINSINTF_ADD_T *)::WinsAllocMem( sizeof(WINSINTF_ADD_T) * nCount); if (RecAction.pAdd == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } RecAction.NoOfAdds = nCount; int i; for (i = 0; i < nCount; ++i) { (RecAction.pAdd+i)->IPAdd = (LONG)mipnp.GetIpAddress(i); (RecAction.pAdd+i)->Type = 0; (RecAction.pAdd+i)->Len = 4; } RecAction.NodeTyp = WINSINTF_E_PNODE; } RecAction.fStatic = TRUE; // // Don't copy the beginning slashes when adding. // int nLen = mipnp.GetNetBIOSNameLength(); // // Must have at least enough room for 16 character string // RecAction.pName = (LPBYTE)::WinsAllocMem(__max(nLen+1, 17)); if (RecAction.pName == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } if (fEdit) { // // No need to convert if already existing in the database. // ::memcpy((char *)RecAction.pName, (char *)(LPCSTR)mipnp.GetNetBIOSName(), nLen+1 ); } else { ::CharToOemBuff((LPCSTR)mipnp.GetNetBIOSName(), (char *)RecAction.pName, nLen+1 ); } if (nLen < 16) { if (nType == WINSINTF_E_SPEC_GROUP) { ::memset(RecAction.pName+nLen, (int)' ',16-nLen); RecAction.pName[15] = 0x1C; RecAction.pName[16] = '\0'; RecAction.NameLen = nLen = 16; m_dwLastStatus = ::WinsRecordAction(&pRecAction); } else if (nType == WINSINTF_E_NORM_GROUP) { ::memset(RecAction.pName+nLen, (int)' ',16-nLen); RecAction.pName[15] = 0x1E; RecAction.pName[16] = '\0'; RecAction.NameLen = nLen = 16; m_dwLastStatus = ::WinsRecordAction(&pRecAction); } else { // // NOTICE:: When lanman compatible, the name is added // three times - once each as worksta, server // and messenger. This will change when we allow // different 16th bytes to be set. // if (m_wpPreferences.IsLanmanCompatible() && !fEdit) { BYTE ab[] = { 0x00, 0x03, 0x20 }; ::memset(RecAction.pName + nLen, (int)' ', 16-nLen); int i; for (i = 0; i < sizeof(ab) / sizeof(ab[0]); ++i) { *(RecAction.pName+15) = ab[i]; *(RecAction.pName+16) = '\0'; RecAction.NameLen = nLen = 16; pRecAction = &RecAction; m_dwLastStatus = ::WinsRecordAction(&pRecAction); if (m_dwLastStatus != ERROR_SUCCESS) { break; } } } else { ::memset(RecAction.pName+nLen, (int)'\0',16-nLen); *(RecAction.pName+15) = 0x20; *(RecAction.pName+16) = '\0'; RecAction.NameLen = nLen; m_dwLastStatus = ::WinsRecordAction(&pRecAction); } } } else { RecAction.NameLen = nLen; m_dwLastStatus = ::WinsRecordAction(&pRecAction); } if (RecAction.pName != NULL); { ::WinsFreeMem(RecAction.pName); } if (RecAction.pAdd != NULL); { ::WinsFreeMem(RecAction.pAdd); } ::WinsFreeMem(pRecAction); SetServiceStatus(); return m_dwLastStatus; } APIERR CWinsadmnApp::DeleteMapping ( CMapping& mapping ) { WINSINTF_RECORD_ACTION_T RecAction; PWINSINTF_RECORD_ACTION_T pRecAction; ASSERT(mapping.GetMappingType() >= WINSINTF_E_UNIQUE && mapping.GetMappingType() <= WINSINTF_E_MULTIHOMED); RecAction.TypOfRec_e = mapping.GetMappingType(); RecAction.Cmd_e = WINSINTF_E_DELETE; RecAction.State_e = WINSINTF_E_DELETED; RecAction.fStatic = TRUE; RecAction.pName = NULL; RecAction.pAdd = NULL; pRecAction = &RecAction; RecAction.pName = (LPBYTE)::WinsAllocMem(mapping.GetNetBIOSName().GetLength()+1); if (RecAction.pName == NULL) { return(::GetLastError()); } ::lstrcpy((char *)(LPCSTR)RecAction.pName, (char *)(LPCSTR)mapping.GetNetBIOSName()); RecAction.NameLen = mapping.GetNetBIOSNameLength() ? mapping.GetNetBIOSNameLength() : ::lstrlen((LPCSTR)RecAction.pName); m_dwLastStatus = ::WinsRecordAction(&pRecAction); if (RecAction.pName != NULL); { ::WinsFreeMem(RecAction.pName); } if (RecAction.pAdd != NULL); { ::WinsFreeMem(RecAction.pAdd); } ::WinsFreeMem(pRecAction); SetServiceStatus(); return m_dwLastStatus; } BOOL CWinsadmnApp::MatchIpAddress ( PADDRESS_MASK pMask, LONG lIpAddress ) { ASSERT(pMask != NULL); LONG l1 = pMask->lIpMask; int i; for (i=0; i < 4; ++i) { if (!(pMask->bMask & 1<lpNetBIOSName != NULL); // // Match NetBIOSName // if(*pMask->lpNetBIOSName) { LPSTR lp1 = (LPSTR)pMask->lpNetBIOSName; LPSTR lp2 = (LPSTR)pRow->pName; while ((*lp1 != TEXT('\0')) && (*lp2 != TEXT('\0'))) { if (*lp1 == '*') { break; } if (*lp1 != '?' && *lp1 != *lp2) { return FALSE; } ++lp1; ++lp2; } if ((*lp1 != '*') && (*lp1 != TEXT('\0') || *lp2 != TEXT('\0'))) { return FALSE; } } // // Match IP Address(es) // if (pMask->bMask != 0xFF) { // // Special case for multiple address // mappings // if (pRow->NoOfAdds==0) { return MatchIpAddress(pMask, pRow->Add.IPAdd); } else { // // The unit matches if any of the IP addresses // matches // int j; int k = 1; for (j=0; j < (int)pRow->NoOfAdds/2; ++j) { if (MatchIpAddress(pMask, (pRow->pAdd+k)->IPAdd)) { return TRUE; } ++k; ++k; } return FALSE; } } return TRUE; } BOOL CWinsadmnApp::IsValidNBMask( CString & strNetBIOSNameMask ) { if (!IsValidNetBIOSName(strNetBIOSNameMask, theApp.m_wpPreferences.IsLanmanCompatible(), FALSE)) { return FALSE; } // // Any characters after the * are not allowed. // int i = strNetBIOSNameMask.Find('*'); if (i == -1) strNetBIOSNameMask += "*"; i = strNetBIOSNameMask.Find('*'); if ((i != -1) && (i!=strNetBIOSNameMask.GetLength()-1)) { return FALSE; } return TRUE; } BOOL CWinsadmnApp::IsValidDNMask( CString & strDomainNameMask ) { if (!IsValidDomain(strDomainNameMask)) { return FALSE; } // // Any characters after the * are not allowed. // int i = strDomainNameMask.Find('*'); if (i == -1) strDomainNameMask += "*"; i = strDomainNameMask.Find('*'); if ((i != -1) && (i!=strDomainNameMask.GetLength()-1)) { return FALSE; } return TRUE; } void CWinsadmnApp::GetFilterString( PADDRESS_MASK pMask, CString& str ) { if (pMask != NULL) { TCHAR sz[256]; // // Mask's are stored as OEM strings // ::OemToCharBuff(pMask->lpNetBIOSName, sz, ::lstrlen(pMask->lpNetBIOSName) + 1 ); LONG l = pMask->lIpMask; str = "["; str += sz; str += "]/["; if (pMask->bMask != 0xFF) { int i; for (i=0; i < 4; ++i) { if (pMask->bMask & 1<= SRVC_NOT_RUNNING && nService <= SRVC_PAUSED); SC_HANDLE hService; SC_HANDLE hScManager; hScManager = ::OpenSCManager(GetConnectedNetBIOSName(), NULL, SC_MANAGER_ALL_ACCESS); if (hScManager == NULL) { return ::GetLastError(); } hService = OpenService(hScManager, "WINS", SERVICE_ALL_ACCESS); if (hService == NULL) { return ::GetLastError(); } SERVICE_STATUS ss; DWORD dwControl; BOOL fSuccess; switch(nService) { case SRVC_NOT_RUNNING: dwControl = SERVICE_CONTROL_STOP; fSuccess = ::ControlService(hService, dwControl, &ss); break; case SRVC_PAUSED: dwControl = SERVICE_CONTROL_PAUSE; fSuccess = ::ControlService(hService, dwControl, &ss); break; case SRVC_RUNNING: if (m_nServiceStatus == SERVICE_PAUSED) { dwControl = SERVICE_CONTROL_CONTINUE; fSuccess = ::ControlService(hService, dwControl, &ss); } else { fSuccess = ::StartService(hService, 0, NULL); } } ::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager); if (!fSuccess) { return ::GetLastError(); } m_nServiceStatus = nService; return ERROR_SUCCESS; } // // CWinsadmnApp commands // // Display the standard about box // void CWinsadmnApp::OnAppAbout() { HMODULE hMod; LPFNSHELLABOUT lpfn; if (hMod = ::LoadLibrary("SHELL32")) { if (lpfn = (LPFNSHELLABOUT)::GetProcAddress(hMod, "ShellAboutA")) { (*lpfn)(m_pMainWnd->m_hWnd, (LPSTR)m_pszAppName, (LPSTR)m_pszAppName, LoadIcon(IDR_MAINFRAME)); } ::FreeLibrary(hMod); } else { ::MessageBeep( MB_ICONEXCLAMATION ); } } // // The one and only CWinsadmnApp object // CWinsadmnApp NEAR theApp;