|
|
/*****************************************************************************\
* MODULE: inetpp.c * * The module contains routines for handling the INETPP functionality. Use * of these routines require the locking/unlocking of a critical-section * to maninpulate the INIMONPORT list. All internal routines assume the * crit-sect is locked prior to executing. CheckMonCrit() is a debugging * call to verify the monitor-crit-sect is locked. * * NOTE: Each of the Inetmon* calls must be protected by the global-crit-sect. * If a new routine is added to this module which is to be called from * another module, be sure to include the call to (semCheckCrit), so * that the debug-code can catch unprotected access. * * Copyright (C) 1996-1997 Microsoft Corporation * Copyright (C) 1996-1997 Hewlett Packard * * History: * 07-Oct-1996 HWP-Guys Initiated port from win95 to winNT * 14-Nov-1997 ChrisWil Added local-spooling functionality. * 10-Jul-1998 WeihaiC Change Authentication Dialog Code * \*****************************************************************************/
#include "precomp.h"
#include "priv.h"
CInetMon::CInetMon () { // Initialize the monitor-port-list.
//
m_pPortList = (PINIMONPORTLIST)memAlloc(sizeof(INIMONPORTLIST));
m_bValid = (m_pPortList != NULL); }
CInetMon::~CInetMon () { }
/*****************************************************************************\
* _inet_validate_portname (Local Routine) * * Validate the portname. * * NOTE: If this check becomes more rigorous, it must account for the (%) * character (escape). * \*****************************************************************************/ BOOL CInetMon::_inet_validate_portname( LPCTSTR lpszPortName) { if (lpszPortName && (*lpszPortName)) return TRUE;
DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : _inet_validate_portname : Invalid Name"))); SetLastError(ERROR_INVALID_NAME);
return FALSE; }
/*****************************************************************************\
* _inet_find_port (Local Routine) * * Locates the entry in the list where the port-name resides. Return the * full entry-type (INIMONPORT) for the location. * \*****************************************************************************/ PCINETMONPORT CInetMon::_inet_find_port( LPCTSTR lpszPortName) { PCINETMONPORT pIniPort;
pIniPort = m_pPortList->pIniFirstPort;
while (pIniPort && lstrcmpi(lpszPortName, pIniPort->m_lpszName)) pIniPort = pIniPort->m_pNext;
return pIniPort; }
/*****************************************************************************\
* _inet_create_port (Local Routine) * * Create a new port data structure and link into the list. This routine * assumes that the Crit is held. * * This routine also assumes the pszPortName is a valid http:// format.
* \*****************************************************************************/ PCINETMONPORT CInetMon::_inet_create_port( LPCTSTR lpszPortName, PCPORTMGR pPortMgr) { PCINETMONPORT pIniPort; PCINETMONPORT pPort; BOOL bRet = FALSE;
if ((pIniPort = new CInetMonPort (lpszPortName, g_szLocalPort, pPortMgr)) && pIniPort->bValid ()) {
// Set the link. If this is the first port added, the
// we set the global variable.
//
if (pPort = m_pPortList->pIniFirstPort) {
while (pPort->GetNext()) pPort = pPort->GetNext();
pPort->SetNext (pIniPort);
} else {
m_pPortList->pIniFirstPort = pIniPort; }
bRet = TRUE; }
if (!bRet) {
if (pIniPort) { delete pIniPort; pIniPort = NULL; } }
return pIniPort; }
/*****************************************************************************\
* _inet_delete_port (Local Routine) * * Free a port data structure that is no longer needed. * \*****************************************************************************/ BOOL CInetMon::_inet_delete_port( LPCTSTR lpszPortName) { PCINETMONPORT pIniPort; PCINETMONPORT pPrvPort; BOOL bRet = FALSE;
// Keep track of our previous/current entries, so that
// we can remove the specified port.
//
pIniPort = m_pPortList->pIniFirstPort;
while (pIniPort && lstrcmpi(pIniPort->m_lpszName, lpszPortName)) {
pPrvPort = pIniPort; pIniPort = pIniPort->GetNext (); }
// If the PortName is found, then delete it.
//
if (pIniPort) {
if (pIniPort->m_cRef > 0 && pIniPort->m_hTerminateEvent) { // To tell spooling thread to terminate
//
SetEvent (pIniPort->m_hTerminateEvent);
semSafeLeaveCrit(pIniPort); //
// Leave the critical section so that the spooling thread can decrease the ref count
//
Sleep (250);
semSafeEnterCrit (pIniPort);
}
// Only allow this port to be deleted if the reference count
// is at zero.
//
if (pIniPort->m_cRef == 0) { pIniPort->m_bDeletePending = TRUE; //
// Remove the pointer from the list
//
// If this is our first-port then we need to handle
// differently as we keep a global-pointer to this.
//
if (pIniPort == m_pPortList->pIniFirstPort) { m_pPortList->pIniFirstPort = pIniPort->GetNext(); } else { pPrvPort->SetNext(pIniPort->GetNext()); } // We only free the memeory if there are no open handles
//
if (pIniPort->m_cPrinterRef == 0) { DBG_MSG(DBG_LEV_INFO, (TEXT("Info: pIniPort Freed %p."), pIniPort));
delete pIniPort; } bRet = TRUE;
} else {
DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: _inet_delete_port: Port in use: Name(%s)"), lpszPortName)); SetLastError(ERROR_BUSY); }
} else {
DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: _inet_delete_port: Unrecognized PortName: Name(%s)"), lpszPortName)); SetLastError(ERROR_UNKNOWN_PORT); }
return bRet; }
/*****************************************************************************\
* _inet_is_xcv_open * * Check whether it is a XCV Open * \*****************************************************************************/ BOOL CInetMon::_inet_is_xcv_open ( LPCTSTR lpszPortName, LPTSTR *ppszServerName, LPTSTR *ppszRealPortName, LPBOOL pbXcv) { static CONST TCHAR cchSlash = _T ('\\'); static CONST TCHAR cszXcvPort[] = _T (",XcvPort "); static CONST DWORD cdwXcvPortLen = (sizeof (cszXcvPort) / sizeof (TCHAR)) - 1; BOOL bRet = TRUE; LPCTSTR pServerStart = NULL; LPTSTR pServerEnd = NULL; LPTSTR pszServerName = NULL; LPTSTR pszRealPortName = NULL;
// "\\Server\,XcvPort Object_" */
DWORD dwLen = lstrlen (lpszPortName); *pbXcv = FALSE;
if (dwLen > cdwXcvPortLen + 1) { if (lpszPortName[0] == _T (',')) { // No Server
pServerEnd = (LPTSTR) lpszPortName; } else if (lpszPortName[0] == cchSlash && lpszPortName[1] == cchSlash) {
pServerStart = lpszPortName + 2; if (pServerEnd = _tcschr (pServerStart, cchSlash)) pServerEnd ++; } else { return bRet; }
if (pServerEnd && ! _tcsncmp (pServerEnd, cszXcvPort, cdwXcvPortLen)) {
LPCTSTR pPortStart = pServerEnd + cdwXcvPortLen;
if (pServerStart) { pszServerName = new TCHAR [(pServerEnd - 1) - pServerStart + 1]; if (!pszServerName) { bRet = FALSE; } else { _tcsncpy (pszServerName, pServerStart, pServerEnd - 1 - pServerStart); pszServerName[pServerEnd - 1 - pServerStart] = 0; } } if (bRet) { pszRealPortName = new TCHAR [lstrlen (pPortStart) + 1];
if (!pszRealPortName) bRet = FALSE; else { lstrcpy (pszRealPortName, pPortStart); *pbXcv = TRUE; } }
if (!bRet) { if (pszServerName) { delete [] pszServerName; pszServerName = NULL; } }
*ppszServerName = pszServerName; *ppszRealPortName = pszRealPortName;
}
}
return bRet; }
PCINETMONPORT CInetMon::InetmonOpenPort( LPCTSTR lpszPortName, PBOOL pbXcv) { PCINETMONPORT pIniPort = NULL; PCPORTMGR pPortMgr = NULL; DWORD dwLE;
*pbXcv = FALSE;
semCheckCrit();
if (_inet_validate_portname(lpszPortName)) { #ifdef WINNT32
// Let's first look to see if it is a XCV call
LPTSTR pszServerName = NULL; LPTSTR pszRealPortName = NULL; BOOL bXcv;
if (_inet_is_xcv_open (lpszPortName, &pszServerName, &pszRealPortName, &bXcv) && bXcv) {
if (pIniPort = _inet_find_port(pszRealPortName)) { if (!pIniPort->m_bDeletePending) { // The refrernce to the iniport is not changed, since the client may open a XCV handle
// to delete the port
//
*pbXcv = TRUE; } else { DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : InetmonOpenPort (XCV) : Open deleted port: Port(%s)"), lpszPortName)); SetLastError(ERROR_INVALID_NAME); }
// This is a valid XcvOpen
if (pszServerName) { delete [] pszServerName; } if (pszRealPortName) { delete [] pszRealPortName; } return pIniPort; } }
#endif
// Let's first look to see if this port is already in the
// list. If not, then add it to the list and continue with
// the open.
//
if ((pIniPort = _inet_find_port(lpszPortName)) == NULL) {
semLeaveCrit(); // Leave the critical section becuase the following call will hit the network
pPortMgr = new CPortMgr;
if (pPortMgr != NULL) { if (! pPortMgr->Create (lpszPortName)) { delete (pPortMgr); pPortMgr = NULL; } }
dwLE = GetLastError (); semEnterCrit();
if (! (pPortMgr)) { // The connection is invalid
DBG_MSG(DBG_LEV_ERROR, (TEXT("Err: InetmonOpenPort : PortMgrCreate Failed: LastError(%d)"), GetLastError()));
if (dwLE != ERROR_ACCESS_DENIED && dwLE != ERROR_INVALID_PRINTER_NAME && dwLE != ERROR_INVALID_NAME) {
dwLE = ERROR_PRINTER_NOT_FOUND; }
#ifndef WINNT32
// Win9X will not allow a RPC printer-name
// to install unless the error is ERROR_INVALID_NAME.
//
if (dwLE == ERROR_INVALID_PRINTER_NAME) dwLE = ERROR_INVALID_NAME; #endif
SetLastError ( dwLE );
goto exit_openport; }
if (_inet_create_port(lpszPortName, pPortMgr) == FALSE) {
DBG_MSG(DBG_LEV_ERROR, (TEXT("Err: InetmonOpenPort : Add Port Failed: LastError(%d)"), GetLastError())); SetLastError(ERROR_INVALID_NAME);
goto exit_openport; } }
if (pIniPort || (pIniPort = _inet_find_port(lpszPortName))) {
if (!pIniPort->m_bDeletePending) { //
// We stop increasing the ref count since the open handles
// won't have affect on the port deletion, i.e. the port
// may be deleted even when there are open handles.
//
// pIniPort->m_cRef ++;
//
// Increase the printer open handle ref count. This
// count is used to manage the life time of the PCINETMONPORT
// data structure. i.e. if the port is deleted when there are
// open handles, PCINETMONPORT is not freed until
//
// pIniPort->m_cPrinterRef == 0
//
pIniPort->IncPrinterRef ();
} else { DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : InetmonOpenPort : Open deleted port: Port(%s)"), lpszPortName)); SetLastError(ERROR_INVALID_NAME); }
} else {
DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : InetmonOpenPort : Invalid Name: Port(%s)"), lpszPortName)); SetLastError(ERROR_INVALID_NAME); } }
exit_openport:
return pIniPort; }
BOOL CInetMon::InetmonReleasePort( PCINETMONPORT pIniPort) { DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: InetmonReleasePort: pIniPort(%08lX)"), pIniPort));
semCheckCrit(); // Validate the port and proceed to close the port.
//
pIniPort->DecPrinterRef ();
if (pIniPort->m_bDeletePending && pIniPort->m_cPrinterRef == 0) { //
// There is no open handles, free PCINETMONPORT
//
DBG_MSG(DBG_LEV_INFO, (TEXT("Info: InetmonReleasePort free pIniPort %p."), pIniPort));
delete pIniPort; }
return TRUE; }
/*****************************************************************************\
* InetmonClosePort * * Close the internet connection. * \*****************************************************************************/ BOOL CInetMon::InetmonClosePort( PCINETMONPORT pIniPort, HANDLE hPrinter) {
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: InetmonClosePort: pIniPort(%08lX)"), pIniPort));
semCheckCrit(); pIniPort->ClosePort (hPrinter); if (pIniPort->m_bDeletePending && pIniPort->m_cPrinterRef == 0) { //
// There is no open handles, free PCINETMONPORT
//
DBG_MSG(DBG_LEV_INFO, (TEXT("Info: pIniPort Freed %p."), pIniPort)); delete pIniPort; }
return TRUE; }
/*****************************************************************************\
* InetmonEnumPorts * * Enumerate the ports registered in our list. * \*****************************************************************************/ BOOL CInetMon::InetmonEnumPorts( LPTSTR lpszServerName, DWORD dwLevel, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned) { PCINETMONPORT pIniPort; DWORD cb; LPBYTE pEnd; DWORD dwError = ERROR_SUCCESS;
semCheckCrit();
// Traverse the list to build the size of the entire list.
//
cb = 0;
pIniPort = m_pPortList->pIniFirstPort;
while (pIniPort) {
cb += pIniPort->_inet_size_entry(dwLevel);
pIniPort = pIniPort->m_pNext; }
// Store the size of the list (This is the size needed).
//
*pcbNeeded = cb;
// If the size of the list is capable of being stored in the buffer
// passed in, then we can return the entries.
//
if (cb <= cbBuf) {
pEnd = pPorts + cbBuf;
*pcReturned = 0;
pIniPort = m_pPortList->pIniFirstPort;
while (pIniPort) {
pEnd = pIniPort->_inet_copy_entry(dwLevel, pPorts, pEnd);
switch (dwLevel) {
case PRINT_LEVEL_1: pPorts += sizeof(PORT_INFO_1); break;
case PRINT_LEVEL_2: pPorts += sizeof(PORT_INFO_2); break; }
pIniPort = pIniPort->m_pNext;
(*pcReturned)++; }
} else {
dwError = ERROR_INSUFFICIENT_BUFFER; }
if (dwError != ERROR_SUCCESS) { SetLastError(dwError); return FALSE; }
return TRUE; }
/*****************************************************************************\
* InetmonDeletePort * * Deletes a port from the INIMONPORT list. * \*****************************************************************************/ BOOL CInetMon::InetmonDeletePort( LPCTSTR lpszPortName, HWND hWnd, LPCTSTR lpszMonitorName) { BOOL bRet = FALSE;
semCheckCrit();
if (_inet_validate_portname(lpszPortName)) bRet = _inet_delete_port(lpszPortName);
return bRet; }
/*****************************************************************************\
* InetmonAddPort * * Adds a port to the INIMONPORT list. * \*****************************************************************************/ BOOL CInetMon::InetmonAddPort( LPCTSTR lpszPortName, LPCTSTR lpszMonitorName) { BOOL bRet = FALSE; PCPORTMGR pPortMgr = NULL;
semCheckCrit();
// If the port is not-found, then we can add it. Otherwise,
// the port already exists.
//
if (_inet_validate_portname(lpszPortName)) {
if (_inet_find_port(lpszPortName) == NULL) {
pPortMgr = new CPortMgr; if (pPortMgr != NULL) { if (!pPortMgr->Init (lpszPortName)) { delete pPortMgr; pPortMgr = NULL; }
if (pPortMgr) { bRet = (_inet_create_port(lpszPortName, pPortMgr) != NULL); } } } }
return bRet; }
/*****************************************************************************\
* InetmonFindPort * * Looks for port in INIMONPORT list. * \*****************************************************************************/ PCINETMONPORT CInetMon::InetmonFindPort( LPCTSTR lpszPortName) { PCINETMONPORT hPort = NULL;
semCheckCrit();
if (_inet_validate_portname(lpszPortName)) hPort = _inet_find_port(lpszPortName) ;
return hPort; }
/********************************************************************************
** End of FIle (inetpp.c) ********************************************************************************/
|