392 lines
9.0 KiB
C
392 lines
9.0 KiB
C
/*++
|
|
|
|
Copyright (c) 1990-1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
addjob.c
|
|
|
|
|
|
Abstract:
|
|
|
|
This module provides all the public exported APIs relating to Printer
|
|
and Job management for the Local Print Providor. This module contains
|
|
LocalSpl's implementation of the following spooler apis
|
|
|
|
LocalAddJob
|
|
LocalScheduleJob
|
|
|
|
|
|
Author:
|
|
|
|
Dave Snipp (DaveSn) 15-Mar-1991
|
|
|
|
Revision History:
|
|
|
|
Rewritten both apis -- Krishna Ganugapati (KrishnaG) 5-Apr-1994
|
|
RapidPrint -- Matthew A Felton (mattfe) June 1994
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
|
|
|
|
DWORD
|
|
GetNextId(
|
|
VOID
|
|
);
|
|
|
|
PINIJOB
|
|
AddJobCreateJobEntry(
|
|
PSPOOL pSpool,
|
|
DWORD Level,
|
|
LPBYTE pDocInfo,
|
|
LPWSTR pUserName,
|
|
DWORD JobId,
|
|
DWORD JobStatus
|
|
);
|
|
|
|
VOID
|
|
AddJobEntry(
|
|
PINIPRINTER pIniPrinter,
|
|
PINIJOB pIniJob
|
|
);
|
|
|
|
|
|
BOOL
|
|
LocalAddJob(
|
|
HANDLE hPrinter,
|
|
DWORD Level,
|
|
LPBYTE pData,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
PINIPRINTER pIniPrinter;
|
|
PINIJOB pIniJob;
|
|
PSPOOL pSpool=(PSPOOL)hPrinter;
|
|
DWORD cb;
|
|
WCHAR szFileName[MAX_PATH];
|
|
LPBYTE pEnd;
|
|
DWORD LastError=0;
|
|
LPADDJOB_INFO_1 pAddJob = (LPADDJOB_INFO_1)pData;
|
|
DWORD NextId;
|
|
BOOL bRemote = FALSE;
|
|
DOC_INFO_1 DocInfo1;
|
|
BOOL bRet;
|
|
DWORD dwStatus = 0;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
|
|
SplOutSem();
|
|
|
|
//
|
|
// memset docinfo
|
|
//
|
|
|
|
memset((LPBYTE)&DocInfo1, 0, sizeof(DOC_INFO_1));
|
|
|
|
//
|
|
// Figure out whether the job is a remote or local job
|
|
//
|
|
|
|
if (!IsInteractiveUser()) {
|
|
bRemote = TRUE;
|
|
}
|
|
|
|
//
|
|
// Get the name of the user
|
|
//
|
|
|
|
if (bRemote) {
|
|
DocInfo1.pDocName = szRemoteDoc;
|
|
} else{
|
|
DocInfo1.pDocName = szLocalDoc;
|
|
}
|
|
|
|
|
|
EnterSplSem();
|
|
|
|
if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )) {
|
|
LeaveSplSem();
|
|
return(FALSE);
|
|
}
|
|
|
|
if (pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE) {
|
|
LeaveSplSem();
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
if (pSpool->TypeofHandle & PRINTER_HANDLE_PORT) {
|
|
if (pSpool->pIniPort->Status & PP_MONITOR) {
|
|
LeaveSplSem();
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}else {
|
|
//
|
|
// This is the "Local Printer masquerading as a Remote Printer"
|
|
//
|
|
LeaveSplSem();
|
|
bRet = AddJob(pSpool->hPort, Level, pData, cbBuf, pcbNeeded);
|
|
return(bRet);
|
|
}
|
|
}
|
|
|
|
pIniPrinter = pSpool->pIniPrinter;
|
|
|
|
SPLASSERT(pIniPrinter);
|
|
|
|
if (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_DIRECT) {
|
|
LeaveSplSem();
|
|
SetLastError(ERROR_INVALID_ACCESS);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Disallow EMF if PRINTER_ATTRIBUTE_RAW_ONLY is set.
|
|
//
|
|
if( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_RAW_ONLY ){
|
|
|
|
LPWSTR pszDatatype = pSpool->pDatatype ?
|
|
pSpool->pDatatype :
|
|
pSpool->pIniPrinter->pDatatype;
|
|
|
|
if( !ValidRawDatatype( pszDatatype )){
|
|
LeaveSplSem();
|
|
SetLastError( ERROR_INVALID_DATATYPE );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
NextId = GetNextId();
|
|
|
|
GetFullNameFromId(pIniPrinter, NextId, TRUE, szFileName,
|
|
pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE);
|
|
cb = wcslen(szFileName)*sizeof(WCHAR) + sizeof(WCHAR) +
|
|
sizeof(ADDJOB_INFO_1);
|
|
|
|
if (cb > cbBuf) {
|
|
*pcbNeeded = cb;
|
|
|
|
// Freeup the JobId.
|
|
MARKOFF(pJobIdMap, NextId);
|
|
LeaveSplSem();
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
dwStatus = JOB_SPOOLING | JOB_TYPE_ADDJOB;
|
|
if ((pIniJob = CreateJobEntry(pSpool,
|
|
1,
|
|
(LPBYTE)&DocInfo1,
|
|
NextId,
|
|
bRemote,
|
|
dwStatus)) == NULL) {
|
|
|
|
// Freeup the JobId.
|
|
MARKOFF(pJobIdMap, NextId);
|
|
DBGMSG(DBG_WARNING,("Error: CreateJobEntry failed in LocalAddJob\n"));
|
|
LeaveSplSem();
|
|
return(FALSE);
|
|
}
|
|
|
|
pIniPrinter->cSpooling++;
|
|
if (pIniPrinter->cSpooling > pIniPrinter->cMaxSpooling) {
|
|
pIniPrinter->cMaxSpooling = pIniPrinter->cSpooling;
|
|
}
|
|
|
|
AddJobEntry(pIniPrinter, pIniJob);
|
|
|
|
pEnd = (LPBYTE)pAddJob+cbBuf;
|
|
pEnd -= wcslen(szFileName)*sizeof(WCHAR)+sizeof(WCHAR);
|
|
WORD_ALIGN_DOWN(pEnd);
|
|
|
|
wcscpy((LPWSTR)pEnd, szFileName);
|
|
pAddJob->Path = (LPWSTR)pEnd;
|
|
pAddJob->JobId = pIniJob->JobId;
|
|
pSpool->pIniJob = pIniJob;
|
|
pSpool->Status |= SPOOL_STATUS_ADDJOB;
|
|
|
|
SetPrinterChange(pSpool->pIniPrinter,
|
|
pIniJob,
|
|
NVAddJob,
|
|
PRINTER_CHANGE_ADD_JOB | PRINTER_CHANGE_SET_PRINTER,
|
|
pSpool->pIniSpooler );
|
|
|
|
//
|
|
// If necessary Start Downlevel Size Detection thread
|
|
//
|
|
|
|
CheckSizeDetectionThread( pSpool->pIniSpooler );
|
|
|
|
LeaveSplSem();
|
|
SplOutSem();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
LocalScheduleJob(
|
|
HANDLE hPrinter,
|
|
DWORD JobId)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
PSPOOL pSpool=(PSPOOL)hPrinter;
|
|
WIN32_FIND_DATA FindData;
|
|
HANDLE fFile;
|
|
PINIJOB pIniJob;
|
|
DWORD Position;
|
|
DWORD LastError = FALSE;
|
|
HANDLE hPort;
|
|
BOOL bRet;
|
|
NOTIFYVECTOR NotifyVector;
|
|
|
|
COPYNV(NotifyVector, NVJobStatus);
|
|
|
|
SplOutSem();
|
|
EnterSplSem();
|
|
|
|
if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )) {
|
|
LeaveSplSem();
|
|
return (FALSE);
|
|
}
|
|
|
|
if (pSpool->Status & SPOOL_STATUS_STARTDOC) {
|
|
SetLastError(ERROR_SPL_NO_ADDJOB);
|
|
LeaveSplSem();
|
|
return(FALSE);
|
|
}
|
|
|
|
if (pSpool->TypeofHandle & PRINTER_HANDLE_PORT) {
|
|
if (pSpool->pIniPort->Status & PP_MONITOR) {
|
|
SetLastError(ERROR_INVALID_ACCESS);
|
|
LeaveSplSem();
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// This is the "Local Printer masquerading as the Network Printer"
|
|
//
|
|
|
|
hPort = pSpool->hPort;
|
|
LeaveSplSem();
|
|
bRet = ScheduleJob(hPort, JobId);
|
|
return(bRet);
|
|
}
|
|
|
|
if ((pIniJob = FindJob(pSpool->pIniPrinter, JobId, &Position)) == NULL) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
LeaveSplSem();
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
if (pIniJob->Status & JOB_SCHEDULE_JOB) {
|
|
|
|
DBGMSG(DBG_WARNING, ("ScheduleJob: job 0x%x (id = %d) already scheduled\n",
|
|
pIniJob, pIniJob->JobId));
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
LeaveSplSem();
|
|
return FALSE;
|
|
}
|
|
|
|
if (!(pIniJob->Status & JOB_TYPE_ADDJOB)) {
|
|
|
|
DBGMSG(DBG_WARNING, ("ScheduleJob: job 0x%x (id = %d) no addjob\n",
|
|
pIniJob, pIniJob->JobId));
|
|
|
|
SetLastError(ERROR_SPL_NO_ADDJOB);
|
|
LeaveSplSem();
|
|
return(FALSE);
|
|
}
|
|
|
|
pIniJob->Status |= JOB_SCHEDULE_JOB;
|
|
|
|
if (pIniJob->Status & JOB_SPOOLING) {
|
|
pIniJob->Status &= ~JOB_SPOOLING;
|
|
pIniJob->pIniPrinter->cSpooling--;
|
|
}
|
|
|
|
if ( pIniJob->Status & JOB_TIMEOUT ) {
|
|
pIniJob->Status &= ~( JOB_TIMEOUT | JOB_ABANDON );
|
|
FreeSplStr(pIniJob->pStatus);
|
|
pIniJob->pStatus = NULL;
|
|
}
|
|
|
|
SplInSem();
|
|
|
|
// Despooling whilst spooling requires us to wake the writing
|
|
// thread if it is waiting.
|
|
|
|
if ( pIniJob->WaitForWrite != INVALID_HANDLE_VALUE )
|
|
SetEvent(pIniJob->WaitForWrite);
|
|
|
|
SPLASSERT(pIniJob->cRef != 0);
|
|
|
|
DECJOBREF(pIniJob);
|
|
|
|
DBGMSG(DBG_TRACE, ("ScheduleJob:cRef = %d\n", pIniJob->cRef));
|
|
|
|
GetFullNameFromId(pSpool->pIniPrinter, pIniJob->JobId, TRUE,
|
|
FindData.cFileName, FALSE);
|
|
if ((fFile = FindFirstFile(FindData.cFileName, &FindData)) == INVALID_HANDLE_VALUE) {
|
|
DBGMSG(DBG_WARNING, ("Could not FindFirst the file %ws in ScheduleJob\n",
|
|
FindData.cFileName));
|
|
DeleteJob(pIniJob, BROADCAST);
|
|
pSpool->pIniJob = NULL;
|
|
pSpool->Status &= ~SPOOL_STATUS_ADDJOB;
|
|
LeaveSplSem();
|
|
SetLastError(ERROR_SPOOL_FILE_NOT_FOUND);
|
|
return(FALSE);
|
|
}
|
|
if (!FindClose(fFile)) {
|
|
DBGMSG(DBG_WARNING, ("FindClose failed %d %d\n", fFile, GetLastError()));
|
|
}
|
|
|
|
//
|
|
// If size changed, we must update our size
|
|
// and potentially notify people.
|
|
//
|
|
if (pIniJob->Size != FindData.nFileSizeLow) {
|
|
ADDNV(NotifyVector, NVSpoolJob);
|
|
pIniJob->Size = FindData.nFileSizeLow;
|
|
}
|
|
|
|
WriteShadowJob(pIniJob);
|
|
|
|
if (pIniJob->Status & JOB_PENDING_DELETION) {
|
|
|
|
DBGMSG(DBG_TRACE, ("LocalScheduleJob: Deleting Job because its pending deletion\n"));
|
|
DeleteJob(pIniJob, BROADCAST);
|
|
|
|
} else {
|
|
|
|
CHECK_SCHEDULER();
|
|
|
|
SetPrinterChange(pIniJob->pIniPrinter,
|
|
pIniJob,
|
|
NotifyVector,
|
|
PRINTER_CHANGE_SET_JOB,
|
|
pIniJob->pIniPrinter->pIniSpooler );
|
|
}
|
|
pSpool->pIniJob = NULL;
|
|
|
|
pSpool->Status &= ~SPOOL_STATUS_ADDJOB;
|
|
|
|
LeaveSplSem();
|
|
SplOutSem();
|
|
return(TRUE);
|
|
}
|