|
|
/*****************************************************************************\
* MODULE: inetport.cxx * * 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*, InetMonPort 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"
CInetMonPort::CInetMonPort ( LPCTSTR lpszPortName, LPCTSTR lpszDevDesc, PCPORTMGR pPortMgr): m_bValid (FALSE), m_pNext (NULL), m_cRef (0), m_cPrinterRef (0), m_bDeletePending (FALSE), m_lpszHost (NULL), m_lpszShare (NULL), m_pPortMgr (pPortMgr), m_pGetPrinterCache (NULL), m_pEnumJobsCache (NULL), m_bCheckConnection (TRUE), m_hTerminateEvent (NULL), m_pjmList (NULL)
{ PCINETMONPORT pIniPort; PCINETMONPORT pPort; LPTSTR lpszHost; LPTSTR lpszShare; INTERNET_PORT iPort; BOOL bSecure;
// Parse out the host/share. This call returns allocated
// string-buffers. It is our responsibility to free the
// memory once we're done with it.
//
if (utlParseHostShare(lpszPortName, &lpszHost, &lpszShare, &iPort, &bSecure)) {
// The (lpszDevDesc) could be NULL only if it's PP_REMOTE.
//
if (lpszDevDesc && *lpszDevDesc) m_lpszDesc = memAllocStr(lpszDevDesc); else m_lpszDesc = memAllocStr(lpszPortName);
m_lpszName = memAllocStr (lpszPortName);
// If succeeded, then continue to initialize the port.
//
if (m_lpszDesc && m_lpszName) {
// Initialize the port-elements.
//
m_lpszHost = lpszHost; m_lpszShare = lpszShare;
DBG_MSG(DBG_LEV_INFO, (TEXT("Info: _inet_create_port: Host(%s) Share(%s)"), lpszHost, lpszShare));
m_pGetPrinterCache = new GetPrinterCache (this); m_pEnumJobsCache = new EnumJobsCache (this);
if (m_pGetPrinterCache && m_pEnumJobsCache && m_pGetPrinterCache->bValid() && m_pEnumJobsCache->bValid ()) { m_bValid = TRUE; } } } }
CInetMonPort::~CInetMonPort () { FreeGetPrinterCache (); FreeEnumJobsCache ();
// Free the entry and all memory allocated on
// behalf of the entry.
//
memFreeStr(m_lpszDesc); memFreeStr(m_lpszHost); memFreeStr(m_lpszShare);
// Remove any job-entries.
//
pjmDelList(m_pjmList);
m_pPortMgr->Remove (); delete m_pPortMgr;
if (m_hTerminateEvent) CloseHandle (m_hTerminateEvent); }
VOID CInetMonPort::IncRef () { m_cRef++; }
VOID CInetMonPort::DecRef () { m_cRef--; }
VOID CInetMonPort::IncPrinterRef () { m_cPrinterRef++; }
VOID CInetMonPort::DecPrinterRef () { m_cPrinterRef--; }
/*****************************************************************************\
* _inet_size_entry (Local Routine) * * Returns the size of an entry depending upon the print-level. * \*****************************************************************************/ DWORD CInetMonPort::_inet_size_entry( DWORD dwLevel) { DWORD cb;
switch (dwLevel) {
case PRINT_LEVEL_1:
cb = sizeof(PORT_INFO_1) + utlStrSize(m_lpszName);
break;
case PRINT_LEVEL_2:
cb = sizeof(PORT_INFO_2) + utlStrSize(m_lpszName) + utlStrSize(m_lpszDesc) + utlStrSize(g_szLocalPort);
break;
default:
cb = 0;
break; }
return cb; }
/*****************************************************************************\
* _inet_copy_entry (Local Routine) * * Returns a copy of the port-entry. * \*****************************************************************************/ LPBYTE CInetMonPort::_inet_copy_entry( DWORD dwLevel, LPBYTE pPortInfo, LPBYTE pEnd) { LPTSTR SourceStrings[sizeof(PORT_INFO_2) / sizeof(LPTSTR)]; LPTSTR *pSourceStrings=SourceStrings; DWORD *pOffsets;
static DWORD s_dwPortInfo1Strings[] = { offsetof(LPPORT_INFO_1A, pName), 0xFFFFFFFF };
static DWORD s_dwPortInfo2Strings[] = { offsetof(LPPORT_INFO_2A, pPortName), offsetof(LPPORT_INFO_2A, pMonitorName), offsetof(LPPORT_INFO_2A, pDescription), 0xFFFFFFFF };
//
//
switch (dwLevel) { case PORT_LEVEL_1: pOffsets = s_dwPortInfo1Strings; break;
case PORT_LEVEL_2: pOffsets = s_dwPortInfo2Strings; break;
default: return pEnd; }
//
//
switch (dwLevel) {
case PORT_LEVEL_1: *pSourceStrings++ = m_lpszName; pEnd = utlPackStrings(SourceStrings, pPortInfo, pOffsets, pEnd); break;
case PORT_LEVEL_2: *pSourceStrings++ = (LPTSTR)m_lpszName; *pSourceStrings++ = (LPTSTR)g_szLocalPort; *pSourceStrings++ = (LPTSTR)m_lpszDesc;
#if 0
((PPORT_INFO_2)pPortInfo)->fPortType = PORT_TYPE_WRITE | PORT_TYPE_NET_ATTACHED; #else
((PPORT_INFO_2)pPortInfo)->fPortType = PORT_TYPE_WRITE | PORT_TYPE_REDIRECTED; #endif
((PPORT_INFO_2)pPortInfo)->Reserved = 0;
pEnd = utlPackStrings(SourceStrings, pPortInfo, pOffsets, pEnd); break; }
return pEnd; }
/*****************************************************************************\
* _inet_req_jobstart (Local Routine) * * Performs the job-start request. This writes out the header info to the * spool-job. * \*****************************************************************************/ BOOL CInetMonPort::_inet_req_jobstart( PIPPREQ_PRTJOB ppj, PJOBMAP pjmJob) { LPBYTE lpIppHdr; REQINFO ri; DWORD cbIppHdr; DWORD dwRet; DWORD cbWr; BOOL bRet = FALSE;
// Convert the IPPREQ_PRTJOB to a IPP-stream-header.
//
ZeroMemory(&ri, sizeof(REQINFO)); ri.cpReq = CP_UTF8; ri.idReq = IPP_REQ_PRINTJOB;
ri.fReq[0] = IPP_REQALL; ri.fReq[1] = IPP_REQALL;
dwRet = WebIppSndData(IPP_REQ_PRINTJOB, &ri, (LPBYTE)ppj, ppj->cbSize, &lpIppHdr, &cbIppHdr);
if (dwRet == WEBIPP_OK) {
bRet = pjmSplWrite(pjmJob, lpIppHdr, cbIppHdr, &cbWr);
WebIppFreeMem(lpIppHdr); }
return bRet; }
/*****************************************************************************\
* _inet_IppPrtRsp (Local Routine) * * Retrieves a get response from the IPP server. * \*****************************************************************************/ BOOL CALLBACK _inet_IppPrtRsp( CAnyConnection *pConnection, HINTERNET hJobReq, PCINETMONPORT pIniPort, PJOBMAP pjmJob) { HANDLE hIpp; DWORD dwRet; DWORD cbRd; LPBYTE lpDta; DWORD cbDta; LPIPPRET_JOB lpRsp; DWORD cbRsp; BYTE bBuf[MAX_IPP_BUFFER]; BOOL bRet = FALSE;
if (hIpp = WebIppRcvOpen(IPP_RET_PRINTJOB)) {
while (TRUE) {
cbRd = 0; if (pIniPort->ReadFile (pConnection, hJobReq, (LPVOID)bBuf, sizeof(bBuf), &cbRd) && cbRd) {
dwRet = WebIppRcvData(hIpp, bBuf, cbRd, (LPBYTE*)&lpRsp, &cbRsp, &lpDta, &cbDta);
switch (dwRet) {
case WEBIPP_OK:
if (bRet = lpRsp->bRet) {
// Set the remote-job-id to the job-entry. This
// entry was added at the time the spool-job-file
// was created.
//
semEnterCrit(); pjmSetJobRemote(pjmJob, lpRsp->ji.ji2.JobId, lpRsp->ji.ipp.pJobUri); semLeaveCrit();
} else {
// If the job failed to open on the server, then
// we will set the last-error from the server
// response.
//
SetLastError(lpRsp->dwLastError); }
WebIppFreeMem(lpRsp);
goto EndPrtRsp;
case WEBIPP_MOREDATA:
// Need to do another read to fullfill our header-response.
//
break;
default: DBG_MSG(DBG_LEV_ERROR, (TEXT("_inet_IppPrtRsp - Err : Receive Data Error (dwRet=%d, LE=%d)"), dwRet, WebIppGetError(hIpp))); SetLastError(ERROR_INVALID_DATA);
goto EndPrtRsp; }
} else {
goto EndPrtRsp; } }
EndPrtRsp:
WebIppRcvClose(hIpp);
} else {
SetLastError(ERROR_OUTOFMEMORY); }
return bRet; }
/*****************************************************************************\
* InetmonSendReq * * \*****************************************************************************/ BOOL CInetMonPort::SendReq( LPBYTE lpIpp, DWORD cbIpp, IPPRSPPROC pfnRsp, LPARAM lParam, BOOL bLeaveCrit) { BOOL bRet = FALSE;
CMemStream *pStream;
pStream = new CMemStream (lpIpp, cbIpp);
if (pStream && pStream->bValid ()){
bRet = SendReq (pStream, pfnRsp, lParam, bLeaveCrit); }
if (pStream) { delete pStream; } return bRet; }
BOOL CInetMonPort::SendReq( CStream *pStream, IPPRSPPROC pfnRsp, LPARAM lParam, BOOL bLeaveCrit) { DWORD dwLE = ERROR_SUCCESS; BOOL bRet = FALSE;
semCheckCrit();
if (bLeaveCrit) //
// We must increaset the port ref count to make sure the
// port is not deleted.
//
semSafeLeaveCrit(this);
bRet = m_pPortMgr->SendRequest (this, pStream, pfnRsp, lParam);
dwLE = GetLastError();
if (bLeaveCrit) semSafeEnterCrit(this);
if (!bRet) { // Need to check connection next time
m_bCheckConnection = TRUE; }
if ((bRet == FALSE) && (dwLE != ERROR_SUCCESS)) SetLastError(dwLE);
return bRet; }
/*****************************************************************************\
* InetmonClosePort * * Close the internet connection. * \*****************************************************************************/ BOOL CInetMonPort::ClosePort( HANDLE hPrinter) { CLogonUserData* pUser = NULL;
semCheckCrit();
// Now see if this is the last port handle that a user is closing
if (hPrinter != NULL) { // This means we couldn't create the printer handle and
// had to close the port
pUser = m_pPortMgr->GetUserIfLastDecRef (((LPINET_HPRINTER)hPrinter)->hUser);
if (pUser) { // We need to stop the Cache Manager thread if the same user owns it
DBG_MSG(DBG_LEV_INFO, (TEXT("Info: Last User Close Printer %p."), pUser));
InvalidateGetPrinterCacheForUser(pUser ); InvalidateEnumJobsCacheForUser(pUser );
semLeaveCrit ();
//
// In some cases, wininet takes a long time to clean up the
// browser session, so we have to leave the CS when making
// InternetSetOption calls to wininet
//
EndBrowserSession ();
semEnterCrit ();
delete ( pUser ); }
}
//
// We stop decrease the ref count since we don't increase the
// refcount at Open
//
DecPrinterRef();
return TRUE; }
/*****************************************************************************\
* InetmonStartDocPort * * Start the beginning of a StartDoc call. * \*****************************************************************************/ BOOL CInetMonPort::StartDocPort( DWORD dwLevel, LPBYTE pDocInfo, PJOBMAP pjmJob) { LPTSTR lpszUser; PIPPREQ_PRTJOB ppj; BOOL bRet = FALSE; DWORD dwLE;
semCheckCrit();
// We are going to hit the network, so leave the critical section
// To make sure the port will not be deleted, we increase the
// ref count
//
semSafeLeaveCrit(this);
bRet = m_pPortMgr->CheckConnection();
dwLE = GetLastError();
semSafeEnterCrit(this);
if (bRet) {
// Reset the value
bRet = FALSE;
// Get the username.
//
if (lpszUser = GetUserName()) {
// Build a IPP_PRTJOB_REQ struct. This routine assures that
// all strings are in Ascii format.
//
ppj = WebIppCreatePrtJobReq(FALSE, lpszUser, ((PDOC_INFO_2)pDocInfo)->pDocName, m_lpszName);
if (ppj) {
// Start the job. This writes out header info to the
// spool-file.
//
bRet = _inet_req_jobstart(ppj, pjmJob);
WebIppFreeMem(ppj); }
memFreeStr(lpszUser); }
} else {
m_bCheckConnection = FALSE; SetLastError (dwLE); }
if (bRet == FALSE) { DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : InetmonStartDocPort: Failed %d"), GetLastError())); }
return bRet; }
/*****************************************************************************\
* InetmonEndDocPort * * Signify the end of writing to a port. This is called after StartDocPort. * \*****************************************************************************/ BOOL CInetMonPort::EndDocPort( PJOBMAP pjmJob) { BOOL bRet = FALSE; CFileStream *pStream = NULL;
semCheckCrit();
if (pStream = pjmSplLock(pjmJob)) {
bRet = SendReq(pStream, (IPPRSPPROC)_inet_IppPrtRsp, (LPARAM)pjmJob, TRUE);
pjmSplUnlock(pjmJob); }
return bRet; }
/*****************************************************************************\
* InetmonWritePort * * Write bytes to the port. This goes to the spool-file until the * InetmonEndDocPort() is called. * \*****************************************************************************/ BOOL CInetMonPort::WritePort( PJOBMAP pjmJob, LPBYTE lpData, DWORD cbData, LPDWORD pcbWr) { BOOL bRet;
semCheckCrit();
bRet = pjmSplWrite(pjmJob, lpData, cbData, pcbWr);
return bRet; }
/*****************************************************************************\
* InetmonAbortPort * * Aborts our print-spooling process. * \*****************************************************************************/ BOOL CInetMonPort::AbortPort( PJOBMAP pjmJob) { semCheckCrit();
return TRUE; //(_inet_validate_port(hPort) ? TRUE : FALSE);
}
/*****************************************************************************\
* InetmonGetPortName * * Return the name of the port. * \*****************************************************************************/ LPCTSTR CInetMonPort::GetPortName( VOID) { LPCTSTR lpszName = NULL;
semCheckCrit();
lpszName = (LPCTSTR)m_lpszName;
return lpszName; }
/*****************************************************************************\
* InetmonGetPJMList * * \*****************************************************************************/ PJOBMAP* CInetMonPort::GetPJMList( VOID) { PJOBMAP* ppjmList = NULL;
semCheckCrit();
ppjmList = &m_pjmList;
return ppjmList; }
/*****************************************************************************\
* InetmonIncUserRefCount * * Increases the reference count on the port for the given user * \*****************************************************************************/ DWORD CInetMonPort::IncUserRefCount( PCLOGON_USERDATA hUser ) {
DWORD dwRet = (DWORD) -1;
dwRet = m_pPortMgr->IncreaseUserRefCount (hUser);
return dwRet; }
VOID CInetMonPort::FreeGetPrinterCache ( VOID) { if (m_pGetPrinterCache) { semLeaveCrit (); m_pGetPrinterCache->Shutdown (); semEnterCrit (); } }
BOOL CInetMonPort::BeginReadGetPrinterCache ( PPRINTER_INFO_2 *ppInfo2) { BOOL bRet = FALSE;
if (m_pGetPrinterCache) { semLeaveCrit (); bRet = m_pGetPrinterCache->BeginReadCache (ppInfo2); semEnterCrit (); }
return bRet; }
VOID CInetMonPort::EndReadGetPrinterCache ( VOID) { if (m_pGetPrinterCache) { m_pGetPrinterCache->EndReadCache (); } }
VOID CInetMonPort::InvalidateGetPrinterCache ( VOID) { if (m_pGetPrinterCache) { semLeaveCrit (); m_pGetPrinterCache->InvalidateCache (); semEnterCrit (); } }
VOID CInetMonPort::InvalidateGetPrinterCacheForUser( HANDLE hUser) /*++
Routine Description: Close the cache if the current user is currently controlling it.
Arguments: hUser - The user for which we want to close the cache
Return Value: None.
--*/ { CLogonUserData *pUser = (CLogonUserData *)hUser;
if (m_pGetPrinterCache && pUser) {
semLeaveCrit (); m_pGetPrinterCache->InvalidateCacheForUser (pUser); semEnterCrit (); } }
VOID CInetMonPort::FreeEnumJobsCache ( VOID) { semLeaveCrit (); m_pEnumJobsCache->Shutdown (); semEnterCrit (); }
BOOL CInetMonPort::BeginReadEnumJobsCache ( LPPPJOB_ENUM *ppje) { BOOL bRet = FALSE;
if (m_pEnumJobsCache) { semLeaveCrit (); bRet = m_pEnumJobsCache->BeginReadCache(ppje); semEnterCrit (); }
return bRet;
}
VOID CInetMonPort::EndReadEnumJobsCache ( VOID) { if (m_pEnumJobsCache) { m_pEnumJobsCache->EndReadCache(); } }
VOID CInetMonPort::InvalidateEnumJobsCache ( VOID) { if (m_pEnumJobsCache) { semLeaveCrit (); m_pEnumJobsCache->InvalidateCache (); semEnterCrit (); } }
VOID CInetMonPort::InvalidateEnumJobsCacheForUser( HANDLE hUser) /*++
Routine Description: Close the cache if the current user is currently controlling it.
Arguments: hUser - The user for which we want to close the cache
Return Value: None.
--*/ {
if (m_pEnumJobsCache && hUser) {
semLeaveCrit (); m_pEnumJobsCache->InvalidateCacheForUser ((CLogonUserData *)hUser); semEnterCrit (); } }
BOOL CInetMonPort::ReadFile ( CAnyConnection *pConnection, HINTERNET hReq, LPVOID lpvBuffer, DWORD cbBuffer, LPDWORD lpcbRd) { return m_pPortMgr->ReadFile (pConnection, hReq, lpvBuffer, cbBuffer, lpcbRd); }
BOOL CInetMonPort::GetCurrentConfiguration ( PINET_XCV_CONFIGURATION pXcvConfiguration) { return m_pPortMgr->GetCurrentConfiguration(pXcvConfiguration); }
BOOL CInetMonPort::ConfigurePort ( PINET_XCV_CONFIGURATION pXcvConfigurePortReqData, PINET_CONFIGUREPORT_RESPDATA pXcvAddPortRespData, DWORD cbSize, PDWORD cbSizeNeeded) { return m_pPortMgr->ConfigurePort (pXcvConfigurePortReqData, pXcvAddPortRespData, cbSize, cbSizeNeeded); }
HANDLE CInetMonPort::CreateTerminateEvent ( VOID) { if (!m_hTerminateEvent) { //
// Craete a manual reset event since multiple threads may be waiting
//
m_hTerminateEvent = CreateEvent (NULL, TRUE, FALSE, NULL); }
return m_hTerminateEvent; }
BOOL CInetMonPort::WaitForTermination ( DWORD dwWaitTime) { BOOL bTerminate = FALSE;
semLeaveCrit();
DWORD dwRet = WaitForSingleObject (m_hTerminateEvent, dwWaitTime);
if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_FAILED) bTerminate = TRUE;
semEnterCrit();
return bTerminate; }
|