717 lines
16 KiB
C++
717 lines
16 KiB
C++
/*****************************************************************************\
|
|
* MODULE: splpjm.c
|
|
*
|
|
* This module contains the routines to deal with job-mapping list.
|
|
*
|
|
*
|
|
* Copyright (C) 1996-1997 Microsoft Corporation
|
|
* Copyright (C) 1996-1997 Hewlett Packard
|
|
*
|
|
* History:
|
|
* 13-Jan-1997 ChrisWil Created.
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#include "priv.h"
|
|
|
|
/*****************************************************************************\
|
|
* pjm_OldEntry (Local Routine)
|
|
*
|
|
*
|
|
\*****************************************************************************/
|
|
_inline BOOL pjm_IsOldEntry(
|
|
PJOBMAP pjm)
|
|
{
|
|
return !pjm->bRemoteJob && !pjmChkState(pjm, PJM_SPOOLING);
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* pjm_IsLocalJob (Local Routine)
|
|
*
|
|
*
|
|
\*****************************************************************************/
|
|
_inline BOOL pjm_IsLocalJob(
|
|
PJOBMAP pjm)
|
|
{
|
|
return !pjm->bRemoteJob && pjmChkState(pjm, PJM_SPOOLING);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************\
|
|
* pjm_DelEntry (Local Routine)
|
|
*
|
|
*
|
|
\*****************************************************************************/
|
|
_inline VOID pjm_DelEntry(
|
|
PJOBMAP pjm)
|
|
{
|
|
if (pjm->hSplFile)
|
|
SplFree(pjm->hSplFile);
|
|
|
|
if (pjm->lpszUri)
|
|
memFreeStr(pjm->lpszUri);
|
|
|
|
if (pjm->lpszUser)
|
|
memFreeStr(pjm->lpszUser);
|
|
|
|
memFree(pjm, sizeof(JOBMAP));
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* pjmAdd
|
|
*
|
|
* Add a job-mapping to the list. Access to this list needs ownership of the
|
|
* crit-sect.
|
|
*
|
|
\*****************************************************************************/
|
|
PJOBMAP pjmAdd(
|
|
PJOBMAP *pjmList,
|
|
PCINETMONPORT pIniPort,
|
|
LPCTSTR lpszUser,
|
|
LPCTSTR lpszDocName)
|
|
{
|
|
PJOBMAP pjm = NULL;
|
|
|
|
static DWORD s_idJobLocal = 0;
|
|
|
|
semCheckCrit();
|
|
|
|
if (pjmList) {
|
|
|
|
|
|
// Add the new job-entry to the list.
|
|
//
|
|
if (pjm = (PJOBMAP)memAlloc(sizeof(JOBMAP))) {
|
|
|
|
// Initialize our job-entry.
|
|
//
|
|
GetSystemTime (&pjm->SubmitTime);
|
|
|
|
pjm->dwState = 0;
|
|
pjm->pIniPort = pIniPort;
|
|
pjm->idJobLocal = ++s_idJobLocal;
|
|
pjm->idJobRemote = 0;
|
|
pjm->lpszUri = NULL;
|
|
pjm->lpszUser = memAllocStr(lpszUser);
|
|
pjm->lpszDocName = memAllocStr(lpszDocName);
|
|
pjm->hSplFile = NULL;
|
|
pjm->dwLocalJobSize = 0;
|
|
pjm->dwStatus = JOB_STATUS_SPOOLING;
|
|
pjm->pNext = NULL;
|
|
|
|
|
|
// Place it at the end of the list.
|
|
//
|
|
|
|
if (! *pjmList) {
|
|
*pjmList = pjm;
|
|
}
|
|
else {
|
|
|
|
for (PJOBMAP pjPtr = *pjmList; pjPtr->pNext; pjPtr = pjPtr->pNext);
|
|
pjPtr->pNext = pjm;
|
|
}
|
|
}
|
|
}
|
|
|
|
return pjm;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* pjmDel
|
|
*
|
|
* Delete a job-mapping from the list. Access to this list needs owenership
|
|
* of the crit-sect.
|
|
*
|
|
\*****************************************************************************/
|
|
VOID pjmDel(
|
|
PJOBMAP* pjmList,
|
|
PJOBMAP pjm)
|
|
{
|
|
PJOBMAP pjPtr;
|
|
PJOBMAP pjPrv;
|
|
DWORD idx;
|
|
|
|
semCheckCrit();
|
|
|
|
if (pjmList) {
|
|
|
|
for (pjPtr = *pjmList, idx = 0; pjPtr && (pjm != pjPtr); ) {
|
|
|
|
// Reposition.
|
|
//
|
|
pjPrv = pjPtr;
|
|
pjPtr = pjPtr->pNext;
|
|
|
|
|
|
// If we've iterated 1000 jobs in this list, then we've
|
|
// either got a very heavily taxed print-system, or we
|
|
// may have an infinite loop.
|
|
//
|
|
if (idx++ >= g_dwJobLimit) {
|
|
|
|
DBG_MSG(DBG_LEV_ERROR, (TEXT("Error: pjmDel : Looped 1000 jobs, possible infinite loop")));
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
// If we found the entry, then delete it.
|
|
//
|
|
if (pjPtr) {
|
|
|
|
if (pjPtr == *pjmList) {
|
|
|
|
*pjmList = pjPtr->pNext;
|
|
|
|
} else {
|
|
|
|
pjPrv->pNext = pjPtr->pNext;
|
|
}
|
|
|
|
pjm_DelEntry(pjPtr);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* pjmCleanRemoteFlag
|
|
*
|
|
* Cleanup remote jobid from list. Access to this list needs ownership of the
|
|
* crit-sect.
|
|
*
|
|
\*****************************************************************************/
|
|
VOID pjmCleanRemoteFlag(
|
|
PJOBMAP* pjmList)
|
|
{
|
|
PJOBMAP pjPtr = NULL;
|
|
|
|
semCheckCrit();
|
|
|
|
if (pjmList) {
|
|
|
|
for (pjPtr = *pjmList; pjPtr; ) {
|
|
|
|
pjPtr->bRemoteJob = FALSE;
|
|
|
|
// Next item.
|
|
//
|
|
pjPtr = pjPtr->pNext;
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* pjmGetLocalJobCount
|
|
*
|
|
* Locate number of job-entries from list. Access to this list needs ownership of the
|
|
* crit-sect.
|
|
*
|
|
\*****************************************************************************/
|
|
DWORD pjmGetLocalJobCount(
|
|
PJOBMAP* pjmList,
|
|
DWORD* pcbItems)
|
|
{
|
|
PJOBMAP pjPtr = NULL;
|
|
DWORD idx = 0;
|
|
|
|
semCheckCrit();
|
|
|
|
*pcbItems = 0;
|
|
if (pjmList) {
|
|
|
|
for (pjPtr = *pjmList; pjPtr; ) {
|
|
|
|
if (pjm_IsLocalJob (pjPtr)) {
|
|
|
|
idx++;
|
|
|
|
*pcbItems += sizeof (JOB_INFO_2) +
|
|
utlStrSize (pjPtr->lpszDocName) +
|
|
utlStrSize (pjPtr->lpszUser);
|
|
}
|
|
|
|
// Next item.
|
|
//
|
|
pjPtr = pjPtr->pNext;
|
|
|
|
}
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* pjmFind
|
|
*
|
|
* Locate job-entry from list. Access to this list needs ownership of the
|
|
* crit-sect. This will lookup either Local/Remote id's and return its
|
|
* position.
|
|
*
|
|
\*****************************************************************************/
|
|
PJOBMAP pjmFind(
|
|
PJOBMAP* pjmList,
|
|
DWORD fType,
|
|
DWORD idJob)
|
|
{
|
|
PJOBMAP pjPtr = NULL;
|
|
DWORD idx;
|
|
|
|
semCheckCrit();
|
|
|
|
if (pjmList) {
|
|
|
|
// Search.
|
|
//
|
|
for (pjPtr = *pjmList, idx = 0; pjPtr && (pjmJobId(pjPtr, fType) != idJob); ) {
|
|
|
|
// Next item.
|
|
//
|
|
pjPtr = pjPtr->pNext;
|
|
|
|
|
|
// If we've iterated 1000 jobs in this list, then we've
|
|
// either got a very heavily taxed print-system, or we
|
|
// may have an infinite loop.
|
|
//
|
|
if (idx++ >= g_dwJobLimit) {
|
|
|
|
DBG_MSG(DBG_LEV_ERROR, (TEXT("Error: pjmFind : Looped 1000 jobs, possible infinite loop")));
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (pjPtr && fType == PJM_REMOTEID) {
|
|
pjPtr->bRemoteJob = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
return pjPtr;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* pjmNextLocalJob
|
|
*
|
|
* Walk the list and look for any expired entries. Access to this list needs
|
|
* ownership of the crit-sect.
|
|
*
|
|
\*****************************************************************************/
|
|
PJOBMAP pjmNextLocalJob(
|
|
PJOBMAP* pjmList,
|
|
PJOB_INFO_2 pJobInfo2,
|
|
PBOOL pbFound)
|
|
{
|
|
PJOBMAP pjPtr = NULL;
|
|
DWORD idx;
|
|
BOOL bFound = FALSE;
|
|
|
|
semCheckCrit();
|
|
|
|
if (pjmList) {
|
|
|
|
for (pjPtr = *pjmList, idx = 0; pjPtr && !bFound; ) {
|
|
|
|
// If we're spooling, then we can't be an old-job.
|
|
//
|
|
if (pjm_IsLocalJob (pjPtr)) {
|
|
|
|
// It is a new entry
|
|
//
|
|
ZeroMemory (pJobInfo2, sizeof (JOB_INFO_2));
|
|
pJobInfo2->JobId = pjPtr->idJobLocal;
|
|
pJobInfo2->pDocument = pjPtr->lpszDocName;
|
|
pJobInfo2->pUserName = pjPtr->lpszUser;
|
|
pJobInfo2->Size = pjPtr->dwLocalJobSize;
|
|
pJobInfo2->Submitted = pjPtr->SubmitTime;
|
|
pJobInfo2->Status = pjPtr->dwStatus;
|
|
|
|
if (pjmChkState (pjPtr, PJM_CANCEL)) {
|
|
pJobInfo2->Status |= JOB_STATUS_DELETING;
|
|
}
|
|
|
|
bFound = TRUE;
|
|
}
|
|
|
|
// Next item.
|
|
//
|
|
pjPtr = pjPtr->pNext;
|
|
|
|
}
|
|
}
|
|
|
|
*pbFound = bFound;
|
|
return pjPtr;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* pjmRmoveOldEntries
|
|
*
|
|
* Walk the list and look for any expired entries. Access to this list needs
|
|
* ownership of the crit-sect.
|
|
*
|
|
\*****************************************************************************/
|
|
VOID pjmRemoveOldEntries(
|
|
PJOBMAP *pjmList)
|
|
{
|
|
PJOBMAP pjPtr;
|
|
PJOBMAP pjDel;
|
|
PJOBMAP pjPrv;
|
|
DWORD idx;
|
|
|
|
semCheckCrit();
|
|
|
|
|
|
for (pjPtr = *pjmList, pjPrv = *pjmList, idx = 0; pjPtr; ) {
|
|
|
|
// If we're an old entry, then delete it.
|
|
//
|
|
if (pjm_IsOldEntry (pjPtr)) {
|
|
|
|
// No remote job ID and the state is not spooling
|
|
// It is an old entry, delete it
|
|
|
|
pjDel = pjPtr;
|
|
|
|
if (pjPtr == *pjmList) {
|
|
|
|
*pjmList = pjPtr->pNext;
|
|
pjPtr = *pjmList;
|
|
pjPrv = *pjmList;
|
|
|
|
} else {
|
|
|
|
pjPrv->pNext = pjPtr->pNext;
|
|
pjPtr = pjPrv->pNext;
|
|
}
|
|
|
|
pjm_DelEntry(pjDel);
|
|
|
|
|
|
} else {
|
|
|
|
pjPrv = pjPtr;
|
|
pjPtr = pjPtr->pNext;
|
|
}
|
|
|
|
|
|
// If we've iterated 1000 jobs in this list, then we've
|
|
// either got a very heavily taxed print-system, or we
|
|
// may have an infinite loop.
|
|
//
|
|
if (idx++ >= g_dwJobLimit) {
|
|
|
|
DBG_MSG(DBG_LEV_ERROR, (TEXT("Warn : pjmWalk : Looped 1000 jobs, possible infinite loop")));
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************\
|
|
* pjmDelList
|
|
*
|
|
*
|
|
\*****************************************************************************/
|
|
VOID pjmDelList(
|
|
PJOBMAP pjmList)
|
|
{
|
|
PJOBMAP pjPtr;
|
|
|
|
semCheckCrit();
|
|
|
|
|
|
for (pjPtr = pjmList; pjPtr; ) {
|
|
|
|
pjmList = pjPtr->pNext;
|
|
|
|
pjm_DelEntry(pjPtr);
|
|
|
|
pjPtr = pjmList;
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* pjmSetState
|
|
*
|
|
* Set the state of the job-entry. If we're setting this to spooling-state,
|
|
* then we go through the extra-trouble of setting up a spool-file entry as
|
|
* well.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL pjmSetState(
|
|
PJOBMAP pjm,
|
|
DWORD dwState)
|
|
{
|
|
DWORD fType;
|
|
BOOL bSet = FALSE;
|
|
|
|
semCheckCrit();
|
|
|
|
|
|
if (pjm) {
|
|
|
|
// If the caller is setting the job into spooling-state, then
|
|
// we need to create a spool-file. If this state is already
|
|
// set, then ignore this particular call.
|
|
//
|
|
if ((dwState & PJM_SPOOLING) && !pjmChkState(pjm, PJM_SPOOLING)) {
|
|
|
|
// Determine the type of spl-file to open. If PJM_NOOPEN
|
|
// is specified, then we will close the file-handle so that
|
|
// other processes can obtain exclusive access (i.e. AddJob,
|
|
// and ScheduleJob require this).
|
|
//
|
|
fType = (dwState & PJM_NOOPEN ? SPLFILE_TMP : SPLFILE_SPL);
|
|
|
|
|
|
// Allocate the spool-file, and close if necessary.
|
|
//
|
|
if (pjm->hSplFile = SplCreate(pjm->idJobLocal, fType)) {
|
|
|
|
if (dwState & PJM_NOOPEN)
|
|
SplClose(pjm->hSplFile);
|
|
|
|
bSet = TRUE;
|
|
|
|
} else {
|
|
|
|
goto EndSet;
|
|
}
|
|
|
|
} else {
|
|
|
|
bSet = TRUE;
|
|
}
|
|
|
|
|
|
// Set the state.
|
|
//
|
|
pjm->dwState |= dwState;
|
|
}
|
|
|
|
EndSet:
|
|
|
|
return bSet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* pjmClrState
|
|
*
|
|
* Clear the state specified in the job-entry. If we're turning of spooling,
|
|
* then we need to free up the spool-file-object.
|
|
*
|
|
\*****************************************************************************/
|
|
VOID pjmClrState(
|
|
PJOBMAP pjm,
|
|
DWORD dwState)
|
|
{
|
|
semCheckCrit();
|
|
|
|
|
|
if (pjm) {
|
|
|
|
// If the caller is turning off spooling, then we need to
|
|
// clean our spool-file resources. If there is no spooling
|
|
// going on, then ignore.
|
|
//
|
|
if ((dwState & PJM_SPOOLING) && pjmChkState(pjm, PJM_SPOOLING)) {
|
|
|
|
// Clean our spooling-file resources.
|
|
//
|
|
SplFree(pjm->hSplFile);
|
|
pjm->hSplFile = NULL;
|
|
}
|
|
|
|
|
|
// Clear the state.
|
|
//
|
|
pjm->dwState &= ~dwState;
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* pjmSetJobRemote
|
|
*
|
|
* Set the remote-job-id into the job-entry. This is usually called once
|
|
* the job-id is obtained from the print-server. We will maintain this for
|
|
* local/remote job-mapping.
|
|
*
|
|
\*****************************************************************************/
|
|
VOID pjmSetJobRemote(
|
|
PJOBMAP pjm,
|
|
DWORD idJobRemote,
|
|
LPCTSTR lpszUri)
|
|
{
|
|
semCheckCrit();
|
|
|
|
if (pjm) {
|
|
|
|
// If we had a previous job-url, then we need to free it
|
|
// before reseting it with the new.
|
|
//
|
|
if (pjm->lpszUri)
|
|
memFreeStr(pjm->lpszUri);
|
|
|
|
|
|
// Store remote-job information.
|
|
//
|
|
pjm->idJobRemote = idJobRemote;
|
|
pjm->lpszUri = memAllocStr(lpszUri);
|
|
pjm->bRemoteJob = TRUE;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* pjmAddJobSize
|
|
*
|
|
* Add the job size to the local job info. This is usually called by
|
|
* PPWritePrinter
|
|
*
|
|
\*****************************************************************************/
|
|
VOID pjmAddJobSize(
|
|
PJOBMAP pjm,
|
|
DWORD dwSize)
|
|
{
|
|
semCheckCrit();
|
|
|
|
if (pjm) {
|
|
|
|
pjm->dwLocalJobSize += dwSize;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************\
|
|
* pjmSplLock
|
|
*
|
|
* Lock the spool-file for reading. This returns a file-map pointer to the
|
|
* caller.
|
|
*
|
|
\*****************************************************************************/
|
|
CFileStream* pjmSplLock(
|
|
PJOBMAP pjm)
|
|
{
|
|
CFileStream *pStream = NULL;
|
|
|
|
semCheckCrit();
|
|
|
|
if (pjm) {
|
|
|
|
// If the state of our spool-object requires that we not
|
|
// keep open-handles on the file, then we need to open
|
|
// it here. This is closed at pjmSplUnlock().
|
|
//
|
|
if (pjmChkState(pjm, PJM_NOOPEN))
|
|
SplOpen(pjm->hSplFile);
|
|
|
|
pStream = SplLock(pjm->hSplFile);
|
|
}
|
|
|
|
return pStream;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* pjmSplUnlock
|
|
*
|
|
* This unlocks our file-mapped-pointer on the spool-file.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL pjmSplUnlock(
|
|
PJOBMAP pjm)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
semCheckCrit();
|
|
|
|
|
|
// The spool-file must have already been locked in order to proceed
|
|
// with this call.
|
|
//
|
|
if (pjm) {
|
|
|
|
// Unlock the spool-file.
|
|
//
|
|
bRet = SplUnlock(pjm->hSplFile);
|
|
|
|
|
|
// If the state of our spool-object requires that
|
|
// we keep no open-handles, then we need to close
|
|
// the spool-handle.
|
|
//
|
|
if (pjmChkState(pjm, PJM_NOOPEN))
|
|
SplClose(pjm->hSplFile);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* pjmSplWrite
|
|
*
|
|
* Write out data to the spool-file.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL pjmSplWrite(
|
|
PJOBMAP pjm,
|
|
LPVOID lpMem,
|
|
DWORD cbMem,
|
|
LPDWORD lpcbWr)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
semCheckCrit();
|
|
|
|
|
|
if (pjm) {
|
|
|
|
if (pjmChkState(pjm, PJM_NOOPEN))
|
|
SplOpen(pjm->hSplFile);
|
|
|
|
bRet = SplWrite(pjm->hSplFile, (LPBYTE) lpMem, cbMem, lpcbWr);
|
|
|
|
if (pjmChkState(pjm, PJM_NOOPEN))
|
|
SplClose(pjm->hSplFile);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* pjmSetState
|
|
*
|
|
* Set the status of the local job-entry.
|
|
*
|
|
\*****************************************************************************/
|
|
VOID pjmUpdateLocalJobStatus(
|
|
PJOBMAP pjm,
|
|
DWORD dwStatus)
|
|
{
|
|
semCheckCrit();
|
|
|
|
|
|
if (pjm) {
|
|
|
|
pjm->dwStatus = dwStatus;
|
|
}
|
|
|
|
}
|