You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1998 lines
55 KiB
1998 lines
55 KiB
/*****************************************************************************\
|
|
* MODULE: ppjobs.c
|
|
*
|
|
* This module contains the print-job manipulating routines.
|
|
*
|
|
*
|
|
* Copyright (C) 1996-1997 Microsoft Corporation
|
|
* Copyright (C) 1996-1997 Hewlett Packard
|
|
*
|
|
* History:
|
|
* 07-Oct-1996 HWP-Guys Initiated port from win95 to winNT
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#include "priv.h"
|
|
|
|
BOOL
|
|
_ppprn_end_docprinter_async (
|
|
PCINETMONPORT pIniPort,
|
|
PJOBMAP pjmJob);
|
|
|
|
typedef struct _ADDJOB_INFO_2W {
|
|
LPWSTR pData;
|
|
DWORD JobId;
|
|
} ADDJOB_INFO_2W, *PADDJOB_INFO_2W, *LPADDJOB_INFO_2W;
|
|
|
|
|
|
DWORD
|
|
ppjob_GetOneSize (
|
|
DWORD dwLevel)
|
|
{
|
|
DWORD cbIdx;
|
|
|
|
switch (dwLevel) {
|
|
case PRINT_LEVEL_1:
|
|
cbIdx = sizeof(JOB_INFO_1);
|
|
break;
|
|
case PRINT_LEVEL_2:
|
|
cbIdx = sizeof(JOB_INFO_2);
|
|
break;
|
|
case PRINT_LEVEL_3:
|
|
cbIdx = sizeof(JOB_INFO_3);
|
|
break;
|
|
}
|
|
return cbIdx;
|
|
}
|
|
/*****************************************************************************\
|
|
* ppjob_IppPrtRsp (Local Routine)
|
|
*
|
|
* Retrieves a get response from the IPP server. Our (pjmJob) in the
|
|
* parameter list references a job-entry.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL CALLBACK ppjob_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("ppjob_IppPrtRsp : Receive Data Error")));
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
|
|
goto EndPrtRsp;
|
|
}
|
|
|
|
} else {
|
|
|
|
goto EndPrtRsp;
|
|
}
|
|
}
|
|
|
|
EndPrtRsp:
|
|
|
|
WebIppRcvClose(hIpp);
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************\
|
|
* ppjob_GetJobSize (Local Routine)
|
|
*
|
|
* Returns the size necessary to hold the jobinfo.
|
|
*
|
|
\*****************************************************************************/
|
|
DWORD ppjob_GetJobSize(
|
|
LPJOB_INFO_2 pji2,
|
|
DWORD dwLevel)
|
|
{
|
|
DWORD cbSize;
|
|
|
|
|
|
switch (dwLevel) {
|
|
|
|
case PRINT_LEVEL_1:
|
|
|
|
cbSize = sizeof(JOB_INFO_1) +
|
|
utlStrSize(pji2->pPrinterName) +
|
|
utlStrSize(pji2->pMachineName) +
|
|
utlStrSize(pji2->pUserName) +
|
|
utlStrSize(pji2->pDocument) +
|
|
utlStrSize(pji2->pDatatype) +
|
|
utlStrSize(pji2->pStatus);
|
|
break;
|
|
|
|
case PRINT_LEVEL_2:
|
|
|
|
cbSize = sizeof(JOB_INFO_2) +
|
|
utlStrSize(pji2->pPrinterName) +
|
|
utlStrSize(pji2->pMachineName) +
|
|
utlStrSize(pji2->pUserName) +
|
|
utlStrSize(pji2->pDocument) +
|
|
utlStrSize(pji2->pNotifyName) +
|
|
utlStrSize(pji2->pDatatype) +
|
|
utlStrSize(pji2->pPrintProcessor) +
|
|
utlStrSize(pji2->pParameters) +
|
|
utlStrSize(pji2->pDriverName) +
|
|
utlStrSize(pji2->pStatus);
|
|
|
|
if (pji2->pDevMode)
|
|
cbSize += (pji2->pDevMode->dmSize + pji2->pDevMode->dmDriverExtra);
|
|
|
|
cbSize = (cbSize + sizeof(DWORD)-1) & ~(sizeof(DWORD)-1);
|
|
|
|
break;
|
|
|
|
case PRINT_LEVEL_3:
|
|
cbSize = sizeof(JOB_INFO_3);
|
|
break;
|
|
|
|
default:
|
|
cbSize = 0;
|
|
break;
|
|
}
|
|
|
|
return cbSize;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* ppjob_CopyJob (Local Routine)
|
|
*
|
|
* Copies a job-info structure to another.
|
|
*
|
|
\*****************************************************************************/
|
|
LPBYTE ppjob_CopyJob(
|
|
LPBYTE pbJobDst,
|
|
DWORD dwLevel,
|
|
LPJOB_INFO_2 pji2Src,
|
|
LPBYTE pbEnd)
|
|
{
|
|
LPJOB_INFO_1 pji1Dst;
|
|
LPJOB_INFO_2 pji2Dst;
|
|
LPJOB_INFO_3 pji3Dst;
|
|
LPJOBMAP pjm;
|
|
LPDWORD pOffsets;
|
|
DWORD cbDM;
|
|
LPTSTR* lpszSrc;
|
|
LPTSTR aszSrc[(sizeof(JOB_INFO_2) / sizeof(LPTSTR))];
|
|
|
|
static DWORD s_JI1Offsets[] = {
|
|
|
|
offsetof(LPJOB_INFO_1, pPrinterName),
|
|
offsetof(LPJOB_INFO_1, pMachineName),
|
|
offsetof(LPJOB_INFO_1, pUserName),
|
|
offsetof(LPJOB_INFO_1, pDocument),
|
|
offsetof(LPJOB_INFO_1, pDatatype),
|
|
offsetof(LPJOB_INFO_1, pStatus),
|
|
0xFFFFFFFF
|
|
};
|
|
|
|
static DWORD s_JI2Offsets[] = {
|
|
|
|
offsetof(LPJOB_INFO_2, pPrinterName),
|
|
offsetof(LPJOB_INFO_2, pMachineName),
|
|
offsetof(LPJOB_INFO_2, pUserName),
|
|
offsetof(LPJOB_INFO_2, pDocument),
|
|
offsetof(LPJOB_INFO_2, pNotifyName),
|
|
offsetof(LPJOB_INFO_2, pDatatype),
|
|
offsetof(LPJOB_INFO_2, pPrintProcessor),
|
|
offsetof(LPJOB_INFO_2, pParameters),
|
|
offsetof(LPJOB_INFO_2, pDriverName),
|
|
offsetof(LPJOB_INFO_2, pDevMode),
|
|
offsetof(LPJOB_INFO_2, pStatus),
|
|
offsetof(LPJOB_INFO_2, pSecurityDescriptor),
|
|
0xFFFFFFFF
|
|
};
|
|
|
|
static DWORD s_JI3Offsets[]={0xFFFFFFFF};
|
|
|
|
|
|
// Set the start of the string-buffer.
|
|
//
|
|
ZeroMemory(aszSrc, sizeof(aszSrc));
|
|
lpszSrc = aszSrc;
|
|
|
|
|
|
// Process the appropriate structure.
|
|
//
|
|
switch (dwLevel) {
|
|
|
|
case PRINT_LEVEL_1:
|
|
|
|
pji1Dst = (LPJOB_INFO_1)pbJobDst;
|
|
pOffsets = s_JI1Offsets;
|
|
|
|
|
|
// Copy fixed values.
|
|
//
|
|
pji1Dst->JobId = pji2Src->JobId;
|
|
pji1Dst->Status = pji2Src->Status;
|
|
pji1Dst->Priority = pji2Src->Priority;
|
|
pji1Dst->Position = pji2Src->Position;
|
|
pji1Dst->TotalPages = pji2Src->TotalPages;
|
|
pji1Dst->PagesPrinted = pji2Src->PagesPrinted;
|
|
pji1Dst->Submitted = pji2Src->Submitted;
|
|
|
|
|
|
// Copy strings.
|
|
//
|
|
*lpszSrc++ = pji2Src->pPrinterName;
|
|
*lpszSrc++ = pji2Src->pMachineName;
|
|
*lpszSrc++ = pji2Src->pUserName;
|
|
*lpszSrc++ = pji2Src->pDocument;
|
|
*lpszSrc++ = pji2Src->pDatatype;
|
|
*lpszSrc++ = pji2Src->pStatus;
|
|
|
|
break;
|
|
|
|
case PRINT_LEVEL_2:
|
|
|
|
pji2Dst = (LPJOB_INFO_2)pbJobDst;
|
|
pOffsets = s_JI2Offsets;
|
|
|
|
|
|
// Copy fixed values.
|
|
//
|
|
pji2Dst->JobId = pji2Src->JobId;
|
|
pji2Dst->Status = pji2Src->Status;
|
|
pji2Dst->Priority = pji2Src->Priority;
|
|
pji2Dst->Position = pji2Src->Position;
|
|
pji2Dst->StartTime = pji2Src->StartTime;
|
|
pji2Dst->UntilTime = pji2Src->UntilTime;
|
|
pji2Dst->TotalPages = pji2Src->TotalPages;
|
|
pji2Dst->Size = pji2Src->Size;
|
|
pji2Dst->Submitted = pji2Src->Submitted;
|
|
pji2Dst->Time = pji2Src->Time;
|
|
pji2Dst->PagesPrinted = pji2Src->PagesPrinted;
|
|
pji2Dst->pSecurityDescriptor = NULL;
|
|
pji2Dst->pDevMode = NULL;
|
|
|
|
|
|
// Copy strings.
|
|
//
|
|
*lpszSrc++ = pji2Src->pPrinterName;
|
|
*lpszSrc++ = pji2Src->pMachineName;
|
|
*lpszSrc++ = pji2Src->pUserName;
|
|
*lpszSrc++ = pji2Src->pDocument;
|
|
*lpszSrc++ = pji2Src->pNotifyName;
|
|
*lpszSrc++ = pji2Src->pDatatype;
|
|
*lpszSrc++ = pji2Src->pPrintProcessor;
|
|
*lpszSrc++ = pji2Src->pParameters;
|
|
*lpszSrc++ = pji2Src->pDriverName;
|
|
*lpszSrc++ = NULL;
|
|
*lpszSrc++ = pji2Src->pStatus;
|
|
*lpszSrc++ = NULL;
|
|
|
|
|
|
if (pji2Src->pDevMode) {
|
|
|
|
cbDM = pji2Src->pDevMode->dmSize + pji2Src->pDevMode->dmDriverExtra;
|
|
|
|
pbEnd -= cbDM;
|
|
pbEnd = (LPBYTE)((UINT_PTR)pbEnd & ~((UINT_PTR)sizeof(UINT_PTR) - 1));
|
|
|
|
pji2Dst->pDevMode = (LPDEVMODE)pbEnd;
|
|
|
|
CopyMemory(pji2Dst->pDevMode, pji2Src->pDevMode, cbDM);
|
|
}
|
|
|
|
break;
|
|
|
|
case PRINT_LEVEL_3:
|
|
|
|
pji3Dst = (LPJOB_INFO_3)pbJobDst;
|
|
pOffsets = s_JI3Offsets;
|
|
|
|
pji3Dst->JobId = pji2Src->JobId;
|
|
break;
|
|
}
|
|
|
|
|
|
return utlPackStrings(aszSrc, (LPBYTE)pbJobDst, pOffsets, pbEnd);
|
|
}
|
|
|
|
BOOL ppjob_CalcAndCopyJob(
|
|
LPBYTE pbJob,
|
|
DWORD cbJob,
|
|
PDWORD pcbNeed,
|
|
PJOB_INFO_2 pji2,
|
|
DWORD dwLevel)
|
|
{
|
|
|
|
BOOL bRet = FALSE;
|
|
LPBYTE pbEnd;
|
|
|
|
// Fill in what we need.
|
|
//
|
|
*pcbNeed = ppjob_GetJobSize(pji2, dwLevel);
|
|
|
|
// If our buffer is big-enough, then
|
|
// proceed to fill in the info.
|
|
//
|
|
if (cbJob >= *pcbNeed) {
|
|
|
|
pbEnd = pbJob + cbJob;
|
|
|
|
ppjob_CopyJob(pbJob, dwLevel, pji2, pbEnd);
|
|
|
|
bRet = TRUE;
|
|
|
|
} else {
|
|
|
|
SetLastError (ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* ppjob_IppEnuRsp (Local Callback Routine)
|
|
*
|
|
* Retrieves a get response from the IPP server. Our (lParam) in the
|
|
* parameter list references a LPPPJOB_ENUM pointer which we are to fill
|
|
* in from the enumeration.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL CALLBACK ppjob_IppEnuRsp(
|
|
CAnyConnection *pConnection,
|
|
HINTERNET hReq,
|
|
PCINETMONPORT pIniPort,
|
|
LPARAM lParam)
|
|
{
|
|
HANDLE hIpp;
|
|
DWORD dwRet;
|
|
DWORD cbRd;
|
|
LPBYTE pbEnd;
|
|
DWORD idx;
|
|
DWORD idx2;
|
|
LPBYTE lpDta;
|
|
DWORD cbDta;
|
|
LPIPPRET_ENUJOB lpRsp;
|
|
DWORD cbRsp;
|
|
LPPPJOB_ENUM pje;
|
|
LPIPPJI2 pji2;
|
|
LPJOBMAP pjm;
|
|
PDWORD pidJob;
|
|
DWORD cbSize;
|
|
PJOBMAP* pjmList;
|
|
BYTE bBuf[MAX_IPP_BUFFER];
|
|
BOOL bRet = FALSE;
|
|
time_t dwPrinterT0;
|
|
|
|
|
|
|
|
if (hIpp = WebIppRcvOpen(IPP_RET_ENUJOB)) {
|
|
|
|
while (TRUE) {
|
|
|
|
cbRd = 0;
|
|
if (pIniPort->ReadFile ( pConnection, hReq, (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) {
|
|
|
|
|
|
if (lpRsp->cItems && lpRsp->cbItems) {
|
|
|
|
semEnterCrit();
|
|
pjmList = pIniPort->GetPJMList();
|
|
|
|
pjmCleanRemoteFlag(pjmList);
|
|
|
|
pji2 = lpRsp->pItems;
|
|
|
|
// We go over the IPP response and put them into PJM list
|
|
// At the mean time, we convert the remote job ID to
|
|
// local job id and store them into the IPP response
|
|
// data structure.
|
|
//
|
|
|
|
for (idx = 0; idx < lpRsp->cItems; idx++) {
|
|
|
|
// Fixup the job-id to the local id we
|
|
// can deal with.
|
|
//
|
|
pidJob = & (pji2[idx].ji2.JobId);
|
|
|
|
if (pjm = pjmFind(pjmList, PJM_REMOTEID, *pidJob)) {
|
|
|
|
*pidJob = pjmJobId(pjm, PJM_LOCALID);
|
|
|
|
} else {
|
|
|
|
if (pjm = pjmAdd(pjmList, pIniPort, NULL, NULL))
|
|
pjmSetJobRemote(pjm, *pidJob, pji2[idx].ipp.pJobUri);
|
|
|
|
*pidJob = pjmJobId(pjm, PJM_LOCALID);
|
|
}
|
|
}
|
|
|
|
// Call our routine to clean our client-list
|
|
// of jobs. This will remove any entries
|
|
// that no longer exist on the server.
|
|
//
|
|
cbSize = sizeof(PPJOB_ENUM) + lpRsp->cbItems;
|
|
|
|
// Allocate storage for enumeration.
|
|
//
|
|
if (pje = (LPPPJOB_ENUM)memAlloc(cbSize)) {
|
|
dwPrinterT0 = pIniPort->GetPowerUpTime();
|
|
// This now containts the powerup time for the printer in
|
|
// our time
|
|
|
|
|
|
pje->cItems = lpRsp->cItems;
|
|
pje->cbSize = lpRsp->cbItems;
|
|
|
|
|
|
pji2 = lpRsp->pItems;
|
|
pbEnd = ((LPBYTE)pje->ji2) + pje->cbSize;
|
|
|
|
for (idx = 0; idx < lpRsp->cItems; idx++) {
|
|
|
|
|
|
pbEnd = ppjob_CopyJob((LPBYTE)&pje->ji2[idx],
|
|
2,
|
|
&pji2[idx].ji2,
|
|
pbEnd);
|
|
|
|
WebIppConvertSystemTime(&pje->ji2[idx].ji2.Submitted, dwPrinterT0);
|
|
|
|
}
|
|
|
|
|
|
pjmRemoveOldEntries(pjmList);
|
|
|
|
semLeaveCrit();
|
|
|
|
*((LPPPJOB_ENUM *)lParam) = pje;
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
}
|
|
}
|
|
else {
|
|
|
|
//
|
|
// This is the case where the job count is 0 on the server
|
|
// We still need to allocate the structure so that the client
|
|
// enum-job function can merge the localjobs.
|
|
//
|
|
|
|
cbSize = sizeof(PPJOB_ENUM);
|
|
|
|
// Allocate storage for enumeration.
|
|
//
|
|
if (pje = (LPPPJOB_ENUM)memAlloc(cbSize)) {
|
|
|
|
pje->cItems = 0;
|
|
pje->cbSize = 0;
|
|
|
|
*((LPPPJOB_ENUM *)lParam) = pje;
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
}
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
SetLastError(lpRsp->dwLastError);
|
|
}
|
|
|
|
WebIppFreeMem(lpRsp);
|
|
|
|
goto EndEnuRsp;
|
|
|
|
case WEBIPP_MOREDATA:
|
|
|
|
// Need to do another read to fullfill our header-response.
|
|
//
|
|
break;
|
|
|
|
default:
|
|
|
|
DBG_MSG(DBG_LEV_ERROR, (TEXT("ppjob_IppEnuRsp : Receive Data Error")));
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
|
|
goto EndEnuRsp;
|
|
}
|
|
|
|
} else {
|
|
|
|
goto EndEnuRsp;
|
|
}
|
|
}
|
|
|
|
EndEnuRsp:
|
|
|
|
WebIppRcvClose(hIpp);
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* ppjob_IppSetRsp (Local Callback Routine)
|
|
*
|
|
* Retrieves a SetJob response from the IPP server
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL CALLBACK ppjob_IppSetRsp(
|
|
CAnyConnection *pConnection,
|
|
HINTERNET hReq,
|
|
PCINETMONPORT pIniPort,
|
|
LPARAM lParam)
|
|
{
|
|
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((WORD)(LPARAM)lParam)) {
|
|
|
|
while (TRUE) {
|
|
|
|
cbRd = 0;
|
|
if (pIniPort->ReadFile (pConnection, hReq, (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) == FALSE)
|
|
SetLastError(lpRsp->dwLastError);
|
|
|
|
WebIppFreeMem(lpRsp);
|
|
|
|
goto EndSetRsp;
|
|
|
|
case WEBIPP_MOREDATA:
|
|
|
|
// Need to do another read to fullfill our header-response.
|
|
//
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DBG_MSG(DBG_LEV_ERROR, (TEXT("ppjob_IppSetRsp : Receive Data Error")));
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
|
|
goto EndSetRsp;
|
|
}
|
|
|
|
} else {
|
|
|
|
goto EndSetRsp;
|
|
}
|
|
}
|
|
|
|
EndSetRsp:
|
|
|
|
WebIppRcvClose(hIpp);
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* ppjob_IppGetRsp (Local Callback Routine)
|
|
*
|
|
* Retrieves a get response from the IPP server. Our (lParam) in the
|
|
* parameter list references a JOB_INFO_2 pointer which we are to fill
|
|
* in from the call.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL CALLBACK ppjob_IppGetRsp(
|
|
CAnyConnection *pConnection,
|
|
HINTERNET hReq,
|
|
PCINETMONPORT pIniPort,
|
|
LPARAM lParam)
|
|
{
|
|
HANDLE hIpp;
|
|
DWORD dwRet;
|
|
DWORD cbRd;
|
|
LPBYTE pbEnd;
|
|
DWORD idx;
|
|
LPBYTE lpDta;
|
|
DWORD cbDta;
|
|
LPIPPRET_JOB lpRsp;
|
|
DWORD cbRsp;
|
|
LPJOB_INFO_2 pji2;
|
|
LPJOBMAP pjm;
|
|
DWORD cbSize;
|
|
BYTE bBuf[MAX_IPP_BUFFER];
|
|
PJOBMAP* pjmList;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
if (hIpp = WebIppRcvOpen(IPP_RET_GETJOB)) {
|
|
|
|
while (TRUE) {
|
|
|
|
cbRd = 0;
|
|
if (pIniPort->ReadFile ( pConnection, hReq, (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) {
|
|
|
|
cbSize = ppjob_GetJobSize(&lpRsp->ji.ji2, 2);
|
|
|
|
// Allocate storage for enumeration.
|
|
//
|
|
if (pji2 = (LPJOB_INFO_2)memAlloc(cbSize)) {
|
|
|
|
pbEnd = ((LPBYTE)pji2) + cbSize;
|
|
|
|
ppjob_CopyJob((LPBYTE)pji2, 2, &lpRsp->ji.ji2, pbEnd);
|
|
|
|
|
|
semEnterCrit();
|
|
|
|
pjmList = pIniPort->GetPJMList();
|
|
|
|
|
|
// Fixup the job-id to the local id we
|
|
// can deal with.
|
|
//
|
|
if (pjm = pjmFind(pjmList, PJM_REMOTEID, pji2->JobId)) {
|
|
|
|
pji2->JobId = pjmJobId(pjm, PJM_LOCALID);
|
|
|
|
} else {
|
|
|
|
if (pjm = pjmAdd(pjmList, pIniPort, NULL, NULL))
|
|
pjmSetJobRemote(pjm, pji2->JobId, lpRsp->ji.ipp.pJobUri);
|
|
|
|
pji2->JobId = pjmJobId(pjm, PJM_LOCALID);
|
|
}
|
|
|
|
semLeaveCrit();
|
|
|
|
|
|
*((LPJOB_INFO_2 *)lParam) = pji2;
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
SetLastError(lpRsp->dwLastError);
|
|
}
|
|
|
|
WebIppFreeMem(lpRsp);
|
|
|
|
goto EndGetRsp;
|
|
|
|
case WEBIPP_MOREDATA:
|
|
|
|
// Need to do another read to fullfill our header-response.
|
|
//
|
|
break;
|
|
|
|
default:
|
|
|
|
DBG_MSG(DBG_LEV_ERROR, (TEXT("ppjob_IppGetRsp - Err : Receive Data Error (dwRet=%d, LE=%d)"),
|
|
dwRet, WebIppGetError(hIpp)));
|
|
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
|
|
goto EndGetRsp;
|
|
}
|
|
|
|
} else {
|
|
|
|
goto EndGetRsp;
|
|
}
|
|
}
|
|
|
|
EndGetRsp:
|
|
|
|
WebIppRcvClose(hIpp);
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* ppjob_Set (Local Routine)
|
|
*
|
|
* Sets a job command in the queue.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL ppjob_Set(
|
|
PCINETMONPORT pIniPort,
|
|
DWORD idJob,
|
|
DWORD dwCmd)
|
|
{
|
|
PIPPREQ_SETJOB psj;
|
|
PJOBMAP pjm;
|
|
WORD wReq;
|
|
REQINFO ri;
|
|
DWORD dwRet;
|
|
LPBYTE lpIpp;
|
|
DWORD cbIpp;
|
|
PJOBMAP* pjmList;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
|
|
// Make sure we have a JobMap entry which we can
|
|
// obtain the remote information.
|
|
//
|
|
pjmList = pIniPort->GetPJMList();
|
|
|
|
if (pjm = pjmFind(pjmList, PJM_LOCALID, idJob)) {
|
|
|
|
// If we're still spooling, then we haven't yet
|
|
// hit the server. Otherwise, we've performed the EndDoc()
|
|
// and the job is being processed remotely.
|
|
//
|
|
if (pjmChkState(pjm, PJM_SPOOLING)) {
|
|
|
|
switch (dwCmd) {
|
|
case JOB_CONTROL_CANCEL:
|
|
case JOB_CONTROL_DELETE:
|
|
pjmSetState(pjm, PJM_CANCEL);
|
|
//
|
|
// If the async thread is on, we let that thread to clean the job queue
|
|
//
|
|
if (!pjmChkState(pjm, PJM_ASYNCON))
|
|
{
|
|
//
|
|
// Otherwise, we delete the job here.
|
|
//
|
|
pjmClrState (pjm, PJM_SPOOLING);
|
|
}
|
|
break;
|
|
|
|
case JOB_CONTROL_PAUSE:
|
|
pjmSetState(pjm, PJM_PAUSE);
|
|
break;
|
|
|
|
case JOB_CONTROL_RESUME:
|
|
pjmClrState(pjm, PJM_PAUSE);
|
|
break;
|
|
|
|
case JOB_CONTROL_RESTART:
|
|
pjmUpdateLocalJobStatus (pjm, JOB_STATUS_RESTART);
|
|
|
|
if (!pjmChkState(pjm, PJM_ASYNCON))
|
|
{
|
|
_ppprn_end_docprinter_async (pIniPort, pjm);
|
|
}
|
|
break;
|
|
}
|
|
|
|
bRet = TRUE;
|
|
|
|
} else {
|
|
|
|
// Look through list to get local/remote job mappings.
|
|
//
|
|
psj = WebIppCreateSetJobReq(pjmJobId(pjm, PJM_REMOTEID),
|
|
dwCmd,
|
|
pIniPort->GetPortName());
|
|
|
|
if (psj) {
|
|
|
|
switch (dwCmd) {
|
|
case JOB_CONTROL_CANCEL:
|
|
case JOB_CONTROL_DELETE:
|
|
wReq = IPP_REQ_CANCELJOB;
|
|
break;
|
|
|
|
case JOB_CONTROL_PAUSE:
|
|
wReq = IPP_REQ_PAUSEJOB;
|
|
break;
|
|
|
|
case JOB_CONTROL_RESUME:
|
|
wReq = IPP_REQ_RESUMEJOB;
|
|
break;
|
|
|
|
case JOB_CONTROL_RESTART:
|
|
wReq = IPP_REQ_RESTARTJOB;
|
|
break;
|
|
|
|
default:
|
|
wReq = 0;
|
|
break;
|
|
}
|
|
|
|
|
|
// Convert the reqest to IPP, and perform the
|
|
// post.
|
|
//
|
|
ZeroMemory(&ri, sizeof(REQINFO));
|
|
ri.cpReq = CP_UTF8;
|
|
ri.idReq = wReq;
|
|
|
|
ri.fReq[0] = IPP_REQALL;
|
|
ri.fReq[1] = IPP_REQALL;
|
|
|
|
dwRet = WebIppSndData(wReq,
|
|
&ri,
|
|
(LPBYTE)psj,
|
|
psj->cbSize,
|
|
&lpIpp,
|
|
&cbIpp);
|
|
|
|
|
|
// The request-structure has been converted to IPP format,
|
|
// so it is ready to go to the server.
|
|
//
|
|
if (dwRet == WEBIPP_OK) {
|
|
|
|
bRet = pIniPort->SendReq(lpIpp,
|
|
cbIpp,
|
|
ppjob_IppSetRsp,
|
|
(LPARAM)(wReq | IPP_RESPONSE),
|
|
TRUE);
|
|
|
|
WebIppFreeMem(lpIpp);
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
}
|
|
|
|
// Once we've verified the request for cancel, then
|
|
// we should remove the job from our list.
|
|
//
|
|
// NOTE: Should this be deleted always? Or should
|
|
// we make this dependent on the success of
|
|
// the server-call?
|
|
//
|
|
// 06-Jan-1998 <chriswil> Will Revisit.
|
|
//
|
|
if (dwCmd == JOB_CONTROL_CANCEL)
|
|
pjmDel(pjmList, pjm);
|
|
|
|
WebIppFreeMem(psj);
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* ppjob_Enum (Local Routine)
|
|
*
|
|
* Enumerates jobs. IPP has the ENUJOB request which can be used for both
|
|
* specific jobs, or enumerated-jobs. We will distinguish whether we're
|
|
* enumerating by a (IPP_GETJOB_ALL) job-id.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL ppjob_Enum(
|
|
PCINETMONPORT pIniPort,
|
|
DWORD nJobStart,
|
|
DWORD cJobs,
|
|
DWORD dwLevel,
|
|
LPBYTE pbJob,
|
|
DWORD cbJob,
|
|
LPDWORD pcbNeed,
|
|
LPDWORD pcItems)
|
|
{
|
|
PIPPREQ_ENUJOB pgj;
|
|
REQINFO ri;
|
|
DWORD dwRet;
|
|
LPBYTE lpIpp;
|
|
DWORD cbIpp;
|
|
DWORD idx;
|
|
DWORD cbSize;
|
|
DWORD cbIdx;
|
|
DWORD dwLastError = ERROR_INVALID_DATA;
|
|
LPBYTE pbEnd;
|
|
LPPPJOB_ENUM pje = NULL;
|
|
BOOL bRet = FALSE;
|
|
DWORD curIdx = 0;
|
|
DWORD dwLocalJobCount = 0;
|
|
DWORD cbLocalJobSize = 0;
|
|
PJOBMAP* pjmList;
|
|
PJOBMAP pjmTmpList;
|
|
JOB_INFO_2 JobInfo2;
|
|
BOOL bFound;
|
|
|
|
|
|
// Specifying (IPP_GETJOB_ALL) will enumerate all jobs.
|
|
//
|
|
|
|
pjmList = pIniPort->GetPJMList ();
|
|
pbEnd = pbJob + cbJob;
|
|
cbIdx = ppjob_GetOneSize (dwLevel);
|
|
|
|
if (pIniPort->BeginReadEnumJobsCache (&pje)) {
|
|
|
|
bRet = TRUE;
|
|
dwLastError = GetLastError();
|
|
|
|
// Upon return, our (pje) pointer contains an
|
|
// enumeration structure of JOB_INFO_2 items.
|
|
//
|
|
// Based upon the level passed in, we need to either
|
|
// return these items or a converted JOB_INFO_1.
|
|
//
|
|
if (pje) {
|
|
|
|
// Calculate the size we'll need to store the
|
|
// enumerated items.
|
|
//
|
|
for (idx = 0, cbSize = 0; idx < pje->cItems; idx++)
|
|
cbSize += ppjob_GetJobSize(&pje->ji2[idx].ji2, dwLevel);
|
|
|
|
dwLocalJobCount = pjmGetLocalJobCount(pjmList, &cbLocalJobSize);
|
|
|
|
if (dwLocalJobCount > 0) {
|
|
|
|
cbSize += cbLocalJobSize;
|
|
}
|
|
|
|
// Fill in the return-value indicating
|
|
// the buffer necessary to hold the items.
|
|
//
|
|
*pcbNeed = cbSize;
|
|
|
|
|
|
// If the user buffer is of sufficient size,
|
|
// then copy/convert the items.
|
|
//
|
|
if (cbJob >= cbSize) {
|
|
|
|
*pcItems = pje->cItems + dwLocalJobCount;
|
|
|
|
|
|
for (idx = 0; idx < pje->cItems && cJobs; idx++) {
|
|
|
|
if ((idx >= nJobStart)) {
|
|
|
|
pbEnd = ppjob_CopyJob(pbJob,
|
|
dwLevel,
|
|
&pje->ji2[idx].ji2,
|
|
pbEnd);
|
|
|
|
|
|
pbJob += cbIdx;
|
|
|
|
cJobs--;
|
|
}
|
|
}
|
|
|
|
curIdx = idx;
|
|
} else {
|
|
bRet = FALSE;
|
|
dwLastError = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
|
|
dwLocalJobCount = pjmGetLocalJobCount(pjmList, &cbLocalJobSize);
|
|
|
|
if (dwLocalJobCount > 0) {
|
|
|
|
cbSize = cbLocalJobSize;
|
|
|
|
// Fill in the return-value indicating
|
|
// the buffer necessary to hold the items.
|
|
//
|
|
*pcbNeed = cbSize;
|
|
|
|
// If the user buffer is of sufficient size,
|
|
// then copy/convert the items.
|
|
//
|
|
if (cbJob >= cbSize) {
|
|
|
|
*pcItems = dwLocalJobCount;
|
|
bRet = TRUE;
|
|
|
|
} else {
|
|
bRet = FALSE;
|
|
dwLastError = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
}
|
|
else {
|
|
dwLastError = GetLastError();
|
|
}
|
|
|
|
}
|
|
|
|
if (bRet) {
|
|
|
|
pjmTmpList = *pjmList;
|
|
|
|
for (idx = curIdx; idx < curIdx + dwLocalJobCount && cJobs; idx++) {
|
|
|
|
pjmTmpList = pjmNextLocalJob (&pjmTmpList, &JobInfo2, &bFound);
|
|
|
|
if ((idx >= nJobStart)) {
|
|
|
|
if (bFound) {
|
|
|
|
DBG_ASSERT( ((pbJob < pbEnd)?TRUE:FALSE),
|
|
(TEXT("ppjob_Enum: idx = %d, cbIdx = %d, cJobs = %d dwLocalJobCount = %d dwLocalSize=%d, pjd=%p\n"),
|
|
idx, cbIdx, cJobs, dwLocalJobCount, dwLocalJobCount, pje));
|
|
|
|
pbEnd = ppjob_CopyJob(pbJob,
|
|
dwLevel,
|
|
&JobInfo2,
|
|
pbEnd);
|
|
|
|
|
|
|
|
pbJob += cbIdx;
|
|
|
|
cJobs--;
|
|
}
|
|
else {
|
|
bRet = FALSE;
|
|
dwLastError = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// This function has to be called to release the critical section
|
|
//
|
|
pIniPort->EndReadEnumJobsCache ();
|
|
|
|
if (!bRet) {
|
|
|
|
SetLastError(dwLastError);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* ppjob_EnumForCache (Local Routine)
|
|
*
|
|
* Enumerates jobs. IPP has the ENUJOB request which can be used for both
|
|
* specific jobs, or enumerated-jobs. We will distinguish whether we're
|
|
* enumerating by a (IPP_GETJOB_ALL) job-id.
|
|
*
|
|
* Upon return, ppbJob stores a pointer to the cache
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL ppjob_EnumForCache(
|
|
PCINETMONPORT pIniPort,
|
|
LPPPJOB_ENUM *ppje)
|
|
{
|
|
PIPPREQ_ENUJOB pgj;
|
|
REQINFO ri;
|
|
DWORD dwRet;
|
|
LPBYTE lpIpp;
|
|
DWORD cbIpp;
|
|
DWORD idx;
|
|
DWORD cbSize;
|
|
DWORD cbIdx;
|
|
DWORD dwLastError = ERROR_INVALID_DATA;
|
|
LPBYTE pbEnd;
|
|
LPPPJOB_ENUM pje = NULL;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
|
|
// Specifying (IPP_GETJOB_ALL) will enumerate all jobs.
|
|
//
|
|
pgj = WebIppCreateEnuJobReq(IPP_GETJOB_ALL, pIniPort->GetPortName());
|
|
|
|
if (pgj) {
|
|
|
|
// Convert the reqest to IPP, and perform the
|
|
// post.
|
|
//
|
|
ZeroMemory(&ri, sizeof(REQINFO));
|
|
ri.cpReq = CP_UTF8;
|
|
ri.idReq = IPP_REQ_ENUJOB;
|
|
|
|
ri.fReq[0] = IPP_REQALL;
|
|
ri.fReq[1] = IPP_REQALL;
|
|
|
|
dwRet = WebIppSndData(IPP_REQ_ENUJOB,
|
|
&ri,
|
|
(LPBYTE)pgj,
|
|
pgj->cbSize,
|
|
&lpIpp,
|
|
&cbIpp);
|
|
|
|
|
|
// The request-structure has been converted to IPP format,
|
|
// so it is ready to go to the server.
|
|
//
|
|
if (dwRet == WEBIPP_OK) {
|
|
|
|
// This routine returns with a LastError set to that
|
|
// which the response-routine sets.
|
|
//
|
|
if (pIniPort->SendReq(lpIpp,
|
|
cbIpp,
|
|
ppjob_IppEnuRsp,
|
|
(LPARAM)&pje,
|
|
TRUE)) {
|
|
|
|
dwLastError = GetLastError();
|
|
bRet = TRUE;
|
|
*ppje = pje;
|
|
|
|
} else {
|
|
|
|
dwLastError = GetLastError();
|
|
}
|
|
|
|
WebIppFreeMem(lpIpp);
|
|
|
|
} else {
|
|
|
|
dwLastError = ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
WebIppFreeMem(pgj);
|
|
|
|
} else {
|
|
|
|
dwLastError = ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
if (!bRet) {
|
|
|
|
SetLastError(dwLastError);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* ppjob_Get (Local Routine)
|
|
*
|
|
* Returns information regarding a job.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL ppjob_Get(
|
|
PCINETMONPORT pIniPort,
|
|
DWORD idJob,
|
|
DWORD dwLevel,
|
|
LPBYTE pbJob,
|
|
DWORD cbJob,
|
|
LPDWORD pcbNeed)
|
|
{
|
|
PJOBMAP pjm;
|
|
PIPPREQ_GETJOB pgj;
|
|
REQINFO ri;
|
|
LPBYTE lpIpp;
|
|
DWORD cbIpp;
|
|
DWORD dwRet;
|
|
LPBYTE pbEnd;
|
|
PJOBMAP* pjmList;
|
|
LPJOB_INFO_2 pji2 = NULL;
|
|
BOOL bRet = FALSE;
|
|
DWORD dwLastError = ERROR_INVALID_DATA;
|
|
|
|
|
|
// Look in our JobMap list for the local-job-id. If we see
|
|
// one, the we can get the job-information.
|
|
//
|
|
pjmList = pIniPort->GetPJMList();
|
|
|
|
if (pjm = pjmFind(pjmList, PJM_LOCALID, idJob)) {
|
|
|
|
if (pjm->bRemoteJob) {
|
|
|
|
// Build a request-structure that we will pass into
|
|
// the IPP layer for processing.
|
|
//
|
|
pgj = WebIppCreateGetJobReq(pjmJobId(pjm, PJM_REMOTEID), pIniPort->GetPortName());
|
|
|
|
if (pgj) {
|
|
|
|
// Convert the reqest to IPP that is suitible for
|
|
// our post.
|
|
//
|
|
ZeroMemory(&ri, sizeof(REQINFO));
|
|
ri.cpReq = CP_UTF8;
|
|
ri.idReq = IPP_REQ_GETJOB;
|
|
|
|
ri.fReq[0] = IPP_REQALL;
|
|
ri.fReq[1] = IPP_REQALL;
|
|
|
|
dwRet = WebIppSndData(IPP_REQ_GETJOB,
|
|
&ri,
|
|
(LPBYTE)pgj,
|
|
pgj->cbSize,
|
|
&lpIpp,
|
|
&cbIpp);
|
|
|
|
|
|
// The request-structure has been converted to IPP format,
|
|
// so it is ready to go to the server. We set a callback
|
|
// to the function that will receive our data.
|
|
//
|
|
if (dwRet == WEBIPP_OK) {
|
|
|
|
pIniPort->SendReq(lpIpp,
|
|
cbIpp,
|
|
ppjob_IppGetRsp,
|
|
(LPARAM)&pji2,
|
|
TRUE);
|
|
|
|
|
|
// Upon return, our (pji2) contains the JOB_INFO_2
|
|
// structure.
|
|
//
|
|
if (pji2) {
|
|
|
|
bRet = ppjob_CalcAndCopyJob(pbJob, cbJob, pcbNeed, pji2, dwLevel);
|
|
|
|
if (!bRet) {
|
|
dwLastError = GetLastError ();
|
|
}
|
|
|
|
memFree(pji2, memGetSize(pji2));
|
|
}
|
|
|
|
WebIppFreeMem(lpIpp);
|
|
|
|
} else {
|
|
|
|
dwLastError = ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
WebIppFreeMem(pgj);
|
|
|
|
} else {
|
|
|
|
dwLastError = ERROR_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else {
|
|
|
|
//
|
|
// This is a local job
|
|
//
|
|
|
|
if (pjm = pjmFind(pjmList, PJM_LOCALID, idJob)) {
|
|
|
|
JOB_INFO_2 JobInfo2;
|
|
BOOL bFound;
|
|
|
|
pjmNextLocalJob(&pjm, &JobInfo2, &bFound);
|
|
|
|
if (bFound) {
|
|
|
|
bRet = ppjob_CalcAndCopyJob(pbJob, cbJob, pcbNeed, &JobInfo2, dwLevel);
|
|
|
|
if (!bRet) {
|
|
dwLastError = GetLastError ();
|
|
}
|
|
}
|
|
else
|
|
dwLastError = ERROR_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
dwLastError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dwLastError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
// Set the lasterror if failure.
|
|
//
|
|
if (!bRet) {
|
|
|
|
SetLastError(dwLastError);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* ppjob_Add (Local Routine)
|
|
*
|
|
* Returns information for an addjob call.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL ppjob_Add(
|
|
HANDLE hPrinter,
|
|
PCINETMONPORT pIniPort,
|
|
DWORD dwLevel,
|
|
LPCTSTR lpszName,
|
|
LPBYTE pbData,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded)
|
|
{
|
|
PJOBMAP pjm;
|
|
LPCTSTR lpszSplFile;
|
|
LPTSTR* lpszSrc;
|
|
LPBYTE pbEnd;
|
|
PJOBMAP* pjmList;
|
|
LPTSTR aszSrc[(sizeof(ADDJOB_INFO_1) / sizeof(LPTSTR))];
|
|
BOOL bRet = FALSE;
|
|
|
|
static DWORD s_AJI1Offsets[] = {
|
|
offsetof(LPADDJOB_INFO_1, Path),
|
|
0xFFFFFFFF
|
|
};
|
|
|
|
|
|
// Create a spool-file and job that we will use
|
|
// for this AddJob() call.
|
|
//
|
|
pjmList = pIniPort->GetPJMList();
|
|
|
|
if (pjm = pjmAdd(pjmList, pIniPort, lpszName, NULL)) {
|
|
|
|
// Set the job into spooling-state. This internally
|
|
// creates the spool-file. By specifying PJM_NOOPEN,
|
|
// we indicate that no open-handles are to be maintained
|
|
// on the spool-file.
|
|
//
|
|
if (pjmSetState(pjm, PJM_SPOOLING | PJM_NOOPEN)) {
|
|
|
|
// Get the spool-file.
|
|
//
|
|
lpszSplFile = pjmSplFile(pjm);
|
|
|
|
|
|
// If a return-size is provided, then set it.
|
|
//
|
|
if (pcbNeeded)
|
|
*pcbNeeded = sizeof(ADDJOB_INFO_1) + utlStrSize(lpszSplFile);
|
|
|
|
|
|
// If the buffer is capable of holding the
|
|
// return-structure, then proceed.
|
|
//
|
|
if (pbData && (cbBuf >= *pcbNeeded)) {
|
|
|
|
// Clean out the string-array and setup
|
|
// for building the structure.
|
|
//
|
|
ZeroMemory(aszSrc, sizeof(aszSrc));
|
|
lpszSrc = aszSrc;
|
|
|
|
|
|
// Initialize fixed values.
|
|
//
|
|
((LPADDJOB_INFO_1)pbData)->JobId = pjmJobId(pjm, PJM_LOCALID);
|
|
|
|
|
|
// Pack the file-name into the return-structure.
|
|
//
|
|
pbEnd = pbData + cbBuf;
|
|
*lpszSrc++ = (LPTSTR)lpszSplFile;
|
|
utlPackStrings(aszSrc, pbData, s_AJI1Offsets, pbEnd);
|
|
|
|
|
|
// Mark this printer to indicate it's in a
|
|
// addjob.
|
|
//
|
|
// NOTE: do we really need to consume the printer
|
|
// for an AddJob(). LocalSpl does this and
|
|
// sets the job into the printer. I don't
|
|
// see why this is necessary.
|
|
//
|
|
PP_SetStatus(hPrinter, PP_ADDJOB);
|
|
|
|
bRet = TRUE;
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_FILE_NOT_FOUND);
|
|
}
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* ppjob_Schedule (Local Routine)
|
|
*
|
|
* Prints the scheduled job.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL ppjob_Schedule(
|
|
HANDLE hPrinter,
|
|
PCINETMONPORT pIniPort,
|
|
PJOBMAP pjm)
|
|
{
|
|
HANDLE hOut;
|
|
BOOL bRemote;
|
|
LPCTSTR lpszUser;
|
|
PIPPREQ_PRTJOB ppj;
|
|
REQINFO ri;
|
|
LPBYTE pbOut;
|
|
LPBYTE pbIpp;
|
|
LPBYTE pbSpl;
|
|
DWORD cbOut;
|
|
DWORD cbIpp;
|
|
DWORD cbSpl;
|
|
DWORD dwRet;
|
|
DWORD cbWr;
|
|
PJOBMAP* pjmList;
|
|
DWORD dwLE = ERROR_INVALID_HANDLE;
|
|
CFileStream *pStream = NULL;
|
|
CFileStream *pSplStream = NULL;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
// Lock the file so we can obtain the spool-data.
|
|
//
|
|
pjmList = pIniPort->GetPJMList();
|
|
|
|
if (pSplStream = pjmSplLock(pjm)) {
|
|
|
|
// Check to determine if this is a remote-call.
|
|
//
|
|
bRemote = TRUE;
|
|
|
|
|
|
// Get the user-name if one was specified in AddJob().
|
|
//
|
|
lpszUser = pjmSplUser(pjm);
|
|
|
|
|
|
// Create the print-job-request that we'll be using.
|
|
//
|
|
ppj = WebIppCreatePrtJobReq(FALSE,
|
|
(lpszUser ? lpszUser : TEXT("Unknown")),
|
|
(bRemote ? g_szDocRemote: g_szDocLocal),
|
|
pIniPort->GetPortName());
|
|
|
|
if (ppj) {
|
|
|
|
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,
|
|
&pbIpp,
|
|
&cbIpp);
|
|
|
|
// Make sure we were able to get the ipp-header.
|
|
//
|
|
if (dwRet == WEBIPP_OK) {
|
|
|
|
// Create the outputfile that will be used to
|
|
// contain both the ipp-header as well as the
|
|
// spool-data.
|
|
//
|
|
if (hOut = SplCreate(pjmJobId(pjm, PJM_LOCALID), SPLFILE_SPL)) {
|
|
|
|
// Output the header and data.
|
|
//
|
|
if (SplWrite(hOut, pbIpp, cbIpp, &cbWr) &&
|
|
SplWrite(hOut, pSplStream) &&
|
|
|
|
// Output the request.
|
|
//
|
|
(pStream = SplLock(hOut))) {
|
|
|
|
bRet = pIniPort->SendReq(pStream,
|
|
(IPPRSPPROC)ppjob_IppPrtRsp,
|
|
(LPARAM)pjm,
|
|
TRUE);
|
|
|
|
if (bRet == FALSE)
|
|
dwLE = GetLastError();
|
|
|
|
SplUnlock(hOut);
|
|
|
|
} else {
|
|
|
|
dwLE = GetLastError();
|
|
}
|
|
|
|
|
|
// Free up the spool-output-file.
|
|
//
|
|
SplFree(hOut);
|
|
|
|
} else {
|
|
|
|
dwLE = GetLastError();
|
|
}
|
|
|
|
WebIppFreeMem(pbIpp);
|
|
|
|
} else {
|
|
|
|
dwLE = ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
WebIppFreeMem(ppj);
|
|
|
|
} else {
|
|
|
|
dwLE = ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
pjmSplUnlock(pjm);
|
|
|
|
} else {
|
|
|
|
dwLE = GetLastError();
|
|
}
|
|
|
|
|
|
// Clear out our spooling-status. This will close
|
|
// and delete the spool-file as the job is now in the
|
|
// hands of spooler.
|
|
//
|
|
pjmClrState(pjm, PJM_SPOOLING);
|
|
|
|
|
|
// If a cancel was set on this job, then delete it's entry from
|
|
// our list.
|
|
//
|
|
if (pjmChkState(pjm, PJM_CANCEL) && pjmList != NULL)
|
|
pjmDel(pjmList, pjm);
|
|
|
|
|
|
// Set lasterror if problem occured.
|
|
//
|
|
if (bRet == FALSE)
|
|
SetLastError(dwLE);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* PPEnumJobs
|
|
*
|
|
* Retrives the information about a specified set of print jobs for a
|
|
* specified printer. Returns TRUE if successful. Otherwise, it returns
|
|
* FALSE.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL PPEnumJobs(
|
|
HANDLE hPrinter,
|
|
DWORD nJobStart,
|
|
DWORD cJobs,
|
|
DWORD dwLevel,
|
|
LPBYTE pbJob,
|
|
DWORD cbJob,
|
|
LPDWORD pcbNeeded,
|
|
LPDWORD pcItems)
|
|
{
|
|
PCINETMONPORT pIniPort;
|
|
BOOL bRet = FALSE;
|
|
|
|
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPEnumJobs: Printer(%08lX) dwLevel(%d)"), hPrinter, dwLevel));
|
|
|
|
semEnterCrit();
|
|
|
|
*pcbNeeded = 0;
|
|
*pcItems = 0;
|
|
|
|
|
|
// Make sure we have a valid printer handle.
|
|
//
|
|
if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
|
|
|
|
// Attempt to get a list of jobs from the ipp print spooler.
|
|
// Format the job information to the requested information level.
|
|
//
|
|
switch (dwLevel) {
|
|
|
|
case PRINT_LEVEL_1:
|
|
case PRINT_LEVEL_2:
|
|
|
|
bRet = ppjob_Enum(pIniPort,
|
|
nJobStart,
|
|
cJobs,
|
|
dwLevel,
|
|
pbJob,
|
|
cbJob,
|
|
pcbNeeded,
|
|
pcItems);
|
|
break;
|
|
|
|
default:
|
|
DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPEnumJobs: Invalid Level (%d)"), dwLevel));
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
break;
|
|
}
|
|
}
|
|
|
|
semLeaveCrit();
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* PPGetJob
|
|
*
|
|
* Retrieves information about a print job on a specified printer. Returns
|
|
* TRUE if successful. Otherwise, it returns FASLSE.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL PPGetJob(
|
|
HANDLE hPrinter,
|
|
DWORD idJob,
|
|
DWORD dwLevel,
|
|
LPBYTE pbJob,
|
|
DWORD cbJob,
|
|
LPDWORD pcbNeed)
|
|
{
|
|
PCINETMONPORT pIniPort;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPGetJob: Printer(%08lX) dwLevel(%d)"), hPrinter, dwLevel));
|
|
|
|
semEnterCrit();
|
|
|
|
*pcbNeed = 0;
|
|
|
|
// Make sure we're looking at a valid printer handle.
|
|
//
|
|
if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
|
|
|
|
// Switch on print-level.
|
|
//
|
|
switch (dwLevel) {
|
|
|
|
case PRINT_LEVEL_1:
|
|
case PRINT_LEVEL_2:
|
|
|
|
bRet = ppjob_Get(pIniPort, idJob, dwLevel, pbJob, cbJob, pcbNeed);
|
|
break;
|
|
|
|
default:
|
|
DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPGetJob: Invalid Level (%d)"), dwLevel));
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
break;
|
|
}
|
|
}
|
|
|
|
semLeaveCrit();
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* PPSetJob
|
|
*
|
|
* Sets information for and issues commands to a print job. Returns TRUE
|
|
* if successful. Otherwise, it returns FALSE.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL PPSetJob(
|
|
HANDLE hPrinter,
|
|
DWORD dwJobId,
|
|
DWORD dwLevel,
|
|
LPBYTE pbJob,
|
|
DWORD dwCmd)
|
|
{
|
|
PCINETMONPORT pIniPort;
|
|
BOOL bResult = FALSE;
|
|
|
|
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPSetJob: Printer(%08lX) dwLevel(%d)"), hPrinter, dwLevel));
|
|
|
|
semEnterCrit();
|
|
|
|
// Make sure we've got a valid printer handle.
|
|
//
|
|
if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
|
|
|
|
// Set job parameters.
|
|
//
|
|
switch (dwLevel) {
|
|
|
|
case PRINT_LEVEL_0:
|
|
|
|
// Do not set parameters. (0) represents "no-command".
|
|
//
|
|
switch (dwCmd) {
|
|
|
|
case JOB_CONTROL_CANCEL:
|
|
case JOB_CONTROL_DELETE:
|
|
case JOB_CONTROL_PAUSE:
|
|
case JOB_CONTROL_RESUME:
|
|
case JOB_CONTROL_RESTART:
|
|
bResult = ppjob_Set(pIniPort, dwJobId, dwCmd);
|
|
if (bResult) {
|
|
// Invalidate has to occur before notfication refresh, otherwise, you
|
|
// get an outdated result
|
|
//
|
|
pIniPort->InvalidateEnumJobsCache ();
|
|
pIniPort->InvalidateGetPrinterCache ();
|
|
|
|
RefreshNotification((LPINET_HPRINTER)hPrinter);
|
|
}
|
|
break;
|
|
|
|
case 0:
|
|
bResult = TRUE;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPSetJob: Invalid Level (%d)"), dwLevel));
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
semLeaveCrit();
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* PPAddJob
|
|
*
|
|
* Sets up for a local-spooled job. Since we are truly a remote-printer, we
|
|
* need to fail this call and signify the correct error-code.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL PPAddJob(
|
|
HANDLE hPrinter,
|
|
DWORD dwLevel,
|
|
LPBYTE pbData,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded)
|
|
{
|
|
PCINETMONPORT pIniPort;
|
|
LPTSTR lpszName;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPAddJob: Printer(%08lX) dwLevel(%d)"), hPrinter, dwLevel));
|
|
|
|
|
|
// Zero out the return-parameters.
|
|
//
|
|
*pcbNeeded = 0;
|
|
|
|
|
|
semEnterCrit();
|
|
|
|
if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
|
|
|
|
if (pbData && pcbNeeded) {
|
|
|
|
switch (dwLevel) {
|
|
|
|
case PRINT_LEVEL_2:
|
|
|
|
lpszName = (LPTSTR)(pbData + (ULONG_PTR)((LPADDJOB_INFO_2W)pbData)->pData);
|
|
|
|
|
|
// Make sure this string-address does not extend past the
|
|
// end of available buffer specified.
|
|
//
|
|
if (lpszName > (LPTSTR)(pbData + cbBuf)) {
|
|
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
|
|
goto EndAdd;
|
|
}
|
|
|
|
|
|
// Ensure NULL termination.
|
|
//
|
|
*(PTCHAR)(((ULONG_PTR)(pbData + cbBuf - sizeof(TCHAR))&~1)) = 0;
|
|
break;
|
|
|
|
case PRINT_LEVEL_1:
|
|
lpszName = NULL;
|
|
break;
|
|
|
|
default:
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
goto EndAdd;
|
|
}
|
|
|
|
|
|
// Do the add.
|
|
//
|
|
bRet = ppjob_Add(hPrinter,
|
|
pIniPort,
|
|
dwLevel,
|
|
lpszName,
|
|
pbData,
|
|
cbBuf,
|
|
pcbNeeded);
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
EndAdd:
|
|
|
|
semLeaveCrit();
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* PPScheduleJob
|
|
*
|
|
* This schedules the job. Since we don't support the PPAddJob(), this call
|
|
* must fail.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL PPScheduleJob(
|
|
HANDLE hPrinter,
|
|
DWORD idJob)
|
|
{
|
|
PCINETMONPORT pIniPort;
|
|
PJOBMAP pjm;
|
|
PJOBMAP* pjmList;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPScheduleJob: Printer(%08lX) idJob(%d)"), hPrinter, idJob));
|
|
|
|
semEnterCrit();
|
|
|
|
if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
|
|
|
|
pjmList = pIniPort->GetPJMList();
|
|
|
|
if (pjm = pjmFind(pjmList, PJM_LOCALID, idJob)) {
|
|
|
|
if (pjmChkState(pjm, PJM_SPOOLING)) {
|
|
|
|
bRet = ppjob_Schedule(hPrinter, pIniPort, pjm);
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_SPL_NO_ADDJOB);
|
|
}
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
PP_ClrStatus(hPrinter, PP_ADDJOB);
|
|
}
|
|
|
|
semLeaveCrit();
|
|
|
|
return bRet;
|
|
}
|