// ClientConsoleDoc.cpp : implementation of the CClientConsoleDoc class // #include "stdafx.h" #define __FILE_ID__ 2 #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif extern CClientConsoleApp theApp; ///////////////////////////////////////////////////////////////////////////// // CClientConsoleDoc IMPLEMENT_DYNCREATE(CClientConsoleDoc, CDocument) BEGIN_MESSAGE_MAP(CClientConsoleDoc, CDocument) //{{AFX_MSG_MAP(CClientConsoleDoc) // NOTE - the ClassWizard will add and remove mapping macros here. // DO NOT EDIT what you see in these blocks of generated code! //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CClientConsoleDoc construction/destruction // // Static members: // HANDLE CClientConsoleDoc::m_hShutdownEvent = NULL; BOOL CClientConsoleDoc::m_bShuttingDown = FALSE; CClientConsoleDoc::CClientConsoleDoc() : m_bRefreshingServers (FALSE), m_bWin9xPrinterFormat(FALSE) {} CClientConsoleDoc::~CClientConsoleDoc() { // // The list of servers is not freed and servers and their folders are not deleted. // The background threads may still be alive and use the CServerNode and CFolder objects. // The main thread doesn’t wait for the background threads termination to prevent application hanging. // if (m_hShutdownEvent) { CloseHandle (m_hShutdownEvent); m_hShutdownEvent = NULL; } } DWORD CClientConsoleDoc::Init () /*++ Routine name : CClientConsoleDoc::Init Routine description: Initializes document events and maps Author: Eran Yariv (EranY), Feb, 2000 Arguments: Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("CClientConsoleDoc::Init"), dwRes); // // Create the shutdown event. This event will be signaled when the app is // about to quit. // ASSERTION (NULL == m_hShutdownEvent); m_hShutdownEvent = CreateEvent (NULL, // No security TRUE, // Manual reset FALSE, // Starts clear NULL); // Unnamed if (NULL == m_hShutdownEvent) { dwRes = GetLastError (); CALL_FAIL (STARTUP_ERR, TEXT("CreateEvent"), dwRes); PopupError (dwRes); return dwRes; } // // Init the map of notification messages from the servers // dwRes = CServerNode::InitMsgsMap (); if (ERROR_SUCCESS != dwRes) { CALL_FAIL (MEM_ERR, TEXT("CServerNode::InitMsgsMap"), dwRes); PopupError (dwRes); return dwRes; } ASSERTION (ERROR_SUCCESS == dwRes); return dwRes; } // CClientConsoleDoc::Init BOOL CClientConsoleDoc::OnNewDocument() { BOOL bRes = FALSE; DBG_ENTER(TEXT("CClientConsoleDoc::OnNewDocument"), bRes); if (!CDocument::OnNewDocument()) { return bRes; } if(theApp.IsCmdLineSingleServer()) { // // get command line server name // try { m_cstrSingleServer = theApp.GetCmdLineSingleServerName(); } catch (...) { CALL_FAIL (MEM_ERR, TEXT("CString::operator ="), ERROR_NOT_ENOUGH_MEMORY); PopupError (ERROR_NOT_ENOUGH_MEMORY); return bRes; } } DWORD dwRes = Init (); if (ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("CClientConsoleDoc::Init"), dwRes); return bRes; } bRes = TRUE; return bRes; } ///////////////////////////////////////////////////////////////////////////// // CClientConsoleDoc serialization void CClientConsoleDoc::Serialize(CArchive& ar) { if (ar.IsStoring()) { // TODO: add storing code here } else { // TODO: add loading code here } } ///////////////////////////////////////////////////////////////////////////// // CClientConsoleDoc diagnostics #ifdef _DEBUG void CClientConsoleDoc::AssertValid() const { CDocument::AssertValid(); } void CClientConsoleDoc::Dump(CDumpContext& dc) const { CDocument::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CClientConsoleDoc commands DWORD CClientConsoleDoc::AddServerNode ( LPCTSTR lpctstrServer ) /*++ Routine name : CClientConsoleDoc::AddServerNode Routine description: Adds a new server node to the servers list and initializes it Author: Eran Yariv (EranY), Feb, 2000 Arguments: lpctstrServer [in] - Server name Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("CClientConsoleDoc::AddServerNode"), dwRes, TEXT("%s"), lpctstrServer); CServerNode *pServerNode = NULL; // // Create the new server node // try { pServerNode = new CServerNode; } catch (...) { dwRes = ERROR_NOT_ENOUGH_MEMORY; CALL_FAIL (MEM_ERR, TEXT ("new CServerNode"), dwRes); PopupError (dwRes); return dwRes; } // // Init the server // dwRes = pServerNode->Init (lpctstrServer); if (ERROR_SUCCESS != dwRes) { pServerNode->Destroy (); PopupError (dwRes); return dwRes; } // // Enter the (initialized) node at the end of the list // try { m_ServersList.push_back (pServerNode); } catch (...) { dwRes = ERROR_NOT_ENOUGH_MEMORY; CALL_FAIL (MEM_ERR, TEXT("list::push_back"), dwRes); PopupError (dwRes); pServerNode->Destroy (); return dwRes; } pServerNode->AttachFoldersToViews(); pServerNode->RefreshState(); CMainFrame *pFrm = GetFrm(); if (!pFrm) { // // Shutdown in progress // return dwRes; } CLeftView* pLeftView = pFrm->GetLeftView(); ASSERTION(pLeftView); CFolderListView* pListView = pLeftView->GetCurrentView(); if(NULL != pListView) { // // refresh current folder // FolderType type = pListView->GetType(); CFolder* pFolder = pServerNode->GetFolder(type); ASSERTION(pFolder); pFolder->SetVisible(); } return dwRes; } // CClientConsoleDoc::AddServerNode DWORD CClientConsoleDoc::RefreshServersList() /*++ Routine name : CClientConsoleDoc::RefreshServersList Routine description: Refreshes the list of servers Author: Eran Yariv (EranY), Jan, 2000 Arguments: None. Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DWORD dwIndex; PRINTER_INFO_2 *pPrinterInfo2 = NULL; DWORD dwNumPrinters; CServerNode* pServerNode; DBG_ENTER(TEXT("CClientConsoleDoc::RefreshServersList"), dwRes); // // Prevent a new servers refresh request // if(m_bRefreshingServers ) { return dwRes; } m_bRefreshingServers = TRUE; if (m_cstrSingleServer.IsEmpty ()) { SetAllServersInvalid(); // // Working in a multiple-servers mode (normal mode) // Enumerate the list of printers available on the system // dwRes = GetPrintersInfo(pPrinterInfo2, dwNumPrinters); if(ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("GetPrintersInfo"), dwRes); goto exit; } // // Iterate the printers // for (dwIndex=0; dwIndex < dwNumPrinters; dwIndex++) { if(pPrinterInfo2[dwIndex].pDriverName) { if (_tcscmp(pPrinterInfo2[dwIndex].pDriverName, FAX_DRIVER_NAME)) { // // This printer does not use the Fax Server driver // continue; } } // // Init the node's share and server name // if( (NULL == pPrinterInfo2[dwIndex].pShareName || 0 == _tcslen(pPrinterInfo2[dwIndex].pShareName)) && (NULL == pPrinterInfo2[dwIndex].pServerName || 0 == _tcslen(pPrinterInfo2[dwIndex].pServerName))) { // // On Win9x machine, the share name and server name are NULL // or empty string but the // port is valid and composed of \\servername\sharename // m_bWin9xPrinterFormat = TRUE; if ((_tcsclen(pPrinterInfo2[dwIndex].pPortName) >= 5) && (_tcsncmp(pPrinterInfo2[dwIndex].pPortName, TEXT("\\\\"), 2) == 0)) { // // Port name is long enough and starts with "\\" // TCHAR* pServerStart = _tcsninc(pPrinterInfo2[dwIndex].pPortName,2); TCHAR* pShareStart = _tcschr (pServerStart, TEXT('\\')); if (pShareStart) { // // Share was found after the server name. // Seperate server from share and advance share name // TCHAR* ptcTmp = pShareStart; pShareStart = _tcsinc(pShareStart); *ptcTmp = TEXT('\0'); pPrinterInfo2[dwIndex].pShareName = pShareStart; pPrinterInfo2[dwIndex].pServerName = pServerStart; } } } pServerNode = FindServerByName(pPrinterInfo2[dwIndex].pServerName); if(NULL == pServerNode) { // // Create new server node // dwRes = AddServerNode (pPrinterInfo2[dwIndex].pServerName); if (ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("AddServerNode"), dwRes); goto exit; } } else { // // the server node already exists // pServerNode->SetValid(TRUE); } } // End of printers loop dwRes = RemoveAllInvalidServers(); if (ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("RemoveAllInvalidServers"), dwRes); goto exit; } } else { // // Working in a single server mode (server name in m_cstrSingleServer). // Create new server node. // int nSize = m_ServersList.size(); ASSERTION(0 == nSize || 1 == nSize); if(0 == nSize) { dwRes = AddServerNode (m_cstrSingleServer); if (ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("AddServerNode"), dwRes); goto exit; } } else { ASSERTION(FindServerByName(m_cstrSingleServer)); } } ASSERTION (ERROR_SUCCESS == dwRes); exit: SAFE_DELETE_ARRAY (pPrinterInfo2); // // Enable a new servers refresh request // m_bRefreshingServers = FALSE; return dwRes; } // CClientConsoleDoc::RefreshServersList void CClientConsoleDoc::OnCloseDocument() { DBG_ENTER(TEXT("CClientConsoleDoc::OnCloseDocument")); // // Signal the event telling all our thread the app. is shutting down // SetEvent (m_hShutdownEvent); m_bShuttingDown = TRUE; CDocument::OnCloseDocument(); } void CClientConsoleDoc::ClearServersList() /*++ Routine name : CClientConsoleDoc::ClearServersList Routine description: Clears the list of servers Author: Eran Yariv (EranY), Jan, 2000 Arguments: Return Value: None. --*/ { DBG_ENTER(TEXT("CClientConsoleDoc::ClearServersList")); for (SERVERS_LIST::iterator it = m_ServersList.begin(); it != m_ServersList.end(); ++it) { CServerNode *pServerNode = *it; pServerNode->Destroy (); } m_ServersList.clear (); } // CClientConsoleDoc::ClearServersList void CClientConsoleDoc::SetAllServersInvalid() { DBG_ENTER(TEXT("CClientConsoleDoc::SetAllServersInvalid")); CServerNode *pServerNode; for (SERVERS_LIST::iterator it = m_ServersList.begin(); it != m_ServersList.end(); ++it) { pServerNode = *it; pServerNode->SetValid(FALSE); } } DWORD CClientConsoleDoc::RemoveServerNode( CServerNode* pServer ) /*++ Routine name : CClientConsoleDoc::RemoveServerNode Routine description: remove the server from the servers list and from the tree view Author: Alexander Malysh (AlexMay), Mar, 2000 Arguments: pServer [in] - server node Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("CClientConsoleDoc::RemoveServerNode"), dwRes); ASSERTION(pServer); dwRes = pServer->InvalidateSubFolders(TRUE); if(ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("CServerNode::InvalidateSubFolders"), dwRes); return dwRes; } // // remove the server node from the list // try { m_ServersList.remove(pServer); } catch(...) { dwRes = ERROR_NOT_ENOUGH_MEMORY; CALL_FAIL (MEM_ERR, TEXT("list::remove"), dwRes); return dwRes; } // // delete the server node object // pServer->Destroy(); return dwRes; } DWORD CClientConsoleDoc::RemoveAllInvalidServers() { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("CClientConsoleDoc::RemoveAllInvalidServers"), dwRes); BOOL bSrvFound; CServerNode *pServerNode; while(TRUE) { // // find invalid server node // bSrvFound = FALSE; for (SERVERS_LIST::iterator it = m_ServersList.begin(); it != m_ServersList.end(); ++it) { pServerNode = *it; if(!pServerNode->IsValid()) { bSrvFound = TRUE; break; } } if(bSrvFound) { // // remove invalid server node // dwRes = RemoveServerNode(pServerNode); if(ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("RemoveServerNode"), dwRes); break; } } else { break; } } return dwRes; } CServerNode* CClientConsoleDoc::FindServerByName( LPCTSTR lpctstrServer ) /*++ Routine name : CClientConsoleDoc::FindServerByName Routine description: find CServerNode by machine name Author: Alexander Malysh (AlexMay), Mar, 2000 Arguments: lpctstrServer [in] - machine name Return Value: CServerNode* --*/ { CServerNode *pServerNode = NULL; CServerNode *pResultNode = NULL; for (SERVERS_LIST::iterator it = m_ServersList.begin(); it != m_ServersList.end(); ++it) { pServerNode = *it; if(pServerNode->Machine().Compare(lpctstrServer ? lpctstrServer : TEXT("")) == 0) { pResultNode = pServerNode; break; } } return pResultNode; } void CClientConsoleDoc::SetInvalidFolder( FolderType type ) /*++ Routine name : CClientConsoleDoc::InvalidateFolder Routine description: invalidate specific folder content Author: Alexander Malysh (AlexMay), Apr, 2000 Arguments: type [in] - folder type Return Value: --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("CClientConsoleDoc::InvalidateFolder")); CFolder* pFolder; CServerNode* pServerNode; for (SERVERS_LIST::iterator it = m_ServersList.begin(); it != m_ServersList.end(); ++it) { pServerNode = *it; pFolder = pServerNode->GetFolder(type); ASSERTION(pFolder); if (pFolder) { pFolder->SetInvalid(); } } } void CClientConsoleDoc::ViewFolder( FolderType type ) /*++ Routine name : CClientConsoleDoc::ViewFolder Routine description: refresh specific folder in all servers Author: Alexander Malysh (AlexMay), Apr, 2000 Arguments: type [in] - folder type Return Value: None. --*/ { DBG_ENTER(TEXT("CClientConsoleDoc::ViewFolder")); CFolder* pFolder; CServerNode *pServerNode; for (SERVERS_LIST::iterator it = m_ServersList.begin(); it != m_ServersList.end(); ++it) { pServerNode = *it; pFolder = pServerNode->GetFolder(type); ASSERTION(pFolder); pFolder->SetVisible(); } } BOOL CClientConsoleDoc::CanReceiveNow () /*++ Routine name : CClientConsoleDoc::CanReceiveNow Routine description: Can the user apply the 'Recieve now' option? Author: Eran Yariv (EranY), Mar, 2001 Arguments: Return Value: TRUE if the user apply the 'Recieve now' option, FALSE otherwise. --*/ { BOOL bEnable = FALSE; // // Locate the local fax server node // CServerNode* pServerNode = FindServerByName (NULL); if (pServerNode) { if(pServerNode->IsOnline() && pServerNode->CanReceiveNow()) { bEnable = TRUE; } } return bEnable; } // CClientConsoleDoc::CanReceiveNow BOOL CClientConsoleDoc::IsSendFaxEnable() /*++ Routine name : CClientConsoleDoc::IsSendFaxEnable Routine description: does user anable to send fax Author: Alexander Malysh (AlexMay), Apr, 2000 Arguments: Return Value: TRUE if anable send fax, FALSE otherwise. --*/ { BOOL bEnable = FALSE; CServerNode* pServerNode; for (SERVERS_LIST::iterator it = m_ServersList.begin(); it != m_ServersList.end(); ++it) { pServerNode = *it; if(pServerNode->IsOnline() && pServerNode->CanSendFax()) { bEnable = TRUE; break; } } return bEnable; } int CClientConsoleDoc::GetFolderDataCount( FolderType type ) /*++ Routine name : CClientConsoleDoc::GetFolderDataCount Routine description: get total message number in specific folder from all servers Author: Alexander Malysh (AlexMay), Apr, 2000 Arguments: type [in] - folder type Return Value: message number --*/ { int nCount=0; CFolder* pFolder; CServerNode* pServerNode; for (SERVERS_LIST::iterator it = m_ServersList.begin(); it != m_ServersList.end(); ++it) { pServerNode = *it; pFolder = pServerNode->GetFolder(type); nCount += pFolder->GetDataCount(); } return nCount; } BOOL CClientConsoleDoc::IsFolderRefreshing( FolderType type ) /*++ Routine name : CClientConsoleDoc::IsFolderRefreshing Routine description: if one of specific folders is refreshing Author: Alexander Malysh (AlexMay), Apr, 2000 Arguments: type [TBD] - folder type Return Value: TRUE if one of specific folders is refreshing, FALSE otherwise. --*/ { CFolder* pFolder; CServerNode* pServerNode; for (SERVERS_LIST::iterator it = m_ServersList.begin(); it != m_ServersList.end(); ++it) { pServerNode = *it; pFolder = pServerNode->GetFolder(type); if (!pFolder) { DBG_ENTER(TEXT("CClientConsoleDoc::IsFolderRefreshing")); ASSERTION_FAILURE; } if(pFolder->IsRefreshing()) { return TRUE; } } return FALSE; }