windows-nt/Source/XPSP1/NT/printscan/print/spooler/spllib/webipp.cxx
2020-09-26 16:20:57 +08:00

5693 lines
162 KiB
C++

/*****************************************************************************\
* MODULE: webipp.cxx
*
* This module contains routines which handle the encoding/decoding of data
* sent across the HTTP wire to represent IPP packets.
*
* Public Interfaces
* -----------------
* WebIppRcvOpen : returns a handle to an ipp-request stream
* WebIppRcvClose : closes the handle to the ipp-request stream
* WebIppRcvData : converts (Ipp -> W32)
* WebIppSndData : converts (W32 -> Ipp)
* WebIppGetError : returns ipp-error if WebIppSndData/WebIppRcvData fails
* WebIppLeToRsp : returns an ipp-error mapping for a win32 error
* WebIppGetReqId : returns the request-id for the ipp-stream
* WebIppGetUnsAttr : returns object with unsupported attribute strings
* WebIppGetReqFlag : returns a flag of requested-attributes from ipp-stream
* WebIppGetReqCp : returns codepage that ipp-stream requests
* WebIppFreeMem : used to free pointers returned from WebIpp* routines
*
* Definintions:
* ------------
* Ipp - Denotes Ipp-Formatted information according to the IPP protocol.
* W32 - Denotes win32 data that NT-Spooler understands.
*
* Copyright (C) 1996-1998 Microsoft Corporation
* Copyright (C) 1996-1998 Hewlett Packard
*
* history:
* 27-Oct-1997 <chriswil/v-chrisw> created.
*
\*****************************************************************************/
#include "spllibp.hxx"
#include <time.h>
#include <sys\timeb.h>
#include <wininet.h>
#include <winsock.h>
/*****************************************************************************\
* Static Strings
*
\*****************************************************************************/
static CONST TCHAR s_szJobLimit [] = TEXT("limit");
static CONST TCHAR s_szJobName [] = TEXT("job-name");
static CONST TCHAR s_szJobReqUser [] = TEXT("requesting-user-name");
static CONST TCHAR s_szJobOrgUser [] = TEXT("job-originating-user-name");
static CONST TCHAR s_szDocName [] = TEXT("document-name");
static CONST TCHAR s_szJobId [] = TEXT("job-id");
static CONST TCHAR s_szJobUri [] = TEXT("job-uri");
static CONST TCHAR s_szJobState [] = TEXT("job-state");
static CONST TCHAR s_szJobPri [] = TEXT("job-priority");
static CONST TCHAR s_szJobKOctets [] = TEXT("job-k-octets");
static CONST TCHAR s_szJobKOctetsProcess [] = TEXT("job-k-octets-processed");
static CONST TCHAR s_szJobSheets [] = TEXT("job-media-sheets");
static CONST TCHAR s_szJobPrtUri [] = TEXT("job-printer-uri");
static CONST TCHAR s_szTimeAtCreation [] = TEXT("time-at-creation");
static CONST TCHAR s_szJobSheetsCompleted[] = TEXT("job-media-sheets-completed");
static CONST TCHAR s_szPrtUri [] = TEXT("printer-uri");
static CONST TCHAR s_szPrtUriSupported [] = TEXT("printer-uri-supported");
static CONST TCHAR s_szPrtUriSecurity [] = TEXT("uri-security-supported");
static CONST TCHAR s_szPrtSecNone [] = TEXT("none");
static CONST TCHAR s_szPrtOpsSupported [] = TEXT("operations-supported");
static CONST TCHAR s_szPrtName [] = TEXT("printer-name");
static CONST TCHAR s_szPrtState [] = TEXT("printer-state");
static CONST TCHAR s_szPrtJobs [] = TEXT("queued-job-count");
static CONST TCHAR s_szPrtMake [] = TEXT("printer-make-and-model");
static CONST TCHAR s_szPrtAcceptingJobs [] = TEXT("printer-is-accepting-jobs");
static CONST TCHAR s_szPrtUpTime [] = TEXT("printer-up-time");
static CONST TCHAR s_szCharSetSupported [] = TEXT("charset-supported");
static CONST TCHAR s_szCharSetConfigured [] = TEXT("charset-configured");
static CONST TCHAR s_szNatLangConfigured [] = TEXT("natural-language-configured");
static CONST TCHAR s_szNatLangSupported [] = TEXT("generated-natural-language-supported");
static CONST TCHAR s_szUnknown [] = TEXT("unknown");
static CONST TCHAR s_szWhichJobs [] = TEXT("which-jobs");
static CONST TCHAR s_szCharSet [] = TEXT("attributes-charset");
static CONST TCHAR s_szNaturalLanguage [] = TEXT("attributes-natural-language");
static CONST TCHAR s_szReqAttr [] = TEXT("requested-attributes");
static CONST TCHAR s_szUtf8 [] = TEXT("utf-8");
static CONST TCHAR s_szUsAscii [] = TEXT("us-ascii");
static CONST TCHAR s_szEnUS [] = TEXT("en-us");
static CONST TCHAR s_szDocFormatDefault [] = TEXT("document-format-default");
static CONST TCHAR s_szDocFormatSupported[] = TEXT("document-format-supported");
static CONST TCHAR s_szStaMsg [] = TEXT("status-message");
static CONST TCHAR s_szPdlOverride [] = TEXT("pdl-override-supported");
static CONST TCHAR s_szNotAttempted [] = TEXT("not-attempted");
static CONST TCHAR s_szDocFormat [] = TEXT("document-format");
static CONST TCHAR s_szCompleted [] = TEXT("completed");
static CONST TCHAR s_szNotCompleted [] = TEXT("not-completed");
static CONST TCHAR s_szMimeTxtHtml [] = TEXT("text/html");
static CONST TCHAR s_szMimeTxtPlain [] = TEXT("text/plain");
static CONST TCHAR s_szMimePostScript [] = TEXT("application/postscript");
static CONST TCHAR s_szMimePCL [] = TEXT("application/vnd.hppcl");
static CONST TCHAR s_szMimeOctStream [] = TEXT("application/octet-stream");
static CONST TCHAR s_szAll [] = TEXT("all");
static CONST TCHAR s_szJobTemplate [] = TEXT("job-template");
static CONST TCHAR s_szJobDescription [] = TEXT("job-description");
static CONST TCHAR s_szPrtDescription [] = TEXT("printer-description");
static CONST TCHAR s_szUnsupported [] = TEXT("unsupported");
static CONST TCHAR s_szAtrFidelity [] = TEXT("ipp-attribute-fidelity");
static CONST TCHAR s_szTrue [] = TEXT("true");
static CONST TCHAR s_szFalse [] = TEXT("false");
/*****************************************************************************\
* Ipp Error-Mapping
*
* These tables define the mappings for Win32 LastErrors and Ipp-http errors.
*
\*****************************************************************************/
static IPPERROR s_LEIpp[] = {
IPPRSP_ERROR_400, ERROR_INVALID_DATA , TEXT("Client: (400) BadRequest") ,
IPPRSP_ERROR_401, ERROR_ACCESS_DENIED , TEXT("Client: (401) Forbidden Access") ,
IPPRSP_ERROR_402, ERROR_ACCESS_DENIED , TEXT("Client: (402) Not Authenticated") ,
IPPRSP_ERROR_403, ERROR_ACCESS_DENIED , TEXT("Client: (403) Not Authorized") ,
IPPRSP_ERROR_404, ERROR_INVALID_DATA , TEXT("Client: (404) Not Possible") ,
IPPRSP_ERROR_405, ERROR_TIMEOUT , TEXT("Client: (405) Time Out") ,
IPPRSP_ERROR_406, ERROR_INVALID_DATA , TEXT("Client: (406) Not Found") ,
IPPRSP_ERROR_407, ERROR_INVALID_DATA , TEXT("Client: (407) Gone") ,
IPPRSP_ERROR_408, ERROR_INVALID_DATA , TEXT("Client: (408) Entity Too Large") ,
IPPRSP_ERROR_409, ERROR_INVALID_DATA , TEXT("Client: (409) Uri Too Long") ,
IPPRSP_ERROR_40A, ERROR_INVALID_DATA , TEXT("Client: (40A) Document Format Not Supported"),
IPPRSP_ERROR_40B, ERROR_INVALID_DATA , TEXT("Client: (40B) Attributes Not Supported") ,
IPPRSP_ERROR_40C, ERROR_INVALID_DATA , TEXT("Client: (40C) Uri Scheme Not Supported") ,
IPPRSP_ERROR_40D, ERROR_INVALID_DATA , TEXT("Client: (40D) Charset Not Supported") ,
IPPRSP_ERROR_40E, ERROR_INVALID_DATA , TEXT("Client: (40E) Conflicting Attributes") ,
IPPRSP_ERROR_500, ERROR_INVALID_DATA , TEXT("Server: (500) Internal Error") ,
IPPRSP_ERROR_501, ERROR_INVALID_DATA , TEXT("Server: (501) Operation Not Supported") ,
IPPRSP_ERROR_502, ERROR_NOT_READY , TEXT("Server: (502) Service Unavailable") ,
IPPRSP_ERROR_503, ERROR_INVALID_DATA , TEXT("Server: (503) Version Not Supported") ,
IPPRSP_ERROR_504, ERROR_NOT_READY , TEXT("Server: (504) Device Error") ,
IPPRSP_ERROR_505, ERROR_OUTOFMEMORY , TEXT("Server: (505) Temporary Error") ,
IPPRSP_ERROR_506, ERROR_INVALID_DATA , TEXT("Server: (506) Not Accepting Jobs") ,
IPPRSP_ERROR_540, ERROR_LICENSE_QUOTA_EXCEEDED, TEXT("Server: (540) Too Many Users")
};
static IPPDEFERROR s_LEDef[] = {
ERROR_INVALID_DATA , IPPRSP_ERROR_400,
ERROR_ACCESS_DENIED , IPPRSP_ERROR_401,
ERROR_INVALID_PARAMETER , IPPRSP_ERROR_404,
ERROR_TIMEOUT , IPPRSP_ERROR_405,
ERROR_NOT_READY , IPPRSP_ERROR_504,
ERROR_OUTOFMEMORY , IPPRSP_ERROR_505,
ERROR_LICENSE_QUOTA_EXCEEDED, IPPRSP_ERROR_540
};
/*****************************************************************************\
* Request/Response attributes that are written to the ipp-stream.
*
*
\*****************************************************************************/
static IPPATTRX s_PJQ[] = { // PrtJob, ValJob Request
IPP_TAG_CHR_URI , RA_PRNURI , IPP_ATR_OFFSET , s_szPrtUri , (LPVOID)offs(PIPPREQ_PRTJOB, pPrnUri) ,
IPP_TAG_CHR_NAME, RA_JOBNAME, IPP_ATR_OFFSET , s_szJobName , (LPVOID)offs(PIPPREQ_PRTJOB, pDocument),
IPP_TAG_CHR_NAME, RA_JOBUSER, IPP_ATR_OFFSET , s_szJobReqUser, (LPVOID)offs(PIPPREQ_PRTJOB, pUserName),
IPP_TAG_DEL_JOB , 0 , IPP_ATR_TAG , NULL , (LPVOID)NULL
};
static IPPATTRX s_EJQ[] = { // GetJobs Request
IPP_TAG_CHR_URI , RA_PRNURI , IPP_ATR_OFFSET , s_szPrtUri , (LPVOID)offs(PIPPREQ_ENUJOB, pPrnUri),
IPP_TAG_INT_INTEGER, RA_JOBCOUNT , IPP_ATR_OFFSET , s_szJobLimit, (LPVOID)offs(PIPPREQ_ENUJOB, cJobs) ,
IPP_TAG_CHR_KEYWORD, 0 , IPP_ATR_ABSOLUTE, s_szReqAttr , (LPVOID)s_szAll
};
static IPPATTRX s_SJQ[] = { // PauJob, CanJob, RsmJob, RstJob Request
IPP_TAG_CHR_URI , 0, IPP_ATR_OFFSET, s_szPrtUri, (LPVOID)offs(PIPPREQ_SETJOB, pPrnUri),
IPP_TAG_INT_INTEGER, 0, IPP_ATR_OFFSET, s_szJobId , (LPVOID)offs(PIPPREQ_SETJOB, idJob)
};
static IPPATTRX s_GJQ[] = { // GetJobAtr Request
IPP_TAG_CHR_URI , 0, IPP_ATR_OFFSET, s_szPrtUri, (LPVOID)offs(PIPPREQ_GETJOB, pPrnUri),
IPP_TAG_INT_INTEGER, 0, IPP_ATR_OFFSET, s_szJobId , (LPVOID)offs(PIPPREQ_GETJOB, idJob)
};
static IPPATTRX s_SPQ[] = { // PauPrn, CanPrn, RsmPrn, RstPrn Request
IPP_TAG_CHR_URI , 0, IPP_ATR_OFFSET, s_szPrtUri , (LPVOID)offs(PIPPREQ_SETPRN, pPrnUri) ,
IPP_TAG_CHR_NAME, 0, IPP_ATR_OFFSET, s_szJobReqUser, (LPVOID)offs(PIPPREQ_SETPRN, pUserName)
};
static IPPATTRX s_GPQ[] = { // GetPrnAtr Request
IPP_TAG_CHR_URI, 0, IPP_ATR_OFFSET, s_szPrtUri, (LPVOID)offs(PIPPREQ_GETPRN, pPrnUri)
};
static IPPATTRX s_PJR[] = { // PrintJob Response
IPP_TAG_DEL_JOB , 0 , IPP_ATR_TAG , NULL , (LPVOID)NULL ,
IPP_TAG_INT_INTEGER, RA_JOBID , IPP_ATR_OFFSET , s_szJobId , (LPVOID)offs(PIPPRET_JOB, ji.ji2.JobId) ,
IPP_TAG_INT_ENUM , RA_JOBSTATE , IPP_ATR_OFFSETCONV, s_szJobState , (LPVOID)offs(PIPPRET_JOB, ji.ji2.Status) ,
IPP_TAG_INT_INTEGER, RA_JOBPRIORITY , IPP_ATR_OFFSET , s_szJobPri , (LPVOID)offs(PIPPRET_JOB, ji.ji2.Priority) ,
IPP_TAG_INT_INTEGER, RA_JOBSIZE , IPP_ATR_OFFSETCONV, s_szJobKOctetsProcess , (LPVOID)offs(PIPPRET_JOB, ji.ji2.Size) ,
IPP_TAG_INT_INTEGER, RA_SHEETSTOTAL , IPP_ATR_OFFSET , s_szJobSheets , (LPVOID)offs(PIPPRET_JOB, ji.ji2.TotalPages) ,
IPP_TAG_INT_INTEGER, RA_SHEETSCOMPLETED, IPP_ATR_OFFSET , s_szJobSheetsCompleted, (LPVOID)offs(PIPPRET_JOB, ji.ji2.PagesPrinted),
IPP_TAG_CHR_NAME , RA_JOBNAME , IPP_ATR_OFFSET , s_szJobName , (LPVOID)offs(PIPPRET_JOB, ji.ji2.pDocument) ,
IPP_TAG_CHR_NAME , RA_JOBUSER , IPP_ATR_OFFSET , s_szJobOrgUser , (LPVOID)offs(PIPPRET_JOB, ji.ji2.pUserName) ,
IPP_TAG_CHR_URI , RA_JOBURI , IPP_ATR_OFFSET , s_szJobUri , (LPVOID)offs(PIPPRET_JOB, ji.ipp.pJobUri) ,
IPP_TAG_CHR_URI , RA_PRNURI , IPP_ATR_OFFSET , s_szJobPrtUri , (LPVOID)offs(PIPPRET_JOB, ji.ipp.pPrnUri)
};
static IPPATTRX s_EJR[] = { // GetJobs Response
IPP_TAG_DEL_JOB , 0 , IPP_ATR_TAG , NULL , (LPVOID)NULL ,
IPP_TAG_INT_INTEGER, RA_JOBID , IPP_ATR_OFFSET, s_szJobId , (LPVOID)offs(PIPPJI2, ji2.JobId) ,
IPP_TAG_INT_ENUM , RA_JOBSTATE , IPP_ATR_OFFSET, s_szJobState , (LPVOID)offs(PIPPJI2, ji2.Status) ,
IPP_TAG_INT_INTEGER, RA_JOBPRIORITY , IPP_ATR_OFFSET, s_szJobPri , (LPVOID)offs(PIPPJI2, ji2.Priority) ,
IPP_TAG_INT_INTEGER, RA_JOBSIZE , IPP_ATR_OFFSET, s_szJobKOctetsProcess , (LPVOID)offs(PIPPJI2, ji2.Size) ,
IPP_TAG_INT_INTEGER, RA_SHEETSTOTAL , IPP_ATR_OFFSET, s_szJobSheets , (LPVOID)offs(PIPPJI2, ji2.TotalPages) ,
IPP_TAG_INT_INTEGER, RA_SHEETSCOMPLETED, IPP_ATR_OFFSET, s_szJobSheetsCompleted, (LPVOID)offs(PIPPJI2, ji2.PagesPrinted),
IPP_TAG_INT_INTEGER, RA_TIMEATCREATION , IPP_ATR_OFFSET, s_szTimeAtCreation , (LPVOID)offs(PIPPJI2, ji2.Submitted) ,
IPP_TAG_CHR_NAME , RA_JOBNAME , IPP_ATR_OFFSET, s_szJobName , (LPVOID)offs(PIPPJI2, ji2.pDocument) ,
IPP_TAG_CHR_NAME , RA_JOBUSER , IPP_ATR_OFFSET, s_szJobOrgUser , (LPVOID)offs(PIPPJI2, ji2.pUserName) ,
IPP_TAG_CHR_URI , RA_JOBURI , IPP_ATR_OFFSET, s_szJobUri , (LPVOID)offs(PIPPJI2, ipp.pJobUri) ,
IPP_TAG_CHR_URI , RA_PRNURI , IPP_ATR_OFFSET, s_szJobPrtUri , (LPVOID)offs(PIPPJI2, ipp.pPrnUri)
};
static IPPATTRX s_GPR[] = { // GetPrnAtr Response
IPP_TAG_DEL_PRINTER, 0 , IPP_ATR_TAG , NULL , (LPVOID)NULL ,
IPP_TAG_INT_ENUM , RA_PRNSTATE , IPP_ATR_OFFSETCONV, s_szPrtState , (LPVOID)offs(PIPPRET_PRN, pi.pi2.Status) ,
IPP_TAG_INT_INTEGER, RA_JOBCOUNT , IPP_ATR_OFFSET , s_szPrtJobs , (LPVOID)offs(PIPPRET_PRN, pi.pi2.cJobs) ,
IPP_TAG_CHR_URI , RA_URISUPPORTED , IPP_ATR_OFFSET , s_szPrtUriSupported , (LPVOID)offs(PIPPRET_PRN, pi.ipp.pPrnUri) ,
IPP_TAG_CHR_KEYWORD, RA_URISECURITY , IPP_ATR_ABSOLUTE , s_szPrtUriSecurity , (LPVOID)s_szPrtSecNone ,
IPP_TAG_CHR_NAME , RA_PRNNAME , IPP_ATR_OFFSET , s_szPrtName , (LPVOID)offs(PIPPRET_PRN, pi.pi2.pPrinterName),
IPP_TAG_CHR_TEXT , RA_PRNMAKE , IPP_ATR_OFFSET , s_szPrtMake , (LPVOID)offs(PIPPRET_PRN, pi.pi2.pDriverName) ,
IPP_TAG_INT_BOOLEAN, RA_ACCEPTINGJOBS , IPP_ATR_ABSOLUTE , s_szPrtAcceptingJobs , (LPVOID)TRUE ,
IPP_TAG_CHR_CHARSET, RA_CHRSETCONFIGURED, IPP_ATR_ABSOLUTE , s_szCharSetConfigured , (LPVOID)s_szUtf8 ,
IPP_TAG_CHR_CHARSET, RA_CHRSETSUPPORTED , IPP_ATR_ABSOLUTE , s_szCharSetSupported , (LPVOID)s_szUtf8 ,
IPP_TAG_CHR_CHARSET, 0 , IPP_ATR_ABSOLUTE , NULL , (LPVOID)s_szUsAscii ,
IPP_TAG_CHR_NATURAL, RA_NATLNGCONFIGURED, IPP_ATR_ABSOLUTE , s_szNatLangConfigured , (LPVOID)s_szEnUS ,
IPP_TAG_CHR_NATURAL, RA_NATLNGSUPPORTED , IPP_ATR_ABSOLUTE , s_szNatLangSupported , (LPVOID)s_szEnUS ,
IPP_TAG_CHR_MEDIA , RA_DOCDEFAULT , IPP_ATR_ABSOLUTE , s_szDocFormatDefault , (LPVOID)s_szMimeOctStream ,
IPP_TAG_CHR_MEDIA , RA_DOCSUPPORTED , IPP_ATR_ABSOLUTE , s_szDocFormatSupported, (LPVOID)s_szMimeOctStream ,
IPP_TAG_CHR_KEYWORD, RA_PDLOVERRIDE , IPP_ATR_ABSOLUTE , s_szPdlOverride , (LPVOID)s_szNotAttempted ,
IPP_TAG_INT_INTEGER, RA_UPTIME , IPP_ATR_ABSOLUTE , s_szPrtUpTime , (LPVOID)1 ,
IPP_TAG_INT_ENUM , RA_OPSSUPPORTED , IPP_ATR_ABSOLUTE , s_szPrtOpsSupported , (LPVOID)IPP_REQ_PRINTJOB ,
IPP_TAG_INT_ENUM , 0 , IPP_ATR_ABSOLUTE , NULL , (LPVOID)IPP_REQ_VALIDATEJOB ,
IPP_TAG_INT_ENUM , 0 , IPP_ATR_ABSOLUTE , NULL , (LPVOID)IPP_REQ_CANCELJOB ,
IPP_TAG_INT_ENUM , 0 , IPP_ATR_ABSOLUTE , NULL , (LPVOID)IPP_REQ_GETJOB ,
IPP_TAG_INT_ENUM , 0 , IPP_ATR_ABSOLUTE , NULL , (LPVOID)IPP_REQ_ENUJOB ,
IPP_TAG_INT_ENUM , 0 , IPP_ATR_ABSOLUTE , NULL , (LPVOID)IPP_REQ_GETPRN ,
IPP_TAG_INT_ENUM , 0 , IPP_ATR_ABSOLUTE , NULL , (LPVOID)IPP_REQ_PAUSEJOB ,
IPP_TAG_INT_ENUM , 0 , IPP_ATR_ABSOLUTE , NULL , (LPVOID)IPP_REQ_RESUMEJOB ,
IPP_TAG_INT_ENUM , 0 , IPP_ATR_ABSOLUTE , NULL , (LPVOID)IPP_REQ_RESTARTJOB ,
IPP_TAG_INT_ENUM , 0 , IPP_ATR_ABSOLUTE , NULL , (LPVOID)IPP_REQ_PAUSEPRN ,
IPP_TAG_INT_ENUM , 0 , IPP_ATR_ABSOLUTE , NULL , (LPVOID)IPP_REQ_RESUMEPRN ,
IPP_TAG_INT_ENUM , 0 , IPP_ATR_ABSOLUTE , NULL , (LPVOID)IPP_REQ_CANCELPRN
};
/*****************************************************************************\
* Request/Response string-mappings.
*
*
\*****************************************************************************/
static FLGSTR s_ReqRspStr[] = {
RA_JOBUSER, s_szJobReqUser,
RA_JOBSIZE, s_szJobKOctets
};
/*****************************************************************************\
* Receive/Response group forms.
*
* These tables defines the order and layout of ipp group tags.
*
\*****************************************************************************/
static BYTE s_FormA[] = {
IPP_TAG_DEL_OPERATION | IPP_MANDITORY,
IPP_TAG_DEL_JOB | IPP_OPTIONAL,
IPP_TAG_DEL_DATA | IPP_MANDITORY,
0
};
static BYTE s_FormB[] = {
IPP_TAG_DEL_OPERATION | IPP_MANDITORY,
IPP_TAG_DEL_DATA | IPP_MANDITORY,
0
};
static BYTE s_FormC[] = {
IPP_TAG_DEL_OPERATION | IPP_MANDITORY,
IPP_TAG_DEL_UNSUPPORTED | IPP_OPTIONAL ,
IPP_TAG_DEL_JOB | IPP_OPTIONAL ,
IPP_TAG_DEL_DATA | IPP_MANDITORY,
0
};
static BYTE s_FormD[] = {
IPP_TAG_DEL_OPERATION | IPP_MANDITORY,
IPP_TAG_DEL_UNSUPPORTED | IPP_OPTIONAL ,
IPP_TAG_DEL_PRINTER | IPP_OPTIONAL ,
IPP_TAG_DEL_DATA | IPP_MANDITORY,
0
};
static BYTE s_FormE[] = {
IPP_TAG_DEL_OPERATION | IPP_MANDITORY,
IPP_TAG_DEL_UNSUPPORTED | IPP_OPTIONAL ,
IPP_TAG_DEL_DATA | IPP_MANDITORY,
0
};
static BYTE s_FormF[] = {
IPP_TAG_DEL_OPERATION | IPP_MANDITORY ,
IPP_TAG_DEL_UNSUPPORTED | IPP_OPTIONAL ,
IPP_TAG_DEL_JOB | IPP_OPTIONAL | IPP_MULTIPLE,
IPP_TAG_DEL_DATA | IPP_MANDITORY ,
0
};
/*****************************************************************************\
* Structure Offsets
*
*
\*****************************************************************************/
static DWORD s_IPPJI2Offs[] = {
offs(LPIPPJI2, ji2.pPrinterName),
offs(LPIPPJI2, ji2.pMachineName),
offs(LPIPPJI2, ji2.pUserName),
offs(LPIPPJI2, ji2.pDocument),
offs(LPIPPJI2, ji2.pNotifyName),
offs(LPIPPJI2, ji2.pDatatype),
offs(LPIPPJI2, ji2.pPrintProcessor),
offs(LPIPPJI2, ji2.pParameters),
offs(LPIPPJI2, ji2.pDriverName),
offs(LPIPPJI2, ji2.pDevMode),
offs(LPIPPJI2, ji2.pStatus),
offs(LPIPPJI2, ji2.pSecurityDescriptor),
offs(LPIPPJI2, ipp.pPrnUri),
offs(LPIPPJI2, ipp.pJobUri),
0xFFFFFFFF
};
static DWORD s_IPPPI2Offs[] = {
offs(LPIPPPI2, pi2.pServerName),
offs(LPIPPPI2, pi2.pPrinterName),
offs(LPIPPPI2, pi2.pShareName),
offs(LPIPPPI2, pi2.pPortName),
offs(LPIPPPI2, pi2.pDriverName),
offs(LPIPPPI2, pi2.pComment),
offs(LPIPPPI2, pi2.pLocation),
offs(LPIPPPI2, pi2.pDevMode),
offs(LPIPPPI2, pi2.pSepFile),
offs(LPIPPPI2, pi2.pPrintProcessor),
offs(LPIPPPI2, pi2.pDatatype),
offs(LPIPPPI2, pi2.pParameters),
offs(LPIPPPI2, pi2.pSecurityDescriptor),
offs(LPIPPPI2, ipp.pPrnUri),
offs(LPIPPPI2, ipp.pUsrName),
0xFFFFFFFF
};
static DWORD s_JI2Off[] = {
offs(LPJOB_INFO_2, pPrinterName),
offs(LPJOB_INFO_2, pMachineName),
offs(LPJOB_INFO_2, pUserName),
offs(LPJOB_INFO_2, pDocument),
offs(LPJOB_INFO_2, pNotifyName),
offs(LPJOB_INFO_2, pDatatype),
offs(LPJOB_INFO_2, pPrintProcessor),
offs(LPJOB_INFO_2, pParameters),
offs(LPJOB_INFO_2, pDriverName),
// Do not include DEVMODE
offs(LPJOB_INFO_2, pStatus),
// Do not include SECURITY-DESCRIPTOR
0xFFFFFFFF
};
static DWORD s_PI2Off[] = {
offs(LPPRINTER_INFO_2, pServerName),
offs(LPPRINTER_INFO_2, pPrinterName),
offs(LPPRINTER_INFO_2, pShareName),
offs(LPPRINTER_INFO_2, pPortName),
offs(LPPRINTER_INFO_2, pDriverName),
offs(LPPRINTER_INFO_2, pComment),
offs(LPPRINTER_INFO_2, pLocation),
// Do not include DEVMODE
offs(LPPRINTER_INFO_2, pSepFile),
offs(LPPRINTER_INFO_2, pPrintProcessor),
offs(LPPRINTER_INFO_2, pDatatype),
offs(LPPRINTER_INFO_2, pParameters),
// Do not include SECURITY-DESCRIPTOR
0xFFFFFFFF
};
static DWORD s_IPJOff[] = {
offs(LPJOB_INFO_IPP, pPrnUri),
offs(LPJOB_INFO_IPP, pJobUri),
0xFFFFFFFF
};
static DWORD s_IPPOff[] = {
offs(LPPRINTER_INFO_IPP, pPrnUri) ,
offs(LPPRINTER_INFO_IPP, pUsrName),
0xFFFFFFFF
};
/*****************************************************************************\
* ipp_SetReq (Local Routine)
*
* Sets a bit in the request flag. If the index (upper 4 bits) is greater
* than 7, then we use this as a special enum flag.
*
\*****************************************************************************/
VOID x_SetReq(
PDWORD pfReq,
DWORD fSet)
{
DWORD idz;
PDWORD pFlg;
DWORD cFlg = 0;
DWORD idx = ((fSet >> 28) & 0x0000000F);
static DWORD s_fReqEnu[] = {
RA_JOBID,
RA_JOBURI
};
static DWORD s_fJobTmp[] = {
RA_JOBPRIORITY ,
RA_SHEETSTOTAL ,
RA_SHEETSCOMPLETED
};
static DWORD s_fJobDsc[] = {
RA_JOBURI ,
RA_JOBID ,
RA_JOBNAME ,
RA_JOBUSER ,
RA_JOBSTATE ,
RA_JOBSTATE_REASONS,
RA_JOBSTATE_MESSAGE,
RA_JOBSIZE
};
static DWORD s_fPrtDsc[] = {
RA_URISUPPORTED ,
RA_URISECURITY ,
RA_PRNNAME ,
RA_PRNMAKE ,
RA_PRNSTATE ,
RA_OPSSUPPORTED ,
RA_CHRSETCONFIGURED,
RA_CHRSETSUPPORTED ,
RA_NATLNGCONFIGURED,
RA_NATLNGSUPPORTED ,
RA_DOCDEFAULT ,
RA_DOCSUPPORTED ,
RA_ACCEPTINGJOBS ,
RA_JOBCOUNT ,
RA_PDLOVERRIDE ,
RA_UPTIME
};
switch (idx) {
case IPP_REQALL_IDX:
pfReq[0] = 0x0FFFFFFF;
pfReq[1] = 0x0FFFFFFF;
break;
case IPP_REQCLEAR_IDX:
pfReq[0] = 0x00000000;
pfReq[1] = 0x00000000;
break;
case IPP_REQENU_IDX:
pFlg = s_fReqEnu;
cFlg = sizeof(s_fReqEnu) / sizeof(s_fReqEnu[0]);
break;
case IPP_REQJDSC_IDX:
pFlg = s_fJobDsc;
cFlg = sizeof(s_fJobDsc) / sizeof(s_fJobDsc[0]);
break;
case IPP_REQJTMP_IDX:
pFlg = s_fJobTmp;
cFlg = sizeof(s_fJobTmp) / sizeof(s_fJobTmp[0]);
break;
case IPP_REQPDSC_IDX:
pFlg = s_fPrtDsc;
cFlg = sizeof(s_fPrtDsc) / sizeof(s_fPrtDsc[0]);
break;
}
if (idx >= IPP_REQALL_IDX) {
for (idz = 0; idz < cFlg; idz++) {
idx = ((pFlg[idz] >> 28) & 0x0000000F);
pfReq[idx] |= (pFlg[idz] & 0x0FFFFFFF);
}
} else {
pfReq[idx] |= (fSet & 0x0FFFFFFF);
}
}
/*****************************************************************************\
* ipp_ChkReq (Local Routine)
*
* Checks to se if bit-flag is set in the request flag.
*
\*****************************************************************************/
BOOL x_ChkReq(
PDWORD pfReq,
DWORD fChk)
{
DWORD idx = ((fChk >> 28) & 0x0000000F);
return pfReq[idx] & (fChk & 0x0FFFFFFF);
}
/*****************************************************************************\
* ipp_CopyAligned (Local Routine)
*
* Copies memory to an aligned-buffer.
*
\*****************************************************************************/
inline LPBYTE ipp_CopyAligned(
LPBYTE lpDta,
DWORD cbDta)
{
LPBYTE lpAln;
if (lpAln = (LPBYTE)webAlloc(cbDta))
CopyMemory((LPVOID)lpAln, lpDta, cbDta);
return lpAln;
}
/*****************************************************************************\
* ipp_WriteData (Local Routine)
*
* Sets the data in an IPP-Data-Stream. This adjusts the pointer to the
* next byte-location in the stream.
*
\*****************************************************************************/
inline VOID ipp_WriteData(
LPBYTE* lplpPtr,
LPVOID lpData,
DWORD cbData)
{
CopyMemory(*lplpPtr, lpData, cbData);
*lplpPtr += cbData;
}
/*****************************************************************************\
* ipp_WriteByte (Local Routine)
*
* Write out a byte to the stream.
*
\*****************************************************************************/
inline VOID ipp_WriteByte(
LPBYTE* lplpIppPtr,
BYTE bVal)
{
ipp_WriteData(lplpIppPtr, (LPVOID)&bVal, IPP_SIZEOFTAG);
}
/*****************************************************************************\
* ipp_ReadByte (Local Routine)
*
* Read a byte from the stream.
*
\*****************************************************************************/
inline BYTE ipp_ReadByte(
LPBYTE lpbPtr,
DWORD cbIdx)
{
return (*(BYTE *)((LPBYTE)(lpbPtr) + cbIdx));
}
/*****************************************************************************\
* ipp_WriteWord (Local Routine)
*
* Write out a word to the stream.
*
\*****************************************************************************/
inline VOID ipp_WriteWord(
LPBYTE* lplpIppPtr,
WORD wVal)
{
WORD wNBW = htons (wVal);
ipp_WriteData(lplpIppPtr, (LPVOID)&wNBW, IPP_SIZEOFLEN);
}
/*****************************************************************************\
* ipp_ReadWord (Local Routine)
*
* Read a word from the stream.
*
\*****************************************************************************/
inline WORD ipp_ReadWord(
LPBYTE lpbPtr,
DWORD cbIdx)
{
WORD wVal = (*(WORD UNALIGNED *)((LPBYTE)(lpbPtr) + cbIdx));
return ntohs (wVal);
}
/*****************************************************************************\
* ipp_WriteDWord (Local Routine)
*
* Write out a dword to the stream.
*
\*****************************************************************************/
inline VOID ipp_WriteDWord(
LPBYTE* lplpIppPtr,
DWORD dwVal)
{
DWORD dwNBDW = htonl(dwVal);
ipp_WriteData(lplpIppPtr, (LPVOID)&dwNBDW, IPP_SIZEOFINT);
}
/*****************************************************************************\
* ipp_ReadDWord (Local Routine)
*
* Read a dword from the stream.
*
\*****************************************************************************/
inline DWORD ipp_ReadDWord(
LPBYTE lpbPtr,
DWORD cbIdx)
{
DWORD dwVal = (*(DWORD UNALIGNED *)((LPBYTE)(lpbPtr) + cbIdx));
return ntohl(dwVal);
}
/*****************************************************************************\
* ipp_MapReqToJobCmd (Local Routine)
*
* Returns a job-command from a request.
*
\*****************************************************************************/
inline DWORD ipp_MapReqToJobCmd(
WORD wReq)
{
if (wReq == IPP_REQ_CANCELJOB)
return JOB_CONTROL_DELETE;
if (wReq == IPP_REQ_PAUSEJOB)
return JOB_CONTROL_PAUSE;
if (wReq == IPP_REQ_RESUMEJOB)
return JOB_CONTROL_RESUME;
if (wReq == IPP_REQ_RESTARTJOB)
return JOB_CONTROL_RESTART;
return 0;
}
/*****************************************************************************\
* ipp_MapReqToPrnCmd (Local Routine)
*
* Returns a printer-command from a request.
*
\*****************************************************************************/
inline DWORD ipp_MapReqToPrnCmd(
WORD wReq)
{
if (wReq == IPP_REQ_RESUMEPRN)
return PRINTER_CONTROL_RESUME;
if (wReq == IPP_REQ_PAUSEPRN)
return PRINTER_CONTROL_PAUSE;
if (wReq == IPP_REQ_CANCELPRN)
return PRINTER_CONTROL_PURGE;
return 0;
}
/*****************************************************************************\
* ipp_W32ToIppJobPriority (Local Routine)
*
* Maps a JOB_INFO_2 priority to an IPP priority.
*
\*****************************************************************************/
inline DWORD ipp_W32ToIppJobPriority(
DWORD dwPriority)
{
return dwPriority;
}
/*****************************************************************************\
* ipp_IppToW32JobPriority (Local Routine)
*
* Maps an IPP job priority to a JOB_INFO_2 priority.
*
\*****************************************************************************/
inline DWORD ipp_IppToW32JobPriority(
DWORD dwPriority)
{
return dwPriority;
}
/*****************************************************************************\
* ipp_W32ToIppJobSize (Local Routine)
*
* Maps a JOB_INFO_2 size to an IPP size.
*
\*****************************************************************************/
inline DWORD ipp_W32ToIppJobSize(
DWORD dwSize)
{
return (1023 + dwSize) / 1024;
}
/*****************************************************************************\
* ipp_IppToW32JobSize (Local Routine)
*
* Maps an IPP job size to a JOB_INFO_2 size.
*
\*****************************************************************************/
inline DWORD ipp_IppToW32JobSize(
DWORD dwSize)
{
return dwSize * 1024;
}
/*****************************************************************************\
* ipp_W32ToIppJobTotalPages (Local Routine)
*
* Maps a JOB_INFO_2 TotalPages to an IPP priority.
*
\*****************************************************************************/
inline DWORD ipp_W32ToIppJobTotalPages(
DWORD dwTotalPages)
{
return dwTotalPages;
}
/*****************************************************************************\
* ipp_IppToW32JobTotalPages (Local Routine)
*
* Maps an IPP TotalPages to a JOB_INFO_2 priority.
*
\*****************************************************************************/
inline DWORD ipp_IppToW32JobTotalPages(
DWORD dwTotalPages)
{
return dwTotalPages;
}
/*****************************************************************************\
* ipp_W32ToIppJobPagesPrinted (Local Routine)
*
* Maps a JOB_INFO_2 PagesPrinted to an IPP priority.
*
\*****************************************************************************/
inline DWORD ipp_W32ToIppJobPagesPrinted(
DWORD dwPagesPrinted)
{
return dwPagesPrinted;
}
/*****************************************************************************\
* ipp_IppToW32JobPagesPrinted (Local Routine)
*
* Maps an IPP PagesPrinted to a JOB_INFO_2 priority.
*
\*****************************************************************************/
inline DWORD ipp_IppToW32JobPagesPrinted(
DWORD dwPagesPrinted)
{
return dwPagesPrinted;
}
/*****************************************************************************\
* ipp_W32ToIppJobState (Local Routine)
*
* Maps a Job-Status flag to that of an IPP State flag.
*
\*****************************************************************************/
DWORD ipp_W32ToIppJobState(
DWORD dwState)
{
if (dwState & (JOB_STATUS_OFFLINE | JOB_STATUS_PAPEROUT | JOB_STATUS_ERROR | JOB_STATUS_USER_INTERVENTION | JOB_STATUS_BLOCKED_DEVQ))
return IPP_JOBSTATE_PROCESSEDSTOPPED;
if (dwState & JOB_STATUS_DELETED)
return IPP_JOBSTATE_CANCELLED;
if (dwState & JOB_STATUS_PAUSED)
return IPP_JOBSTATE_PENDINGHELD;
if (dwState & JOB_STATUS_PRINTED)
return IPP_JOBSTATE_COMPLETED;
if (dwState & (JOB_STATUS_PRINTING | JOB_STATUS_SPOOLING | JOB_STATUS_DELETING))
return IPP_JOBSTATE_PROCESSING;
if ((dwState == 0) || (dwState & JOB_STATUS_RESTART))
return IPP_JOBSTATE_PENDING;
return IPP_JOBSTATE_UNKNOWN;
}
/*****************************************************************************\
* ipp_IppToW32JobState (Local Routine)
*
* Maps a IPP State flag to that of a W32 Status flag.
*
\*****************************************************************************/
DWORD ipp_IppToW32JobState(
DWORD dwState)
{
switch (dwState) {
case IPP_JOBSTATE_PENDINGHELD:
return JOB_STATUS_PAUSED;
case IPP_JOBSTATE_PROCESSEDSTOPPED:
return JOB_STATUS_ERROR;
case IPP_JOBSTATE_PROCESSING:
return JOB_STATUS_PRINTING;
case IPP_JOBSTATE_CANCELLED:
case IPP_JOBSTATE_ABORTED:
return JOB_STATUS_DELETING;
case IPP_JOBSTATE_COMPLETED:
return JOB_STATUS_PRINTED;
default:
case IPP_JOBSTATE_PENDING:
return 0;
}
}
/*****************************************************************************\
* ipp_W32ToIppPrnState (Local Routine)
*
* Maps a W32-Prn-State to Ipp-Prn-State.
*
\*****************************************************************************/
DWORD ipp_W32ToIppPrnState(
DWORD dwState)
{
if (dwState == 0)
return IPP_PRNSTATE_IDLE;
if (dwState & PRINTER_STATUS_PAUSED)
return IPP_PRNSTATE_STOPPED;
if (dwState & (PRINTER_STATUS_PROCESSING | PRINTER_STATUS_PRINTING))
return IPP_PRNSTATE_PROCESSING;
return IPP_PRNSTATE_UNKNOWN;
}
/*****************************************************************************\
* ipp_IppToW32PrnState (Local Routine)
*
* Maps a Ipp-Prn-State to W32-Prn-State.
*
\*****************************************************************************/
DWORD ipp_IppToW32PrnState(
DWORD dwState)
{
switch (dwState) {
case IPP_PRNSTATE_STOPPED:
return PRINTER_STATUS_PAUSED;
case IPP_PRNSTATE_PROCESSING:
return PRINTER_STATUS_PROCESSING;
default:
case IPP_PRNSTATE_IDLE:
return 0;
}
}
/*****************************************************************************\
* ipp_IppCurTime (Local Routine)
*
* Returns the base seconds printer has been alive. This is used for the
* printer-up-time attribute. Since our implementation can't determine the
* true printer up-time, we're going to use the relative seconds returned
* from the time() function.
*
\*****************************************************************************/
DWORD ipp_IppCurTime(VOID)
{
time_t tTime;
ZeroMemory(&tTime, sizeof(time_t));
time(&tTime);
return (DWORD) tTime;
}
/*****************************************************************************\
* ipp_IppToW32Time (Local Routine)
*
* Converts an IPP (DWORD) time to a win32 SYSTEMTIME. Note that we pass in the
* printers' normalised start time as a straight overwrite of the first fields
* of the LPSYSTEMTIME structure. This is nasty but since the code has no concept
* of session, we have to pass it back to code that does.
*
\*****************************************************************************/
BOOL ipp_IppToW32Time(
time_t dwTime,
LPSYSTEMTIME pst)
{
#if 1
// All we do is brutally overwrite the structure with the time and send it back
//
// *(time_t *)pst = dwTime;
// Change to use CopyMemory to avoid 64bit alignment error
//
CopyMemory (pst, &dwTime, sizeof (time_t));
return TRUE;
#else
FILETIME ft;
DosDateTimeToFileTime(HIWORD(dwTime), LOWORD(dwTime), &ft);
return FileTimeToSystemTime(&ft, pst);
#endif
}
/*******************************************************************************
** ippConvertSystemTime
**
** This receives the system time (which has actually been packed with the time
** retrieved from the printers) and converts it to the Real System time based
** on the original T0 of the printer
**
******************************************************************************/
BOOL WebIppConvertSystemTime(
IN OUT LPSYSTEMTIME pST,
IN time_t dwPrinterT0) {
// First we need to get the time stored in the LPSYSTEMTIME structure
// time_t dwSubmitTime = *(time_t *)pST;
// Use CopyMemory to avoid alignment error in 64bit machine.
time_t dwSubmitTime;
CopyMemory (&dwSubmitTime, pST, sizeof (time_t));
SYSTEMTIME TmpST;
// If the submitted time is zero, it means that either the job was submitted before
// the printer was rebooted, or, the printer does not support the submitted time of the
// job
if (!dwSubmitTime) {
ZeroMemory( &pST, sizeof(LPSYSTEMTIME));
} else {
// Next we have to normalise the time to that of the PrinterT0
dwSubmitTime += dwPrinterT0;
tm *ptm;
// Convert the time into a struct and return the SYSTEMTIME
// structure.
//
ptm = gmtime(&dwSubmitTime);
if (ptm) {
TmpST.wYear = (WORD)(1900 + ptm->tm_year);
TmpST.wMonth = (WORD)(ptm->tm_mon + 1);
TmpST.wDayOfWeek = (WORD)ptm->tm_wday;
TmpST.wDay = (WORD)ptm->tm_mday;
TmpST.wHour = (WORD)ptm->tm_hour;
TmpST.wMinute = (WORD)ptm->tm_min;
TmpST.wSecond = (WORD)ptm->tm_sec;
TmpST.wMilliseconds = 0;
CopyMemory (pST, &TmpST, sizeof (SYSTEMTIME));
}
else
ZeroMemory( &pST, sizeof(LPSYSTEMTIME));
}
return TRUE;
}
/*****************************************************************************\
* ipp_W32ToIppTime (Local Routine)
*
* Converts a Win32 SYSTEMTIME to UCT.
*
\*****************************************************************************/
DWORD ipp_W32ToIppTime(
LPSYSTEMTIME pst) // We pass in the T0 for the system in here
{
#if 1
tm tmCvt;
struct _timeb tiTimeb;
_ftime(&tiTimeb); // We obtain the time zone difference from here,
// mktime assumes local time in doing the conversion
ZeroMemory(&tmCvt, sizeof(tm));
tmCvt.tm_sec = (int)(short)pst->wSecond;
tmCvt.tm_min = (int)(short)pst->wMinute;
tmCvt.tm_hour = (int)(short)pst->wHour;
tmCvt.tm_mday = (int)(short)pst->wDay;
tmCvt.tm_mon = (int)(short)(pst->wMonth - 1);
tmCvt.tm_year = ((int)(short)pst->wYear - 1900);
tmCvt.tm_wday = (int)(short)pst->wDayOfWeek;
INT iUCT = (INT)mktime(&tmCvt);
iUCT -= tiTimeb.timezone * 60; // Normalise for timezone difference
return (DWORD)iUCT;
#else
WORD wDate;
WORD wTime;
FILETIME ft;
SystemTimeToFileTime(pst, &ft);
FileTimeToDosDateTime(&ft, &wDate, &wTime);
return (DWORD)MAKELONG(wTime, wDate);
#endif
}
/*****************************************************************************\
* ipp_JidFromUri
*
* Returns a job-id from a job-uri string.
*
\*****************************************************************************/
DWORD ipp_JidFromUri(
LPTSTR lpszUri)
{
LPTSTR lpszPtr;
DWORD jid = 0;
if (lpszPtr = webFindRChar(lpszUri, TEXT('=')))
jid = webAtoI(++lpszPtr);
return jid;
}
/*****************************************************************************\
* ipp_PackStrings
*
* This routine packs strings to the end of a buffer. This is used for
* building a JOB_INFO_2 list from IPP information.
*
\*****************************************************************************/
LPBYTE ipp_PackStrings(
LPTSTR* ppszSrc,
LPBYTE pbDst,
LPDWORD pdwDstOffsets,
LPBYTE pbEnd)
{
DWORD cbStr;
while (*pdwDstOffsets != (DWORD)-1) {
// We fill in the strings from the end of the structure and fill in the
// structure forwards, if our string pointer is ever less than the address
// we are copying into, the initial block allocated was too small
if (*ppszSrc) {
cbStr = webStrSize(*ppszSrc);
pbEnd -= cbStr;
CopyMemory(pbEnd, *ppszSrc, cbStr);
LPTSTR *strWriteLoc = (LPTSTR *)(pbDst + *pdwDstOffsets);
WEB_IPP_ASSERT( (LPBYTE)pbEnd >= (LPBYTE)strWriteLoc );
*strWriteLoc = (LPTSTR)pbEnd;
} else {
*(LPTSTR *)(pbDst + *pdwDstOffsets) = TEXT('\0');
}
ppszSrc++;
pdwDstOffsets++;
}
return pbEnd;
}
/*****************************************************************************\
* ipp_NextVal (Local Routine)
*
* Returns next value-field in a tag-attribute.
*
* Parameters:
* ----------
* lpIppHdr - Pointer to the IPP-Stream.
* lpcbIdx - Current Byte offset into the IPP-Stream.
* cbIppHdr - Size of the IPP-Stream.
*
\*****************************************************************************/
LPBYTE ipp_NextVal(
LPBYTE lpIppHdr,
LPDWORD lpcbIdx,
DWORD cbIppHdr)
{
DWORD cbIdx;
DWORD cbSize;
// The (cbIdx) is positioned at the location where a length
// is to be read.
//
cbIdx = *lpcbIdx;
// Make sure we have enough to read a WORD value.
//
if ((cbIdx + IPP_SIZEOFTAG) >= cbIppHdr)
return NULL;
// Get the name-length of the attribute. Adjust our
// offset by this amount and add size of length-field to
// position to the next attribute-length.
//
cbSize = (DWORD)ipp_ReadWord(lpIppHdr, cbIdx);
cbIdx += (cbSize + IPP_SIZEOFLEN);
if (cbIdx >= cbIppHdr)
return NULL;
*lpcbIdx = cbIdx;
return lpIppHdr + cbIdx;
}
/*****************************************************************************\
* ipp_NextTag (Local Routine)
*
* Returns a pointer to the next tag in the header. If this routine returns
* NULL, then we do not have enough data to advance to the next-tag.
*
* Parameters:
* ----------
* lpTag - Pointer to the current-tag postion.
* lpcbIdx - Bytes offset from the header.
* cbHdr - Size of the header-stream we're working with.
*
\*****************************************************************************/
LPBYTE ipp_NextTag(
LPBYTE lpIppHdr,
LPDWORD lpcbIdx,
DWORD cbIppHdr)
{
BYTE bTag;
DWORD cbIdx;
DWORD cbSize;
// Out current byte-offset is at a tag. Grab the tag, and advance
// our index past it to proced to get past the possible attribute.
//
cbIdx = *lpcbIdx;
bTag = ipp_ReadByte(lpIppHdr, cbIdx);
cbIdx += IPP_SIZEOFTAG;
// If our tag is a deliminator, then we need only advance to the
// next byte where the next tag should be.
//
if (IS_TAG_DELIMITER(bTag)) {
// Make sure we have enough bytes to return an offset
// to the next tag.
//
if (cbIdx >= cbIppHdr)
return NULL;
*lpcbIdx = cbIdx;
return lpIppHdr + cbIdx;
}
// Otherwise, we are currently at an attribute-tag. We need to
// calculate bytes offset to the next tag.
//
if (IS_TAG_ATTRIBUTE(bTag)) {
// This logic calculates the byte-offsets to the
// value-tags. We need to do two value adjustments
// since there is both a (name) and a (value) component
// to an attribute.
//
if (ipp_NextVal(lpIppHdr, &cbIdx, cbIppHdr)) {
// This last adjustment will return the position
// of the next tag.
//
if (ipp_NextVal(lpIppHdr, &cbIdx, cbIppHdr)) {
*lpcbIdx = cbIdx;
return lpIppHdr + cbIdx;
}
}
}
return NULL;
}
/*****************************************************************************\
* ipp_RelAttr (Local Routine)
*
* Release (Free) the attribute block.
*
\*****************************************************************************/
BOOL ipp_RelAttr(
LPIPPATTR lpAttr)
{
if (lpAttr) {
webFree(lpAttr->lpszName);
webFree(lpAttr->lpValue);
webFree(lpAttr);
return TRUE;
}
return FALSE;
}
/*****************************************************************************\
* ipp_GetAttr (Local Routine)
*
* Returns an attribute in a structured-from.
*
\*****************************************************************************/
LPIPPATTR ipp_GetAttr(
LPBYTE lpTag,
DWORD cbIdx,
LPIPPOBJ lpObj)
{
LPIPPATTR lpAttr = NULL;
WORD wIdx;
BYTE bTag = ipp_ReadByte(lpTag, 0);
DWORD cbSize;
if (IS_TAG_ATTRIBUTE(bTag)) {
if (lpAttr = (LPIPPATTR)webAlloc(sizeof(IPPATTR))) {
__try {
lpAttr->bTag = bTag;
lpTag += IPP_SIZEOFTAG;
lpAttr->cbName = ipp_ReadWord(lpTag, 0);
lpTag += IPP_SIZEOFLEN;
if (lpAttr->cbName) {
lpAttr->lpszName = webMBtoTC(CP_UTF8, (LPSTR)lpTag, lpAttr->cbName);
lpTag += lpAttr->cbName;
}
#if 1
// hack. This is added to support name-with-language attributes. To
// do this temporarily, this code will work but ignore the language
// part of the attribute. In the future, we can look at dealing with
// the language appropriately.
//
// 15-Mar-1999 : ChrisWil (HP).
//
if (IS_TAG_COMPOUND(bTag)) {
if (ipp_ReadWord(lpTag, 0)) {
lpTag += IPP_SIZEOFLEN;
lpTag += ipp_ReadWord(lpTag, 0);
lpTag += IPP_SIZEOFLEN;
}
}
#endif
lpAttr->cbValue = ipp_ReadWord(lpTag, 0);
lpTag += IPP_SIZEOFLEN;
// If there's a value, then make sure that the size doesn't
// exceed our IPP-Stream.
//
if (lpAttr->cbValue && (lpAttr->cbValue < (lpObj->cbIppHdr - cbIdx))) {
// Convert the value to the appropriate format. This
// block currently makes the assumption that all strings
// are dealt with as Octet-Strings. When this parser
// supports other character-sets, then the conversion
// for Character-Strings can utilize a different codepage.
//
if (IS_TAG_OCTSTR(lpAttr->bTag)) {
lpAttr->lpValue = (LPVOID)webMBtoTC(CP_UTF8, (LPSTR)lpTag, lpAttr->cbValue);
} else if (IS_TAG_CHARSETSTR(lpAttr->bTag)) {
lpAttr->lpValue = (LPVOID)webMBtoTC(lpObj->uCPRcv, (LPSTR)lpTag, lpAttr->cbValue);
} else if (IS_TAG_CHRSTR(lpAttr->bTag)) {
lpAttr->lpValue = (LPVOID)webMBtoTC(CP_ACP, (LPSTR)lpTag, lpAttr->cbValue);
} else {
if (lpAttr->cbValue <= sizeof(DWORD))
lpAttr->lpValue = (LPVOID)webAlloc(sizeof(DWORD));
else
lpAttr->lpValue = (LPVOID)webAlloc(lpAttr->cbValue);
if (lpAttr->lpValue) {
if (lpAttr->cbValue == sizeof(BYTE))
*(LPDWORD)(lpAttr->lpValue) = (DWORD)ipp_ReadByte(lpTag, 0);
else if (lpAttr->cbValue == sizeof(WORD))
*(LPDWORD)(lpAttr->lpValue) = (DWORD)ipp_ReadWord(lpTag, 0);
else if (lpAttr->cbValue == sizeof(DWORD))
*(LPDWORD)(lpAttr->lpValue) = ipp_ReadDWord(lpTag, 0);
else
CopyMemory((LPVOID)lpAttr->lpValue, (LPVOID)lpTag, lpAttr->cbValue);
}
}
}
} __except (1) {
ipp_RelAttr(lpAttr);
lpAttr = NULL;
}
}
}
return lpAttr;
}
/*****************************************************************************\
* ipp_WriteAttr (Local Routine)
*
* Write out the attribute. If NULL is passed in as the (lplpIppPtr), then
* this routine returns the size necessary to write the info.
*
\*****************************************************************************/
DWORD ipp_WriteAttr(
LPBYTE* lplpIppPtr,
BYTE bTag,
DWORD cbName,
LPVOID lpName,
DWORD cbValue,
LPVOID lpValue)
{
DWORD cbSize;
// Set the size that this attribute occupies.
//
cbSize = (cbName + cbValue + IPP_SIZEOFTAG + IPP_SIZEOFLEN + IPP_SIZEOFLEN);
// Write out the attribute to the buffer (if available).
//
if (lplpIppPtr) {
ipp_WriteByte(lplpIppPtr, bTag);
if (cbName) {
ipp_WriteWord(lplpIppPtr, (WORD)cbName);
ipp_WriteData(lplpIppPtr, (LPVOID)lpName, cbName);
} else {
ipp_WriteWord(lplpIppPtr, (WORD)cbName);
}
ipp_WriteWord(lplpIppPtr, (WORD)cbValue);
switch (bTag) {
case IPP_TAG_INT_INTEGER:
case IPP_TAG_INT_ENUM:
ipp_WriteDWord(lplpIppPtr, * (DWORD*)lpValue);
break;
case IPP_TAG_INT_BOOLEAN:
ipp_WriteByte(lplpIppPtr, * (BYTE*)lpValue);
break;
default:
ipp_WriteData(lplpIppPtr, (LPVOID)lpValue , cbValue);
break;
}
}
return cbSize;
}
/*****************************************************************************\
* ipp_SizeAttr (Local Routine)
*
* Return the size necessary to store the attribute.
*
\*****************************************************************************/
inline DWORD ipp_SizeAttr(
DWORD cbName,
DWORD cbValue)
{
return ipp_WriteAttr(NULL, 0, cbName, NULL, cbValue, NULL);
}
/*****************************************************************************\
* ipp_WriteHead (Local Routine)
*
* Write out our "generic" type header. This includes the character-set
* that we support.
*
\*****************************************************************************/
DWORD ipp_WriteHead(
LPBYTE* lplpIppPtr,
WORD wReq,
DWORD idReq,
UINT cpReq)
{
DWORD cbNamCS;
DWORD cbValCS;
DWORD cbNamNL;
DWORD cbValNL;
LPCTSTR lpszCS;
LPSTR lputfNamCS;
LPSTR lputfValCS;
LPSTR lputfNamNL;
LPSTR lputfValNL;
DWORD cbSize = 0;
// Encode in the specified character-set.
//
lpszCS = ((cpReq == CP_ACP) ? s_szUsAscii : s_szUtf8);
lputfNamCS = webTCtoMB(CP_ACP, s_szCharSet , &cbNamCS);
lputfValCS = webTCtoMB(CP_ACP, lpszCS , &cbValCS);
lputfNamNL = webTCtoMB(CP_ACP, s_szNaturalLanguage, &cbNamNL);
lputfValNL = webTCtoMB(CP_ACP, s_szEnUS , &cbValNL);
if (lputfNamCS && lputfValCS && lputfNamNL && lputfValNL) {
// Calculate the size necessary to hold the IPP-Header.
//
cbSize = IPP_SIZEOFHDR + // Version-Request.
IPP_SIZEOFTAG + // Operation Tag
ipp_SizeAttr(cbNamCS, cbValCS) + // CharSet Attribute.
ipp_SizeAttr(cbNamNL, cbValNL); // NaturalLang Attribute.
if (lplpIppPtr) {
ipp_WriteWord(lplpIppPtr, IPP_VERSION);
ipp_WriteWord(lplpIppPtr, wReq);
ipp_WriteDWord(lplpIppPtr, idReq);
ipp_WriteByte(lplpIppPtr, IPP_TAG_DEL_OPERATION);
ipp_WriteAttr(lplpIppPtr, IPP_TAG_CHR_CHARSET, cbNamCS, lputfNamCS, cbValCS, lputfValCS);
ipp_WriteAttr(lplpIppPtr, IPP_TAG_CHR_NATURAL, cbNamNL, lputfNamNL, cbValNL, lputfValNL);
}
}
webFree(lputfValCS);
webFree(lputfNamCS);
webFree(lputfValNL);
webFree(lputfNamNL);
return cbSize;
}
/*****************************************************************************\
* ipp_SizeHdr (Local Routine)
*
* Return the size necessary to store the header and operation tags.
*
\*****************************************************************************/
inline DWORD ipp_SizeHdr(
UINT cpReq)
{
return ipp_WriteHead(NULL, 0, 0, cpReq);
}
/*****************************************************************************\
* ipp_ValDocFormat (Local Routine)
*
* Validates the document-format.
*
\*****************************************************************************/
BOOL ipp_ValDocFormat(
LPCTSTR lpszFmt)
{
DWORD idx;
DWORD cCnt;
static PCTSTR s_szFmts[] = {
s_szMimeTxtHtml ,
s_szMimeTxtPlain ,
s_szMimePostScript,
s_szMimePCL ,
s_szMimeOctStream
};
cCnt = sizeof(s_szFmts) / sizeof(s_szFmts[0]);
for (idx = 0; idx < cCnt; idx++) {
if (lstrcmpi(lpszFmt, s_szFmts[idx]) == 0)
return TRUE;
}
return FALSE;
}
/*****************************************************************************\
* ipp_ValAtrFidelity (Local Routine)
*
* Validates the attribute-fidelity.
*
\*****************************************************************************/
BOOL ipp_ValAtrFidelity(
DWORD dwVal,
LPBOOL lpbFidelity)
{
if (dwVal == 1) {
*lpbFidelity = TRUE;
} else if (dwVal == 0) {
*lpbFidelity = FALSE;
} else {
return FALSE;
}
return TRUE;
}
/*****************************************************************************\
* ipp_ValWhichJobs (Local Routine)
*
* Validates the which-jobs.
*
\*****************************************************************************/
BOOL ipp_ValWhichJobs(
PDWORD pfReq,
LPCTSTR lpszWJ)
{
DWORD idx;
DWORD cCnt;
static FLGSTR s_fsVal[] = {
RA_JOBSCOMPLETED , s_szCompleted ,
RA_JOBSUNCOMPLETED, s_szNotCompleted
};
cCnt = sizeof(s_fsVal) / sizeof(s_fsVal[0]);
for (idx = 0; idx < cCnt; idx++) {
if (lstrcmpi(lpszWJ, s_fsVal[idx].pszStr) == 0) {
x_SetReq(pfReq, s_fsVal[idx].fFlag);
return TRUE;
}
}
return FALSE;
}
/*****************************************************************************\
* ipp_GetRspSta (Local Routine)
*
* Returns the response-code and any status messages if failure.
*
\*****************************************************************************/
WORD ipp_GetRspSta(
WORD wRsp,
UINT cpReq,
LPSTR* lplputfNamSta,
LPDWORD lpcbNamSta,
LPSTR* lplputfValSta,
LPDWORD lpcbValSta)
{
DWORD idx;
DWORD cErrors;
*lplputfNamSta = NULL;
*lplputfValSta = NULL;
*lpcbNamSta = 0;
*lpcbValSta = 0;
if (SUCCESS_RANGE(wRsp) == FALSE) {
// Get the status-name.
//
*lplputfNamSta = webTCtoMB(CP_ACP, s_szStaMsg, lpcbNamSta);
// Get the string we will be using to encode the error.
//
cErrors = sizeof(s_LEIpp) / sizeof(s_LEIpp[0]);
for (idx = 0; idx < cErrors; idx++) {
if (wRsp == s_LEIpp[idx].wRsp) {
*lplputfValSta = webTCtoMB(cpReq, s_LEIpp[idx].pszStr, lpcbValSta);
break;
}
}
}
return TRUE;
}
/*****************************************************************************\
* ipp_CvtW32Val (Local Routine - Server)
*
* Converts a value to the appropriate ipp-value.
*
\*****************************************************************************/
VOID ipp_CvtW32Val(
LPCTSTR lpszName,
LPVOID lpvVal)
{
if (lstrcmpi(lpszName, s_szPrtState) == 0) {
*(LPDWORD)lpvVal = ipp_W32ToIppPrnState(*(LPDWORD)lpvVal);
} else if (lstrcmpi(lpszName, s_szJobState) == 0) {
*(LPDWORD)lpvVal = ipp_W32ToIppJobState(*(LPDWORD)lpvVal);
} else if (lstrcmpi(lpszName, s_szJobKOctets) == 0) {
*(LPDWORD)lpvVal = ipp_W32ToIppJobSize(*(LPDWORD)lpvVal);
} else if (lstrcmpi(lpszName, s_szJobKOctetsProcess) == 0) {
*(LPDWORD)lpvVal = ipp_W32ToIppJobSize(*(LPDWORD)lpvVal);
}
}
/*****************************************************************************\
* ipp_AllocUnsVals
*
* Allocates an array of ipp-values used to write to a stream.
*
\*****************************************************************************/
LPIPPATTRY ipp_AllocUnsVals(
PWEBLST pwlUns,
LPDWORD pcUns,
LPDWORD lpcbAtrs)
{
DWORD idx;
DWORD cUns;
DWORD cbUns;
PCTSTR pszStr;
LPIPPATTRY pUns = NULL;
*pcUns = 0;
if (pwlUns && (cUns = pwlUns->Count())) {
if (pUns = (LPIPPATTRY)webAlloc(cUns * sizeof(IPPATTRY))) {
*lpcbAtrs += IPP_SIZEOFTAG;
*pcUns = cUns;
// Loop through each item and convert for addition to stream.
//
pwlUns->Reset();
for (idx = 0; idx < cUns; idx++) {
if (pszStr = pwlUns->Get()) {
pUns[idx].pszNam = webTCtoMB(CP_ACP, pszStr , &pUns[idx].cbNam);
// Unsupported-values should be null.
//
pUns[idx].pszVal = NULL;
pUns[idx].cbVal = 0;
*lpcbAtrs += ipp_SizeAttr(pUns[idx].cbNam, pUns[idx].cbVal);
}
pwlUns->Next();
}
}
}
return pUns;
}
/*****************************************************************************\
* ipp_AllocAtrVals
*
* Allocates an array of ipp-values used to write to a stream.
*
\*****************************************************************************/
LPIPPATTRY ipp_AllocAtrVals(
WORD wReq,
PDWORD pfReq,
UINT cpReq,
LPBYTE lpbData,
LPIPPATTRX pRsp,
DWORD cAtr,
LPDWORD lpcbAtrs)
{
BOOL bRet = FALSE;
BOOL fWr;
DWORD idx;
BOOL bDel;
LPVOID lpvVal;
LPIPPATTRY pAtr = NULL;
if (cAtr && (pAtr = (LPIPPATTRY)webAlloc(cAtr * sizeof(IPPATTRY)))) {
// Allocate the attribute-values.
//
for (idx = 0, fWr = TRUE; idx < cAtr; idx++) {
bDel = FALSE;
// Build the attribute-name.
//
if (pRsp[idx].pszNam) {
pAtr[idx].pszNam = webTCtoMB(CP_ACP, pRsp[idx].pszNam, &pAtr[idx].cbNam);
// If the value is absolute, then assign the
// attribute directly. Otherwise, it's an offset into
// the return-structure, and as such, must be indirectly
// built.
//
if (pRsp[idx].nVal == IPP_ATR_ABSOLUTE) {
// Special-case the printer-up-time to reflect the number
// of seconds it's been up and running. Since we can't
// determine the time the printer's been up, use the time
// windows has been started.
//
if (lstrcmpi(pRsp[idx].pszNam, s_szPrtUpTime) == 0)
pRsp[idx].pvVal = (LPVOID)ULongToPtr (ipp_IppCurTime());
else
lpvVal = (LPVOID)&pRsp[idx].pvVal;
} else {
lpvVal = (LPVOID)(lpbData + (DWORD_PTR)pRsp[idx].pvVal);
}
fWr = x_ChkReq(pfReq, pRsp[idx].fReq);
}
// Add it to the stream if it is a request or if
// the response requires it.
//
if (fWr || !(wReq & IPP_RESPONSE)) {
// If the value is absolute, then assign the
// attribute directly. Otherwise, it's an offset into
// the return-structure, and as such, must be indirectly
// built.
//
if (pRsp[idx].nVal == IPP_ATR_ABSOLUTE)
lpvVal = (LPVOID)&pRsp[idx].pvVal;
else
lpvVal = (LPVOID)(lpbData + (DWORD_PTR)pRsp[idx].pvVal);
// Build the attribute-value.
//
if (IS_TAG_DELIMITER(pRsp[idx].bTag)) {
bDel = TRUE;
} else if (IS_TAG_OCTSTR(pRsp[idx].bTag)) {
pAtr[idx].pszVal = webTCtoMB(CP_UTF8, *(LPTSTR*)lpvVal, &pAtr[idx].cbVal);
} else if (IS_TAG_CHARSETSTR(pRsp[idx].bTag)) {
pAtr[idx].pszVal = webTCtoMB(cpReq, *(LPTSTR*)lpvVal, &pAtr[idx].cbVal);
} else if (IS_TAG_CHRSTR(pRsp[idx].bTag)) {
pAtr[idx].pszVal = webTCtoMB(CP_ACP, *(LPTSTR*)lpvVal, &pAtr[idx].cbVal);
} else {
pAtr[idx].pszVal = (LPSTR)webAlloc(sizeof(DWORD));
if ( !pAtr[idx].pszVal )
goto Cleanup;
if (pRsp[idx].bTag == IPP_TAG_INT_BOOLEAN) {
pAtr[idx].cbVal = IPP_SIZEOFBYTE;
} else {
pAtr[idx].cbVal = IPP_SIZEOFINT;
}
CopyMemory(pAtr[idx].pszVal, lpvVal, pAtr[idx].cbVal);
// Do we need to convert the value.
//
if (pRsp[idx].nVal == IPP_ATR_OFFSETCONV)
ipp_CvtW32Val(pRsp[idx].pszNam, (LPVOID)pAtr[idx].pszVal);
}
// If this is a delimiter then it only occupies 1 byte.
//
if (bDel)
*lpcbAtrs += IPP_SIZEOFTAG;
else
*lpcbAtrs += ipp_SizeAttr(pAtr[idx].cbNam, pAtr[idx].cbVal);
}
}
}
bRet = TRUE;
Cleanup:
if ( !bRet && pAtr ) {
for (idx = 0 ; idx < cAtr; ++idx)
if ( pAtr[idx].pszVal )
webFree(pAtr[idx].pszVal);
webFree(pAtr);
pAtr = NULL;
}
return pAtr;
}
/*****************************************************************************\
* ipp_WriteUnsVals
*
* Writes an array of ipp-values to an ipp-stream.
*
\*****************************************************************************/
BOOL ipp_WriteUnsVals(
LPBYTE* lplpIppPtr,
LPIPPATTRY pUns,
DWORD cUns)
{
DWORD idx;
if (pUns && cUns) {
ipp_WriteByte(lplpIppPtr, IPP_TAG_DEL_UNSUPPORTED);
// Unsupported values should be null.
//
for (idx = 0; idx < cUns; idx++)
ipp_WriteAttr(lplpIppPtr, IPP_TAG_OUT_UNSUPPORTED, pUns[idx].cbNam, pUns[idx].pszNam, 0, NULL);
}
return TRUE;
}
/*****************************************************************************\
* ipp_WriteAtrVals
*
* Writes an array of ipp-values to an ipp-stream.
*
\*****************************************************************************/
BOOL ipp_WriteAtrVals(
WORD wReq,
PDWORD pfReq,
LPBYTE* lplpIppPtr,
LPIPPATTRX pRsp,
LPIPPATTRY pAtr,
DWORD cAtr)
{
BOOL fWr;
DWORD idx;
for (idx = 0, fWr = TRUE; idx < cAtr; idx++) {
// If this item has a name-tag, then determine if the
// originator wants it in the stream.
//
if (pRsp[idx].pszNam)
fWr = x_ChkReq(pfReq, pRsp[idx].fReq);
// Only write out the item if it is requested, or if
// it is a request-operation.
//
if (fWr || !(wReq & IPP_RESPONSE)) {
if (pRsp[idx].nVal == IPP_ATR_TAG)
ipp_WriteByte(lplpIppPtr, pRsp[idx].bTag);
else
ipp_WriteAttr(lplpIppPtr, pRsp[idx].bTag, pAtr[idx].cbNam, pAtr[idx].pszNam, pAtr[idx].cbVal, pAtr[idx].pszVal);
}
}
return TRUE;
}
/*****************************************************************************\
* ipp_FreeAtrVals
*
* Frees array of attribute values.
*
\*****************************************************************************/
VOID ipp_FreeAtrVals(
LPIPPATTRY pAtr,
DWORD cAtr)
{
DWORD idx;
// Free up the attribute-values.
//
for (idx = 0; idx < cAtr; idx++) {
webFree(pAtr[idx].pszNam);
webFree(pAtr[idx].pszVal);
}
webFree(pAtr);
}
/*****************************************************************************\
* ipp_FreeIPPJI2 (Local Routine)
*
* Frees up the IPPJI2 memory.
*
\*****************************************************************************/
VOID ipp_FreeIPPJI2(
LPIPPJI2 lpji)
{
DWORD cCnt;
DWORD idx;
// Free JI2-Data.
//
cCnt = ((sizeof(s_JI2Off) / sizeof(s_JI2Off[0])) - 1);
for (idx = 0; idx < cCnt; idx++)
webFree(*(LPBYTE *)(((LPBYTE)&lpji->ji2) + s_JI2Off[idx]));
// Free IPP-Data.
//
cCnt = ((sizeof(s_IPJOff) / sizeof(s_IPJOff[0])) - 1);
for (idx = 0; idx < cCnt; idx++)
webFree(*(LPBYTE *)(((LPBYTE)&lpji->ipp) + s_IPJOff[idx]));
}
/*****************************************************************************\
* ipp_FreeIPPPI2 (Local Routine)
*
* Frees up the IPPPI2 memory.
*
\*****************************************************************************/
VOID ipp_FreeIPPPI2(
LPIPPPI2 lppi)
{
DWORD cCnt;
DWORD idx;
// Free PI2-Data.
//
cCnt = ((sizeof(s_PI2Off) / sizeof(s_PI2Off[0])) - 1);
for (idx = 0; idx < cCnt; idx++)
webFree(*(LPBYTE *)(((LPBYTE)&lppi->pi2) + s_PI2Off[idx]));
// Free IPP-Data.
//
cCnt = ((sizeof(s_IPPOff) / sizeof(s_IPPOff[0])) - 1);
for (idx = 0; idx < cCnt; idx++)
webFree(*(LPBYTE *)(((LPBYTE)&lppi->ipp) + s_IPPOff[idx]));
}
/*****************************************************************************\
* ipp_GetIPPJI2 (Local Routine)
*
* Returns the info for a complete job in the IPP stream. We essentially
* loop through the attributes looking for the next IPP_TAG_DEL_JOB to
* signify another job-info-item.
*
\*****************************************************************************/
LPBYTE ipp_GetIPPJI2(
LPBYTE lpbTag,
LPIPPJI2 lpji,
LPDWORD lpcbIdx,
LPIPPOBJ lpObj)
{
LPIPPATTR lpAttr;
BYTE bTag;
DWORD idx;
DWORD cAtr;
BOOL bReq;
BOOL bFound;
DWORD fAtr[IPPOBJ_MASK_SIZE];
BOOL bFid = FALSE;
BOOL bAtr = FALSE;
BOOL bEnu = FALSE;
x_SetReq(fAtr, IPP_REQALL);
bTag = ipp_ReadByte(lpbTag, 0);
bReq = ((lpObj->wReq & IPP_RESPONSE) ? FALSE : TRUE);
bEnu = (BOOL)(lpObj->wReq & IPP_REQ_ENUJOB);
while ((!bEnu || (bTag != IPP_TAG_DEL_JOB)) && (bTag != IPP_TAG_DEL_DATA)) {
if (lpAttr = ipp_GetAttr(lpbTag, *lpcbIdx, lpObj)) {
if (lpAttr->lpszName && lpAttr->lpValue) {
if (lstrcmpi(lpAttr->lpszName, s_szCharSet) == 0) {
if (lpAttr->cbValue > SIZE_CHARSET)
lpObj->wError = IPPRSP_ERROR_409;
} else if (lstrcmpi(lpAttr->lpszName, s_szNaturalLanguage) == 0) {
if (lpAttr->cbValue > SIZE_NATLANG)
lpObj->wError = IPPRSP_ERROR_409;
} else if (lstrcmpi(lpAttr->lpszName, s_szJobId) == 0) {
if (lpAttr->cbValue != SIZE_INTEGER)
lpObj->wError = IPPRSP_ERROR_409;
else
lpji->ji2.JobId = *(LPDWORD)lpAttr->lpValue;
} else if (lstrcmpi(lpAttr->lpszName, s_szJobLimit) == 0) {
if (lpAttr->cbValue != SIZE_INTEGER)
lpObj->wError = IPPRSP_ERROR_409;
else
lpji->ipp.cJobs = *(LPDWORD)lpAttr->lpValue;
} else if (lstrcmpi(lpAttr->lpszName, s_szJobState) == 0) {
if (lpAttr->cbValue != SIZE_INTEGER)
lpObj->wError = IPPRSP_ERROR_409;
else
lpji->ji2.Status = ipp_IppToW32JobState(*(LPDWORD)lpAttr->lpValue);
} else if (lstrcmpi(lpAttr->lpszName, s_szJobPri) == 0) {
if (lpAttr->cbValue != SIZE_INTEGER)
lpObj->wError = IPPRSP_ERROR_409;
else
lpji->ji2.Priority = ipp_IppToW32JobPriority(*(LPDWORD)lpAttr->lpValue);
} else if (lstrcmpi(lpAttr->lpszName, s_szJobKOctets) == 0) {
if (lpAttr->cbValue != SIZE_INTEGER)
lpObj->wError = IPPRSP_ERROR_409;
else
lpji->ji2.Size = ipp_IppToW32JobSize(*(LPDWORD)lpAttr->lpValue);
} else if (lstrcmpi(lpAttr->lpszName, s_szJobKOctetsProcess) == 0) {
if (lpAttr->cbValue != SIZE_INTEGER)
lpObj->wError = IPPRSP_ERROR_409;
else
lpji->ji2.Size = ipp_IppToW32JobSize(*(LPDWORD)lpAttr->lpValue);
} else if (lstrcmpi(lpAttr->lpszName, s_szJobSheets) == 0) {
if (lpAttr->cbValue != SIZE_INTEGER)
lpObj->wError = IPPRSP_ERROR_409;
else
lpji->ji2.TotalPages = ipp_IppToW32JobTotalPages(*(LPDWORD)lpAttr->lpValue);
} else if (lstrcmpi(lpAttr->lpszName, s_szJobSheetsCompleted) == 0) {
if (lpAttr->cbValue != SIZE_INTEGER)
lpObj->wError = IPPRSP_ERROR_409;
else
lpji->ji2.PagesPrinted = ipp_IppToW32JobPagesPrinted(*(LPDWORD)lpAttr->lpValue);
} else if (lstrcmpi(lpAttr->lpszName, s_szJobName) == 0) {
if (lpAttr->cbValue > SIZE_NAME) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
webFree(lpji->ji2.pDocument);
lpji->ji2.pDocument = webAllocStr((LPTSTR)lpAttr->lpValue);
}
} else if (lstrcmpi(lpAttr->lpszName, s_szDocName) == 0) {
if (lpAttr->cbValue > SIZE_NAME) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
webFree(lpji->ji2.pDocument);
lpji->ji2.pDocument = webAllocStr((LPTSTR)lpAttr->lpValue);
}
} else if (lstrcmpi(lpAttr->lpszName, s_szJobOrgUser) == 0) {
if (lpAttr->cbValue > SIZE_NAME) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
webFree(lpji->ji2.pUserName);
lpji->ji2.pUserName = webAllocStr((LPTSTR)lpAttr->lpValue);
}
} else if (lstrcmpi(lpAttr->lpszName, s_szJobReqUser) == 0) {
if (lpAttr->cbValue > SIZE_NAME) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
webFree(lpji->ji2.pUserName);
lpji->ji2.pUserName = webAllocStr((LPTSTR)lpAttr->lpValue);
}
} else if (lstrcmpi(lpAttr->lpszName, s_szJobUri) == 0) {
if (lpAttr->cbValue > SIZE_URI) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
webFree(lpji->ipp.pJobUri);
lpji->ipp.pJobUri = webAllocStr((LPTSTR)lpAttr->lpValue);
if (bReq && lpji->ipp.pJobUri)
lpji->ji2.JobId = ipp_JidFromUri(lpji->ipp.pJobUri);
}
} else if (lstrcmpi(lpAttr->lpszName, s_szJobPrtUri) == 0) {
if (lpAttr->cbValue > SIZE_URI) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
webFree(lpji->ipp.pPrnUri);
lpji->ipp.pPrnUri = webAllocStr((LPTSTR)lpAttr->lpValue);
}
} else if (lstrcmpi(lpAttr->lpszName, s_szPrtUri) == 0) {
if (lpAttr->cbValue > SIZE_URI) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
webFree(lpji->ipp.pPrnUri);
lpji->ipp.pPrnUri = webAllocStr((LPTSTR)lpAttr->lpValue);
}
} else if (lstrcmpi(lpAttr->lpszName, s_szDocFormat) == 0) {
if (lpAttr->cbValue > SIZE_MIMEMEDIA) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
if (ipp_ValDocFormat((PCTSTR)lpAttr->lpValue) == FALSE)
lpObj->wError = IPPRSP_ERROR_40A;
}
} else if (lstrcmpi(lpAttr->lpszName, s_szAtrFidelity) == 0) {
if (lpAttr->cbValue != SIZE_BOOLEAN) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
if (ipp_ValAtrFidelity(*(LPDWORD)lpAttr->lpValue, &bFid) == FALSE)
lpObj->wError = IPPRSP_ERROR_400;
else
lpObj->fState |= (bFid ? IPPFLG_USEFIDELITY : 0);
}
} else if (lstrcmpi(lpAttr->lpszName, s_szWhichJobs) == 0) {
if (lpAttr->cbValue > SIZE_KEYWORD) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
if (ipp_ValWhichJobs(fAtr, (PCTSTR)lpAttr->lpValue) == FALSE)
lpObj->wError = IPPRSP_ERROR_40B;
}
} else if (lstrcmpi(lpAttr->lpszName, s_szTimeAtCreation) == 0) {
if (lpAttr->cbValue != SIZE_INTEGER) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
ipp_IppToW32Time(*(LPDWORD)lpAttr->lpValue, &lpji->ji2.Submitted);
}
} else if (bReq && (lstrcmpi(lpAttr->lpszName, s_szReqAttr) == 0)) {
bAtr = TRUE;
x_SetReq(fAtr, IPP_REQCLEAR);
goto ProcessVal;
} else {
lpObj->pwlUns->Add(lpAttr->lpszName);
}
} else if (bAtr && lpAttr->lpValue) {
ProcessVal:
if (lpAttr->cbValue > SIZE_KEYWORD) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
if (lstrcmpi((PCTSTR)lpAttr->lpValue, s_szAll) == 0) {
x_SetReq(fAtr, IPP_REQALL);
} else if (lstrcmpi((PCTSTR)lpAttr->lpValue, s_szJobTemplate) == 0) {
x_SetReq(fAtr, IPP_REQJTMP);
} else if (lstrcmpi((PCTSTR)lpAttr->lpValue, s_szJobDescription) == 0) {
x_SetReq(fAtr, IPP_REQJDSC);
} else {
// Walk through the possible response attributes
// and look for those requested.
//
cAtr = sizeof(s_PJR) / sizeof(s_PJR[0]);
for (idx = 0, bFound = FALSE; idx < cAtr; idx++) {
if (s_PJR[idx].pszNam) {
if (lstrcmpi((PCTSTR)lpAttr->lpValue, s_PJR[idx].pszNam) == 0) {
x_SetReq(fAtr, s_PJR[idx].fReq);
bFound = TRUE;
break;
}
}
}
// Look through potential request/response mappings. This
// is necessary for request that have a different name
// than that we give back in a response. i.e. JobReqUser
// verses JobOrgUser.
//
if (bFound == FALSE) {
cAtr = sizeof(s_ReqRspStr) / sizeof(s_ReqRspStr[0]);
for (idx = 0; idx < cAtr; idx++) {
if (lstrcmpi((PCTSTR)lpAttr->lpValue, s_ReqRspStr[idx].pszStr) == 0) {
x_SetReq(fAtr, s_ReqRspStr[idx].fFlag);
bFound = TRUE;
break;
}
}
}
if (!bFound)
lpObj->pwlUns->Add((PCTSTR)lpAttr->lpValue);
}
}
}
ipp_RelAttr(lpAttr);
}
if (ERROR_RANGE(lpObj->wError))
break;
// Advance to next Tag. This routine also increments
// the (cbIdx) count. If we run out of bytes in the
// header before we can get to the next-tag, then this
// will return NULL.
//
if (lpbTag = ipp_NextTag(lpObj->lpIppHdr, lpcbIdx, lpObj->cbIppHdr))
bTag = ipp_ReadByte(lpbTag, 0);
else
break;
}
// If the fidelity is desired, then we should have
// no unsupported attributes.
//
if (bFid && (lpObj->pwlUns->Count()))
lpObj->wError = IPPRSP_ERROR_40B;
// Set the internal-state
//
if (bAtr)
CopyMemory(lpObj->fReq, fAtr, IPPOBJ_MASK_SIZE * sizeof(DWORD));
return lpbTag;
}
/*****************************************************************************\
* ipp_GetIPPPI2 (Local Routine)
*
* Returns the info for a complete job in the IPP stream. We essentially
* loop through the attributes looking for the next IPP_TAG_DEL_JOB to
* signify another printer-info-item.
*
\*****************************************************************************/
LPBYTE ipp_GetIPPPI2(
LPBYTE lpbTag,
LPIPPPI2 lppi,
LPDWORD lpcbIdx,
LPIPPOBJ lpObj)
{
LPIPPATTR lpAttr;
BYTE bTag;
DWORD cAtr;
DWORD idx;
BOOL bReq;
BOOL bFound;
DWORD fAtr[IPPOBJ_MASK_SIZE];
BOOL bAtr = FALSE;
x_SetReq(fAtr, IPP_REQALL);
bTag = ipp_ReadByte(lpbTag, 0);
bReq = ((lpObj->wReq & IPP_RESPONSE) ? FALSE : TRUE);
while ((bTag != IPP_TAG_DEL_PRINTER) && (bTag != IPP_TAG_DEL_DATA)) {
if (lpAttr = ipp_GetAttr(lpbTag, *lpcbIdx, lpObj)) {
// Check the name-type to see how to handle the value.
//
if (lpAttr->lpszName && lpAttr->lpValue) {
if (lstrcmpi(lpAttr->lpszName, s_szPrtUpTime) == 0) {
if (lpAttr->cbValue != SIZE_INTEGER) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
// What we want to do is get the current time in seconds and then
// work out what the T0 of the printer must be in this renormalised
// time
// These will be positive, we assume [0..2^31-1]
DWORD dwCurTime = ipp_IppCurTime();
DWORD dwPrtTime = *(LPDWORD) lpAttr->lpValue;
lppi->ipp.dwPowerUpTime = (time_t)dwCurTime - (time_t)dwPrtTime;
}
} else if (lstrcmpi(lpAttr->lpszName, s_szCharSet) == 0) {
if (lpAttr->cbValue > SIZE_CHARSET)
lpObj->wError = IPPRSP_ERROR_409;
} else if (lstrcmpi(lpAttr->lpszName, s_szNaturalLanguage) == 0) {
if (lpAttr->cbValue > SIZE_NATLANG)
lpObj->wError = IPPRSP_ERROR_409;
} else if (lstrcmpi(lpAttr->lpszName, s_szPrtState) == 0) {
if (lpAttr->cbValue != SIZE_INTEGER)
lpObj->wError = IPPRSP_ERROR_409;
else
lppi->pi2.Status = ipp_IppToW32PrnState(*(LPDWORD)lpAttr->lpValue);
} else if (lstrcmpi(lpAttr->lpszName, s_szPrtJobs) == 0) {
if (lpAttr->cbValue != SIZE_INTEGER)
lpObj->wError = IPPRSP_ERROR_409;
else
lppi->pi2.cJobs = *(LPDWORD)lpAttr->lpValue;
} else if (lstrcmpi(lpAttr->lpszName, s_szPrtName) == 0) {
if (lpAttr->cbValue > SIZE_NAME) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
webFree(lppi->pi2.pPrinterName);
lppi->pi2.pPrinterName = webAllocStr((LPTSTR)lpAttr->lpValue);
}
} else if (lstrcmpi(lpAttr->lpszName, s_szPrtUri) == 0) {
if (lpAttr->cbValue > SIZE_URI) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
webFree(lppi->ipp.pPrnUri);
lppi->ipp.pPrnUri = webAllocStr((LPTSTR)lpAttr->lpValue);
}
} else if (lstrcmpi(lpAttr->lpszName, s_szJobReqUser) == 0) {
if (lpAttr->cbValue > SIZE_NAME) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
webFree(lppi->ipp.pUsrName);
lppi->ipp.pUsrName = webAllocStr((LPTSTR)lpAttr->lpValue);
}
} else if (lstrcmpi(lpAttr->lpszName, s_szPrtUriSupported) == 0) {
if (lpAttr->cbValue > SIZE_URI) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
webFree(lppi->ipp.pPrnUri);
lppi->ipp.pPrnUri = webAllocStr((LPTSTR)lpAttr->lpValue);
}
} else if (lstrcmpi(lpAttr->lpszName, s_szPrtMake) == 0) {
if (lpAttr->cbValue > SIZE_TEXT) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
webFree(lppi->pi2.pDriverName);
lppi->pi2.pDriverName = webAllocStr((LPTSTR)lpAttr->lpValue);
}
} else if (lstrcmpi(lpAttr->lpszName, s_szDocFormat) == 0) {
if (lpAttr->cbValue > SIZE_MIMEMEDIA) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
if (ipp_ValDocFormat((PCTSTR)lpAttr->lpValue) == FALSE)
lpObj->wError = IPPRSP_ERROR_40A;
}
} else if (lstrcmpi(lpAttr->lpszName, s_szJobReqUser) == 0) {
if (lpAttr->cbValue > SIZE_NAME)
lpObj->wError = IPPRSP_ERROR_409;
} else if (bReq && (lstrcmpi(lpAttr->lpszName, s_szReqAttr) == 0)) {
bAtr = TRUE;
x_SetReq(fAtr, IPP_REQCLEAR);
goto ProcessVal;
} else {
lpObj->pwlUns->Add(lpAttr->lpszName);
}
} else if (bAtr && lpAttr->lpValue) {
ProcessVal:
if (lpAttr->cbValue > SIZE_KEYWORD) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
if (lstrcmpi((PCTSTR)lpAttr->lpValue, s_szAll) == 0) {
x_SetReq(fAtr, IPP_REQALL);
} else if (lstrcmpi((PCTSTR)lpAttr->lpValue, s_szJobTemplate) == 0) {
x_SetReq(fAtr, IPP_REQPTMP);
} else if (lstrcmpi((PCTSTR)lpAttr->lpValue, s_szPrtDescription) == 0) {
x_SetReq(fAtr, IPP_REQPDSC);
} else {
// Walk through the possible response attributes
// and look for those requested.
//
cAtr = sizeof(s_GPR) / sizeof(s_GPR[0]);
for (idx = 0, bFound = FALSE; idx < cAtr; idx++) {
if (s_GPR[idx].pszNam) {
if (lstrcmpi((PCTSTR)lpAttr->lpValue, s_GPR[idx].pszNam) == 0) {
x_SetReq(fAtr, s_GPR[idx].fReq);
bFound = TRUE;
break;
}
}
}
// Look through potential request/response mappings. This
// is necessary for request that have a different name
// than that we give back in a response. i.e. JobReqUser
// verses JobOrgUser.
//
if (bFound == FALSE) {
cAtr = sizeof(s_ReqRspStr) / sizeof(s_ReqRspStr[0]);
for (idx = 0; idx < cAtr; idx++) {
if (lstrcmpi((PCTSTR)lpAttr->lpValue, s_ReqRspStr[idx].pszStr) == 0)
x_SetReq(fAtr, s_ReqRspStr[idx].fFlag);
}
}
if (!bFound)
lpObj->pwlUns->Add((PCTSTR)lpAttr->lpValue);
}
}
}
ipp_RelAttr(lpAttr);
}
if (ERROR_RANGE(lpObj->wError))
break;
// Advance to next Tag. This routine also increments
// the (cbIdx) count. If we run out of bytes in the
// header before we can get to the next-tag, then this
// will return NULL.
//
if (lpbTag = ipp_NextTag(lpObj->lpIppHdr, lpcbIdx, lpObj->cbIppHdr))
bTag = ipp_ReadByte(lpbTag, 0);
else
break;
}
// Set the internal-state
//
if (bAtr)
CopyMemory(lpObj->fReq, fAtr, IPPOBJ_MASK_SIZE * sizeof(DWORD));
return lpbTag;
}
/*****************************************************************************\
* ipp_CopyJI2toIPPJI2 (Local Routine)
*
* Copies a JOB_INFO_2 to IPPJI2.
*
\*****************************************************************************/
LPBYTE ipp_CopyJI2toIPPJI2(
LPIPPJI2 lpjiDst,
LPJOB_INFO_2 lpJI2,
LPTSTR lpszJobBase,
LPBYTE lpbEnd)
{
LPTSTR* lpszSrc;
LPTSTR lpszPtr;
LPTSTR lpszJobUri;
LPTSTR lpszPrnUri;
LPTSTR aszSrc[(sizeof(IPPJI2) / sizeof(LPTSTR))];
// Set the start of the string-buffer.
//
ZeroMemory(aszSrc , sizeof(aszSrc));
ZeroMemory(lpjiDst, sizeof(IPPJI2));
// Copy fixed values.
//
lpjiDst->ji2.JobId = lpJI2->JobId;
lpjiDst->ji2.Status = ipp_W32ToIppJobState(lpJI2->Status);
lpjiDst->ji2.Priority = ipp_W32ToIppJobPriority(lpJI2->Priority);
lpjiDst->ji2.Size = ipp_W32ToIppJobSize(lpJI2->Size);
lpjiDst->ji2.TotalPages = ipp_W32ToIppJobTotalPages(lpJI2->TotalPages);
lpjiDst->ji2.PagesPrinted = ipp_W32ToIppJobPagesPrinted(lpJI2->PagesPrinted);
*((LPDWORD)&lpjiDst->ji2.Submitted) = ipp_W32ToIppTime(&lpJI2->Submitted);
// Build a job-uri.
//
if (lpszJobUri = (LPTSTR)webAlloc(webStrSize(lpszJobBase) + 80))
wsprintf(lpszJobUri, TEXT("%s%d"), lpszJobBase, lpJI2->JobId);
// Build a printer-uri.
//
lpszPrnUri = NULL;
if (lpszJobBase && (lpszPtr = webFindRChar(lpszJobBase, TEXT('?')))) {
*lpszPtr = TEXT('\0');
lpszPrnUri = (LPTSTR)webAllocStr(lpszJobBase);
*lpszPtr = TEXT('?');
}
// Copy strings. Make sure we place the strings in the appropriate
// offset.
//
lpszSrc = aszSrc;
*lpszSrc++ = lpJI2->pPrinterName;
*lpszSrc++ = lpJI2->pMachineName;
*lpszSrc++ = lpJI2->pUserName;
*lpszSrc++ = lpJI2->pDocument;
*lpszSrc++ = lpJI2->pNotifyName;
*lpszSrc++ = lpJI2->pDatatype;
*lpszSrc++ = lpJI2->pPrintProcessor;
*lpszSrc++ = lpJI2->pParameters;
*lpszSrc++ = lpJI2->pDriverName;
*lpszSrc++ = NULL;
*lpszSrc++ = lpJI2->pStatus;
*lpszSrc++ = NULL;
*lpszSrc++ = lpszPrnUri;
*lpszSrc++ = lpszJobUri;
lpbEnd = ipp_PackStrings(aszSrc, (LPBYTE)lpjiDst, s_IPPJI2Offs, lpbEnd);
webFree(lpszJobUri);
webFree(lpszPrnUri);
return lpbEnd;
}
/*****************************************************************************\
* ipp_SizeofIPPPI2 (Local Routine)
*
* Returns the size necessary to store a IPPPI2 struct. This excludes the
* DEVMODE and SECURITYDESCRIPTOR fields.
*
\*****************************************************************************/
DWORD ipp_SizeofIPPPI2(
LPPRINTER_INFO_2 lppi2,
LPPRINTER_INFO_IPP lpipp)
{
DWORD cCnt;
DWORD idx;
DWORD cbSize;
LPTSTR lpszStr;
// Default Size.
//
cbSize = 0;
// Get the size necessary for PRINTER_INFO_2 structure.
//
if (lppi2) {
cCnt = ((sizeof(s_PI2Off) / sizeof(s_PI2Off[0])) - 1);
for (idx = 0; idx < cCnt; idx++) {
lpszStr = *(LPTSTR*)(((LPBYTE)lppi2) + s_PI2Off[idx]);
cbSize += (lpszStr ? webStrSize(lpszStr) : 0);
}
}
// Get the size necessary for PRINTER_INFO_IPP structure.
//
if (lpipp) {
cCnt = ((sizeof(s_IPPOff) / sizeof(s_IPPOff[0])) - 1);
for (idx = 0; idx < cCnt; idx++) {
lpszStr = *(LPTSTR*)(((LPBYTE)lpipp) + s_IPPOff[idx]);
cbSize += (lpszStr ? webStrSize(lpszStr) : 0);
}
}
return cbSize;
}
/*****************************************************************************\
* ipp_SizeofIPPJI2 (Local Routine)
*
* Returns the size necessary to store a IPPJI2 struct. This excludes the
* DEVMODE and SECURITYDESCRIPTOR fields.
*
\*****************************************************************************/
DWORD ipp_SizeofIPPJI2(
LPJOB_INFO_2 lpji2,
LPJOB_INFO_IPP lpipp)
{
DWORD cCnt;
DWORD idx;
DWORD cbSize;
LPTSTR lpszStr;
// Default Size.
//
cbSize = 0;
// Get the size necessary for JOB_INFO_2 structure.
//
if (lpji2) {
cCnt = ((sizeof(s_JI2Off) / sizeof(s_JI2Off[0])) - 1);
for (idx = 0; idx < cCnt; idx++) {
lpszStr = *(LPTSTR*)(((LPBYTE)lpji2) + s_JI2Off[idx]);
cbSize += (lpszStr ? webStrSize(lpszStr) : 0);
}
}
// Get the size necessary for JOB_INFO_IPP structure.
//
if (lpipp) {
cCnt = ((sizeof(s_IPJOff) / sizeof(s_IPJOff[0])) - 1);
for (idx = 0; idx < cCnt; idx++) {
lpszStr = *(LPTSTR*)(((LPBYTE)lpipp) + s_IPJOff[idx]);
cbSize += (lpszStr ? webStrSize(lpszStr) : 0);
}
}
return cbSize;
}
/*****************************************************************************\
* ipp_BuildPI2 (Local Routine)
*
* Builds a IPPPI2 struct from PRINTER_INFO_2 and PRINTER_INFO_IPP.
*
\*****************************************************************************/
LPBYTE ipp_BuildPI2(
LPIPPPI2 lppi,
LPPRINTER_INFO_2 lppi2,
LPPRINTER_INFO_IPP lpipp,
LPBYTE lpbEnd)
{
LPTSTR* lpszSrc;
LPTSTR aszSrc[(sizeof(IPPPI2) / sizeof(LPTSTR))];
// Set the start of the string-buffer.
//
ZeroMemory(aszSrc, sizeof(aszSrc));
ZeroMemory(lppi , sizeof(IPPPI2));
// Copy fixed values.
//
if (lppi2) {
lppi->pi2.Attributes = lppi2->Attributes;
lppi->pi2.Priority = lppi2->Priority;
lppi->pi2.DefaultPriority = lppi2->DefaultPriority;
lppi->pi2.StartTime = lppi2->StartTime;
lppi->pi2.UntilTime = lppi2->UntilTime;
lppi->pi2.Status = lppi2->Status;
lppi->pi2.cJobs = lppi2->cJobs;
lppi->pi2.AveragePPM = lppi2->AveragePPM;
}
lppi->ipp.dwPowerUpTime = (lpipp ? lpipp->dwPowerUpTime : 0);
// Copy strings. Make sure we place the strings in the appropriate
// offset.
//
lpszSrc = aszSrc;
*lpszSrc++ = (lppi2 ? lppi2->pServerName : NULL);
*lpszSrc++ = (lppi2 ? lppi2->pPrinterName : NULL);
*lpszSrc++ = (lppi2 ? lppi2->pShareName : NULL);
*lpszSrc++ = (lppi2 ? lppi2->pPortName : NULL);
*lpszSrc++ = (lppi2 ? lppi2->pDriverName : NULL);
*lpszSrc++ = (lppi2 ? lppi2->pComment : NULL);
*lpszSrc++ = (lppi2 ? lppi2->pLocation : NULL);
*lpszSrc++ = NULL;
*lpszSrc++ = (lppi2 ? lppi2->pSepFile : NULL);
*lpszSrc++ = (lppi2 ? lppi2->pPrintProcessor : NULL);
*lpszSrc++ = (lppi2 ? lppi2->pDatatype : NULL);
*lpszSrc++ = (lppi2 ? lppi2->pParameters : NULL);
*lpszSrc++ = NULL;
*lpszSrc++ = (lpipp ? lpipp->pPrnUri : NULL);
*lpszSrc++ = (lpipp ? lpipp->pUsrName : NULL);
return ipp_PackStrings(aszSrc, (LPBYTE)lppi, s_IPPPI2Offs, lpbEnd);
}
/*****************************************************************************\
* ipp_BuildJI2 (Local Routine)
*
* Builds a IPPJI2 struct from JOB_INFO_2 and JOB_INFO_IPP.
*
\*****************************************************************************/
LPBYTE ipp_BuildJI2(
LPIPPJI2 lpji,
LPJOB_INFO_2 lpji2,
LPJOB_INFO_IPP lpipp,
LPBYTE lpbEnd)
{
LPTSTR* lpszSrc;
LPTSTR aszSrc[(sizeof(IPPJI2) / sizeof(LPTSTR))];
// Set the start of the string-buffer.
//
ZeroMemory(aszSrc, sizeof(aszSrc));
ZeroMemory(lpji, sizeof(IPPJI2));
// Copy fixed values.
//
if (lpji2) {
lpji->ji2.JobId = lpji2->JobId;
lpji->ji2.Status = lpji2->Status;
lpji->ji2.Priority = lpji2->Priority;
lpji->ji2.Position = lpji2->Position;
lpji->ji2.StartTime = lpji2->StartTime;
lpji->ji2.UntilTime = lpji2->UntilTime;
lpji->ji2.TotalPages = lpji2->TotalPages;
lpji->ji2.Size = lpji2->Size;
lpji->ji2.Time = lpji2->Time;
lpji->ji2.PagesPrinted = lpji2->PagesPrinted;
lpji->ji2.StartTime = lpji2->StartTime;
CopyMemory(&lpji->ji2.Submitted, &lpji2->Submitted, sizeof(SYSTEMTIME));
}
// Copy strings. Make sure we place the strings in the appropriate
// offset.
//
lpszSrc = aszSrc;
*lpszSrc++ = (lpji2 ? lpji2->pPrinterName : NULL);
*lpszSrc++ = (lpji2 ? lpji2->pMachineName : NULL);
*lpszSrc++ = (lpji2 ? lpji2->pUserName : NULL);
*lpszSrc++ = (lpji2 ? lpji2->pDocument : NULL);
*lpszSrc++ = (lpji2 ? lpji2->pNotifyName : NULL);
*lpszSrc++ = (lpji2 ? lpji2->pDatatype : NULL);
*lpszSrc++ = (lpji2 ? lpji2->pPrintProcessor : NULL);
*lpszSrc++ = (lpji2 ? lpji2->pParameters : NULL);
*lpszSrc++ = (lpji2 ? lpji2->pDriverName : NULL);
*lpszSrc++ = NULL;
*lpszSrc++ = (lpji2 ? lpji2->pStatus : NULL);
*lpszSrc++ = NULL;
*lpszSrc++ = (lpipp ? lpipp->pPrnUri : NULL);
*lpszSrc++ = (lpipp ? lpipp->pJobUri : NULL);
return ipp_PackStrings(aszSrc, (LPBYTE)lpji, s_IPPJI2Offs, lpbEnd);
}
/*****************************************************************************\
* ipp_GetJobCount (Local Routine)
*
* Returns the total number of jobs in an enumerated GETJOB response.
*
\*****************************************************************************/
DWORD ipp_GetJobCount(
LPBYTE lpbHdr,
DWORD cbHdr)
{
DWORD cbIdx;
LPBYTE lpbTag;
DWORD cJobs = 0;
// Position the tag at the start of the header.
//
lpbTag = lpbHdr + IPP_SIZEOFHDR;
for (cbIdx = IPP_SIZEOFHDR; lpbTag && (ipp_ReadByte(lpbTag, 0) != IPP_TAG_DEL_DATA); ) {
// If we hit a job-deliminator, then we have a job-info item.
//
if (ipp_ReadByte(lpbTag, 0) == IPP_TAG_DEL_JOB)
cJobs++;
// Advance to next Tag. This routine also increments
// the (cbIdx) count. If we run out of bytes in the
// header before we can get to the next-tag, then this
// will return NULL.
//
lpbTag = ipp_NextTag(lpbHdr, &cbIdx, cbHdr);
}
return cJobs;
}
/*****************************************************************************\
* ipp_IppToW32 (Local Routine - Client/Server)
*
* Converts an Ipp-Header to a W32-Structure.
*
\*****************************************************************************/
DWORD ipp_IppToW32(
LPIPPOBJ lpObj,
LPBYTE* lplpRawHdr,
LPDWORD lpcbRawHdr)
{
DWORD cbIdx;
DWORD dwCmd;
IPPJI2 ji;
IPPPI2 pi;
PIPPREQ_ALL pr;
UINT uType = IPPTYPE_UNKNOWN;
DWORD dwRet = WEBIPP_FAIL;
// Position the tag at the Tag/Attributes and fetch the information
// for the request.
//
cbIdx = IPP_SIZEOFHDR;
switch (lpObj->wReq) {
case IPP_REQ_PRINTJOB:
case IPP_REQ_VALIDATEJOB:
case IPP_REQ_GETJOB:
case IPP_REQ_CANCELJOB:
case IPP_REQ_PAUSEJOB:
case IPP_REQ_RESUMEJOB:
case IPP_REQ_RESTARTJOB:
case IPP_REQ_ENUJOB:
ZeroMemory(&ji, sizeof(IPPJI2));
ji.ipp.cJobs = IPP_GETJOB_ALL;
ipp_GetIPPJI2(lpObj->lpIppHdr + IPP_SIZEOFHDR, &ji, &cbIdx, lpObj);
uType = IPPTYPE_JOB;
break;
case IPP_REQ_GETPRN:
case IPP_REQ_PAUSEPRN:
case IPP_REQ_CANCELPRN:
case IPP_REQ_RESUMEPRN:
ZeroMemory(&pi, sizeof(IPPPI2));
ipp_GetIPPPI2(lpObj->lpIppHdr + IPP_SIZEOFHDR, &pi, &cbIdx, lpObj);
uType = IPPTYPE_PRT;
break;
case IPP_REQ_FORCEAUTH:
uType = IPPTYPE_AUTH;
break;
}
// If a failure occured, then there's no need to proceed.
//
if (ERROR_RANGE(lpObj->wError))
goto EndCvt;
// Initialize any default-values, that may have been overlooked
// in the request-stream.
//
switch (uType) {
case IPPTYPE_JOB:
if (ji.ji2.pUserName == NULL)
ji.ji2.pUserName = webAllocStr(s_szUnknown);
if (ji.ji2.pDocument == NULL)
ji.ji2.pDocument = webAllocStr(s_szUnknown);
break;
case IPPTYPE_PRT:
if (pi.pi2.pPrinterName == NULL)
pi.pi2.pPrinterName = webAllocStr(s_szUnknown);
break;
}
// Build the request structure based upon the request command.
//
switch (lpObj->wReq) {
case IPP_REQ_PRINTJOB:
pr = (PIPPREQ_ALL)WebIppCreatePrtJobReq(FALSE, ji.ji2.pUserName, ji.ji2.pDocument, ji.ipp.pPrnUri);
break;
case IPP_REQ_VALIDATEJOB:
pr = (PIPPREQ_ALL)WebIppCreatePrtJobReq(TRUE, ji.ji2.pUserName, ji.ji2.pDocument, ji.ipp.pPrnUri);
break;
case IPP_REQ_ENUJOB:
pr = (PIPPREQ_ALL)WebIppCreateEnuJobReq(ji.ipp.cJobs, ji.ipp.pPrnUri);
break;
case IPP_REQ_CANCELJOB:
case IPP_REQ_PAUSEJOB:
case IPP_REQ_RESUMEJOB:
case IPP_REQ_RESTARTJOB:
dwCmd = ipp_MapReqToJobCmd(lpObj->wReq);
pr = (PIPPREQ_ALL)WebIppCreateSetJobReq(ji.ji2.JobId, dwCmd, ji.ipp.pPrnUri);
break;
case IPP_REQ_GETJOB:
pr = (PIPPREQ_ALL)WebIppCreateGetJobReq(ji.ji2.JobId, ji.ipp.pPrnUri);
break;
case IPP_REQ_GETPRN:
pr = (PIPPREQ_ALL)WebIppCreateGetPrnReq(0, pi.ipp.pPrnUri);
break;
case IPP_REQ_PAUSEPRN:
case IPP_REQ_CANCELPRN:
case IPP_REQ_RESUMEPRN:
dwCmd = ipp_MapReqToPrnCmd(lpObj->wReq);
pr = (PIPPREQ_ALL)WebIppCreateSetPrnReq(dwCmd, pi.ipp.pUsrName, pi.ipp.pPrnUri);
break;
case IPP_REQ_FORCEAUTH:
pr = (PIPPREQ_AUTH)WebIppCreateAuthReq();
break;
default:
pr = NULL;
break;
}
// Set the return values.
//
if (pr) {
*lplpRawHdr = (LPBYTE)pr;
*lpcbRawHdr = pr->cbSize;
dwRet = WEBIPP_OK;
} else {
dwRet = WEBIPP_NOMEMORY;
}
EndCvt:
// Cleanup.
//
switch (uType) {
case IPPTYPE_JOB:
ipp_FreeIPPJI2(&ji);
break;
case IPPTYPE_PRT:
ipp_FreeIPPPI2(&pi);
break;
}
return dwRet;
}
/*****************************************************************************\
* ipp_W32ToIpp (Local Routine - Client/Server)
*
* Converts a W32 information to an IPP Header (both request and responses).
*
\*****************************************************************************/
DWORD ipp_W32ToIpp(
WORD wReq,
LPREQINFO lpri,
LPBYTE lpbData,
LPIPPATTRX pSnd,
DWORD cSnd,
LPBYTE* lplpIppHdr,
LPDWORD lpcbIppHdr)
{
LPIPPRET_ENUJOB pej;
LPBYTE lpIppHdr;
LPBYTE lpIppPtr;
DWORD cbIppHdr;
LPIPPJI2 lpji;
DWORD cUns;
DWORD idx;
DWORD cbSize;
DWORD dwRet;
DWORD dwState;
DWORD cbUns;
WORD wOut;
LPIPPATTRY pAtr = NULL;
LPIPPATTRY pUns = NULL;
// Zero out our return pointer/count.
//
*lplpIppHdr = NULL;
*lpcbIppHdr = 0;
// Is this a request or response.
//
if (wReq & IPP_RESPONSE) {
if (((LPIPPRET_ALL)lpbData)->wRsp == IPPRSP_SUCCESS) {
wOut = ((lpri->pwlUns && lpri->pwlUns->Count()) ? IPPRSP_SUCCESS1 : IPPRSP_SUCCESS);
} else {
wOut = ((LPIPPRET_ALL)lpbData)->wRsp;
}
} else {
wOut = wReq;
}
// Minimum header size.
//
cbIppHdr = ipp_SizeHdr(lpri->cpReq) + IPP_SIZEOFTAG;
// Treat the EnumJob response differently from the others, since this
// returns a dynamic list of jobs.
//
if (wReq == IPP_RET_ENUJOB) {
// Build the unsupported-attributes if there
// are any.
//
cbUns = 0;
pUns = ipp_AllocUnsVals(lpri->pwlUns, &cUns, &cbUns);
pej = (PIPPRET_ENUJOB)lpbData;
cbSize = cbIppHdr +
cbUns +
((pej->cItems && pej->cbItems) ? (3 * pej->cbItems) : 0);
if (lpIppHdr = (LPBYTE)webAlloc(cbSize)) {
cbIppHdr += cbUns;
lpIppPtr = lpIppHdr;
// Output the ipp-stream.
//
ipp_WriteHead(&lpIppPtr, wOut, lpri->idReq, lpri->cpReq);
ipp_WriteUnsVals(&lpIppPtr, pUns, cUns);
for (idx = 0, lpji = pej->pItems; idx < pej->cItems; idx++) {
dwState = ipp_IppToW32JobState(lpji[idx].ji2.Status);
// Check for any requested-attributes that include this job-entry.
//
if ((x_ChkReq(lpri->fReq, RA_JOBSCOMPLETED) && (dwState & JOB_STATUS_PRINTED)) ||
(x_ChkReq(lpri->fReq, RA_JOBSUNCOMPLETED) && !(dwState & JOB_STATUS_PRINTED)) ||
(x_ChkReq(lpri->fReq, (RA_JOBSCOMPLETED | RA_JOBSUNCOMPLETED)) == FALSE)) {
if (pAtr = ipp_AllocAtrVals(wReq, lpri->fReq, lpri->cpReq, (LPBYTE)&lpji[idx], pSnd, cSnd, &cbIppHdr)) {
ipp_WriteAtrVals(wReq, lpri->fReq, &lpIppPtr, pSnd, pAtr, cSnd);
ipp_FreeAtrVals(pAtr, cSnd);
}
}
}
ipp_WriteByte(&lpIppPtr, IPP_TAG_DEL_DATA);
// Set the return values for the IPP-Stream-Header
// as well as the size.
//
dwRet = WEBIPP_OK;
*lplpIppHdr = lpIppHdr;
*lpcbIppHdr = cbIppHdr;
} else {
dwRet = WEBIPP_NOMEMORY;
}
ipp_FreeAtrVals(pUns, cUns);
} else {
if ((cSnd == 0) ||
(pAtr = ipp_AllocAtrVals(wReq, lpri->fReq, lpri->cpReq, lpbData, pSnd, cSnd, &cbIppHdr))) {
// Build the unsupported-attributes if there
// are any.
//
pUns = ipp_AllocUnsVals(lpri->pwlUns, &cUns, &cbIppHdr);
// Write the IPP-Stream.
//
if (lpIppHdr = (LPBYTE)webAlloc(cbIppHdr)) {
lpIppPtr = lpIppHdr;
ipp_WriteHead(&lpIppPtr, wOut, lpri->idReq, lpri->cpReq);
ipp_WriteUnsVals(&lpIppPtr, pUns, cUns);
ipp_WriteAtrVals(wReq, lpri->fReq, &lpIppPtr, pSnd, pAtr, cSnd);
ipp_WriteByte(&lpIppPtr, IPP_TAG_DEL_DATA);
// Set the return values for the IPP-Stream-Header
// as well as the size.
//
dwRet = WEBIPP_OK;
*lplpIppHdr = lpIppHdr;
*lpcbIppHdr = cbIppHdr;
} else {
dwRet = WEBIPP_NOMEMORY;
}
if (pUns)
{
ipp_FreeAtrVals(pUns, cUns);
}
if (pAtr)
{
ipp_FreeAtrVals(pAtr, cSnd);
}
} else {
dwRet = WEBIPP_NOMEMORY;
}
}
return dwRet;
}
/*****************************************************************************\
* ipp_IppToFailure (Local Routine - Client)
*
* Converts an Ipp-Header to a IPPRET_ALL From the stream we need
* to pull out the following information:
*
\*****************************************************************************/
DWORD ipp_IppToFailure(
LPIPPOBJ lpObj,
LPBYTE* lplpRawHdr,
LPDWORD lpcbRawHdr)
{
PIPPRET_ALL pbr;
WORD wRsp;
BOOL bRet;
DWORD dwRet;
// Pull out the response.
//
wRsp = ipp_ReadWord(lpObj->lpIppHdr, IPP_SIZEOFVER);
bRet = SUCCESS_RANGE(wRsp);
// Build the response structure.
//
if (pbr = WebIppCreateBadRet(wRsp, bRet)) {
*lplpRawHdr = (LPBYTE)pbr;
*lpcbRawHdr = pbr->cbSize;
dwRet = WEBIPP_OK;
} else {
dwRet = WEBIPP_NOMEMORY;
}
return dwRet;
}
/*****************************************************************************\
* ipp_IppToJobRet (Local Routine - Client)
*
* Converts an Ipp-Header to a IPPRET_JOB. From the stream we need
* to pull out the following information:
*
\*****************************************************************************/
DWORD ipp_IppToJobRet(
LPIPPOBJ lpObj,
LPBYTE* lplpRawHdr,
LPDWORD lpcbRawHdr)
{
LPBYTE lpbTag;
PIPPRET_JOB pj;
WORD wRsp;
IPPJI2 ji;
DWORD cbIdx;
BOOL bRet;
DWORD dwRet;
BOOL bValidate = FALSE;
// Set our default-settings necessary for our PIPPRET_JOB.
//
ZeroMemory(&ji, sizeof(IPPJI2));
// Position the tag at the Tag/Attributes.
//
lpbTag = lpObj->lpIppHdr + IPP_SIZEOFHDR;
// Pull out the response.
//
wRsp = ipp_ReadWord(lpObj->lpIppHdr, IPP_SIZEOFVER);
// If this is a failure-response then call the routine to
// generate a failure-structure.
//
if (SUCCESS_RANGE(wRsp) == FALSE)
return ipp_IppToFailure(lpObj, lplpRawHdr, lpcbRawHdr);
// Traverse through the header, advancing through the attributes,
// until the IPP_TAG_DEL_DATA is encountered.
//
for (cbIdx = IPP_SIZEOFHDR; lpbTag && (ipp_ReadByte(lpbTag, 0) != IPP_TAG_DEL_DATA); ) {
// Look for a IPP_TAG_DEL_JOB to indicate we have a job-info
// item. Otherwise, skip to the next attribute.
//
if (ipp_ReadByte(lpbTag, 0) == IPP_TAG_DEL_JOB) {
// Since were currently at a deliminator, we need to get to
// the next for the start of the job.
//
if (lpbTag = ipp_NextTag(lpObj->lpIppHdr, &cbIdx, lpObj->cbIppHdr)) {
lpbTag = ipp_GetIPPJI2(lpbTag, &ji, &cbIdx, lpObj);
}
} else {
lpbTag = ipp_NextTag(lpObj->lpIppHdr, &cbIdx, lpObj->cbIppHdr);
}
}
// Determine the correct return-code based upon the request response.
//
switch (lpObj->wReq) {
case IPP_RET_PRINTJOB:
bRet = (SUCCESS_RANGE(wRsp) ? (BOOL)ji.ji2.JobId : FALSE);
break;
case IPP_RET_VALIDATEJOB:
bValidate = TRUE;
// Fall Through.
//
default:
bRet = SUCCESS_RANGE(wRsp);
break;
}
// Build the response structure.
//
if (pj = WebIppCreateJobRet(wRsp, bRet, bValidate, &ji.ji2, &ji.ipp)) {
*lplpRawHdr = (LPBYTE)pj;
*lpcbRawHdr = pj->cbSize;
dwRet = WEBIPP_OK;
} else {
dwRet = WEBIPP_NOMEMORY;
}
// Cleanup.
//
ipp_FreeIPPJI2(&ji);
return dwRet;
}
/*****************************************************************************\
* ipp_IppToPrnRet (Local Routine - Client)
*
* Converts an Ipp-Header to a IPPRET_PRN. From the stream we need
* to pull out the following information:
*
\*****************************************************************************/
DWORD ipp_IppToPrnRet(
LPIPPOBJ lpObj,
LPBYTE* lplpRawHdr,
LPDWORD lpcbRawHdr)
{
PIPPRET_PRN pp;
IPPPI2 pi;
WORD wRsp;
LPBYTE lpbTag;
LPBYTE lpbEnd;
DWORD cbIdx;
DWORD idx;
DWORD dwRet;
// Set our default-settings necessary for our PIPPRET_PRN.
//
ZeroMemory(&pi, sizeof(IPPPI2));
// Position the tag at the Tag/Attributes.
//
lpbTag = lpObj->lpIppHdr + IPP_SIZEOFHDR;
// Pull out response code.
//
wRsp = ipp_ReadWord(lpObj->lpIppHdr, IPP_SIZEOFVER);
// If this is a failure-response then call the routine to
// generate a failure-structure.
//
if (SUCCESS_RANGE(wRsp) == FALSE)
return ipp_IppToFailure(lpObj, lplpRawHdr, lpcbRawHdr);
// Traverse through the header, advancing through the attributes,
// until the IPP_TAG_DEL_DATA is encountered.
//
for (cbIdx = IPP_SIZEOFHDR; lpbTag && (ipp_ReadByte(lpbTag, 0) != IPP_TAG_DEL_DATA); ) {
// Look for a IPP_TAG_DEL_PRINTER to indicate we have a printer-info
// item. Otherwise, skip to the next attribute.
//
if (ipp_ReadByte(lpbTag, 0) == IPP_TAG_DEL_PRINTER) {
// Since were currently at a deliminator, we need to get to
// the next for the start of the job.
//
if (lpbTag = ipp_NextTag(lpObj->lpIppHdr, &cbIdx, lpObj->cbIppHdr))
lpbTag = ipp_GetIPPPI2(lpbTag, &pi, &cbIdx, lpObj);
} else {
lpbTag = ipp_NextTag(lpObj->lpIppHdr, &cbIdx, lpObj->cbIppHdr);
}
}
// If none is specified for the pertinent information, then
// use a default-str.
//
if (pi.ipp.pPrnUri == NULL)
pi.ipp.pPrnUri = webAllocStr(s_szUnknown);
if (pi.ipp.pUsrName == NULL)
pi.ipp.pUsrName = webAllocStr(s_szUnknown);
if (pi.pi2.pPrinterName == NULL)
pi.pi2.pPrinterName = webAllocStr(s_szUnknown);
if (pi.pi2.pDriverName == NULL)
pi.pi2.pDriverName = webAllocStr(s_szUnknown);
// Build the response structure.
//
pp = WebIppCreatePrnRet(wRsp, SUCCESS_RANGE(wRsp), &pi.pi2, &pi.ipp);
if (pp != NULL) {
*lplpRawHdr = (LPBYTE)pp;
*lpcbRawHdr = pp->cbSize;
dwRet = WEBIPP_OK;
} else {
dwRet = WEBIPP_NOMEMORY;
}
// Cleanup.
//
ipp_FreeIPPPI2(&pi);
return dwRet;
}
/*****************************************************************************\
* ipp_IppToEnuRet (Local Routine - Client)
*
* Converts an Ipp-Header to a IPPRET_ENUJOB.
*
\*****************************************************************************/
DWORD ipp_IppToEnuRet(
LPIPPOBJ lpObj,
LPBYTE* lplpRawHdr,
LPDWORD lpcbRawHdr)
{
PIPPRET_ENUJOB pgj;
LPIPPJI2 lpjiSrc;
LPIPPJI2 lpjiDst;
WORD wRsp;
DWORD cJobs;
DWORD cbJobs;
LPBYTE lpbTag;
LPBYTE lpbEnd;
DWORD cbIdx;
DWORD idx;
DWORD dwRet;
// Set our default-settings necessary for our PIPPRET_ENUJOB.
//
cJobs = 0;
cbJobs = 0;
lpjiDst = NULL;
// Get the response-code.
//
wRsp = ipp_ReadWord(lpObj->lpIppHdr, IPP_SIZEOFVER);
// If this is a failure-response then call the routine to
// generate a failure-structure.
//
if (SUCCESS_RANGE(wRsp) == FALSE)
return ipp_IppToFailure(lpObj, lplpRawHdr, lpcbRawHdr);
// See if we have jobs to enumerate.
//
if (cJobs = ipp_GetJobCount(lpObj->lpIppHdr, lpObj->cbIppHdr)) {
if (lpjiSrc = (LPIPPJI2)webAlloc(cJobs * sizeof(IPPJI2))) {
// Get the job-info.
//
lpbTag = lpObj->lpIppHdr + IPP_SIZEOFHDR;
for (idx = 0, cbIdx = IPP_SIZEOFHDR; lpbTag && (idx < cJobs); ) {
// Look for a IPP_TAG_DEL_JOB to indicate we have a job-info
// item. Otherwise, skipp to the next attribute.
//
if (ipp_ReadByte(lpbTag, 0) == IPP_TAG_DEL_JOB) {
// Since were currently at a deliminator, we need to get to
// the next for the start of the job.
//
if (lpbTag = ipp_NextTag(lpObj->lpIppHdr, &cbIdx, lpObj->cbIppHdr))
lpbTag = ipp_GetIPPJI2(lpbTag, &lpjiSrc[idx++], &cbIdx, lpObj);
} else {
lpbTag = ipp_NextTag(lpObj->lpIppHdr, &cbIdx, lpObj->cbIppHdr);
}
}
// Get storage necessary for packed IPPJI2 structures.
//
cbJobs = (cJobs * sizeof(IPPJI2));
for (idx = 0; idx < cJobs; idx++)
cbJobs += ipp_SizeofIPPJI2(&lpjiSrc[idx].ji2, &lpjiSrc[idx].ipp);
// Allocate an array of JI2 structs to contain our
// enumeration.
//
if (lpjiDst = (LPIPPJI2)webAlloc(cbJobs)) {
// For each job-item, initialize.
//
lpbEnd = ((LPBYTE)lpjiDst) + cbJobs;
for (idx = 0; idx < cJobs; idx++)
lpbEnd = ipp_BuildJI2(&lpjiDst[idx], &lpjiSrc[idx].ji2, &lpjiSrc[idx].ipp, lpbEnd);
}
// Free the memory allocated for the job-item.
//
for (idx = 0; idx < cJobs; idx++)
ipp_FreeIPPJI2(&lpjiSrc[idx]);
webFree(lpjiSrc);
}
}
// Build the response structure.
//
pgj = WebIppCreateEnuJobRet(wRsp, SUCCESS_RANGE(wRsp), cbJobs, cJobs, lpjiDst);
if (pgj != NULL) {
*lplpRawHdr = (LPBYTE)pgj;
*lpcbRawHdr = pgj->cbSize;
dwRet = WEBIPP_OK;
} else {
dwRet = WEBIPP_NOMEMORY;
}
// Cleanup.
//
webFree(lpjiDst);
return dwRet;
}
/*****************************************************************************\
* ipp_IppToAthRet (Local Routine - Client)
*
* Converts an Ipp-Header to a IPPRET_AUTH. From the stream we need
* to pull out the following information:
*
\*****************************************************************************/
DWORD ipp_IppToAthRet(
LPIPPOBJ lpObj,
LPBYTE* lplpRawHdr,
LPDWORD lpcbRawHdr)
{
PIPPRET_AUTH pfa;
WORD wRsp;
BOOL bRet;
DWORD dwRet;
// Pull out the response.
//
wRsp = ipp_ReadWord(lpObj->lpIppHdr, IPP_SIZEOFVER);
bRet = SUCCESS_RANGE(wRsp);
// Build the response structure.
//
if (pfa = WebIppCreateAuthRet(wRsp, bRet)) {
*lplpRawHdr = (LPBYTE)pfa;
*lpcbRawHdr = pfa->cbSize;
dwRet = WEBIPP_OK;
} else {
dwRet = WEBIPP_NOMEMORY;
}
return dwRet;
}
/*****************************************************************************\
* ipp_FailureToIpp (Local Routine - Server)
*
* Converts a IPPRET_ALL to an IPP Header. This is used for responding to
* clients that an operation is not supported, or returning a failure.
*
\*****************************************************************************/
DWORD ipp_FailureToIpp(
WORD wReq,
LPREQINFO lpri,
LPBYTE lpbData,
LPBYTE* lplpIppHdr,
LPDWORD lpcbIppHdr)
{
LPBYTE lpIppHdr;
LPBYTE lpIppPtr;
DWORD cbIppHdr;
DWORD dwRet;
DWORD cbNamSta;
DWORD cbValSta;
LPSTR lputfNamSta;
LPSTR lputfValSta;
PIPPRET_ALL pbr = (PIPPRET_ALL)lpbData;
// Zero out our return pointer/count.
//
*lplpIppHdr = NULL;
*lpcbIppHdr = 0;
ipp_GetRspSta(pbr->wRsp, lpri->cpReq, &lputfNamSta, &cbNamSta, &lputfValSta, &cbValSta);
// Calculate the space necessary to generate our
// IPP-Header-Stream.
//
cbIppHdr = ipp_SizeHdr(lpri->cpReq) +
(lputfNamSta && lputfValSta ? ipp_SizeAttr(cbNamSta, cbValSta) : 0) +
IPP_SIZEOFTAG;
// Allocate the header for the IPP-Stream.
//
if (lpIppHdr = (LPBYTE)webAlloc(cbIppHdr)) {
// Initialize the pointer which will keep track
// of where we are in writing the IPP-Stream-Header.
//
lpIppPtr = lpIppHdr;
// Write out the IPP-Header-Stream.
//
ipp_WriteHead(&lpIppPtr, pbr->wRsp, lpri->idReq, lpri->cpReq);
if (lputfNamSta && lputfValSta)
ipp_WriteAttr(&lpIppPtr, IPP_TAG_CHR_TEXT, cbNamSta, lputfNamSta, cbValSta, lputfValSta);
ipp_WriteByte(&lpIppPtr, IPP_TAG_DEL_DATA);
// Set the return values for the IPP-Stream-Header
// as well as the size.
//
dwRet = WEBIPP_OK;
*lplpIppHdr = lpIppHdr;
*lpcbIppHdr = cbIppHdr;
} else {
dwRet = WEBIPP_NOMEMORY;
}
// Cleanup
//
webFree(lputfNamSta);
webFree(lputfValSta);
return dwRet;
}
/*****************************************************************************\
* Ipp Send/Receive Table
*
*
*
\*****************************************************************************/
static IPPSNDRCV s_pfnIpp[] = {
// Operation Req Form Rsp Form Req X Req X Size Rsp X Rsp X Size Rsp (cli)
// ----------------- -------- -------- ------ -------------- ------ -------------- ----------------
//
IPP_REQ_PRINTJOB , s_FormA, s_FormC, s_PJQ, sizeof(s_PJQ), s_PJR, sizeof(s_PJR), ipp_IppToJobRet,
IPP_REQ_VALIDATEJOB, s_FormA, s_FormE, s_PJQ, sizeof(s_PJQ), NULL , 0 , ipp_IppToJobRet,
IPP_REQ_CANCELJOB , s_FormB, s_FormE, s_SJQ, sizeof(s_SJQ), NULL , 0 , ipp_IppToJobRet,
IPP_REQ_GETJOB , s_FormB, s_FormC, s_GJQ, sizeof(s_GJQ), s_PJR, sizeof(s_PJR), ipp_IppToJobRet,
IPP_REQ_ENUJOB , s_FormB, s_FormF, s_EJQ, sizeof(s_EJQ), s_EJR, sizeof(s_EJR), ipp_IppToEnuRet,
IPP_REQ_GETPRN , s_FormB, s_FormD, s_GPQ, sizeof(s_GPQ), s_GPR, sizeof(s_GPR), ipp_IppToPrnRet,
IPP_REQ_PAUSEJOB , s_FormB, s_FormE, s_SJQ, sizeof(s_SJQ), NULL , 0 , ipp_IppToJobRet,
IPP_REQ_RESUMEJOB , s_FormB, s_FormE, s_SJQ, sizeof(s_SJQ), NULL , 0 , ipp_IppToJobRet,
IPP_REQ_RESTARTJOB , s_FormB, s_FormE, s_SJQ, sizeof(s_SJQ), NULL , 0 , ipp_IppToJobRet,
IPP_REQ_PAUSEPRN , s_FormB, s_FormE, s_SPQ, sizeof(s_SPQ), NULL , 0 , ipp_IppToPrnRet,
IPP_REQ_RESUMEPRN , s_FormB, s_FormE, s_SPQ, sizeof(s_SPQ), NULL , 0 , ipp_IppToPrnRet,
IPP_REQ_CANCELPRN , s_FormB, s_FormE, s_SPQ, sizeof(s_SPQ), NULL , 0 , ipp_IppToPrnRet,
IPP_REQ_FORCEAUTH , s_FormB, s_FormB, NULL , 0 , NULL , 0 , ipp_IppToAthRet
};
/*****************************************************************************\
* ipp_ValidateRcvReq (Local Routine)
*
* Returns whether the header is a supported request.
*
\*****************************************************************************/
DWORD ipp_ValidateRcvReq(
LPIPPOBJ lpObj)
{
DWORD idx;
DWORD cCnt;
DWORD dwId = ipp_ReadDWord(lpObj->lpIppHdr, IPP_SIZEOFINT);
WORD wVer = ipp_ReadWord(lpObj->lpIppHdr, 0);
WORD wReq = ipp_ReadWord(lpObj->lpIppHdr, IPP_SIZEOFVER);
// First check that we are the correct-version, then proceed
// to validate the request.
//
if (wVer == IPP_VERSION) {
if (REQID_RANGE(dwId)) {
// See if we're in the range of response codes.
//
if (SUCCESS_RANGE(wReq) || ERROR_RANGE(wReq))
return WEBIPP_OK;
// Validate supported operations.
//
cCnt = sizeof(s_pfnIpp) / sizeof(s_pfnIpp[0]);
for (idx = 0; idx < cCnt; idx++) {
if (wReq == s_pfnIpp[idx].wReq)
return WEBIPP_OK;
}
lpObj->wError = IPPRSP_ERROR_400;
} else {
lpObj->wError = IPPRSP_ERROR_400;
}
} else {
lpObj->wError = IPPRSP_ERROR_503;
}
return WEBIPP_FAIL;
}
/*****************************************************************************\
* ipp_ValForm (Local Routine)
*
* Checks the tag-order for delimiters.
*
\*****************************************************************************/
BOOL ipp_ValForm(
BYTE bTag,
PBYTE pbVal)
{
DWORD idx;
// Look to see if the tag is one of our supported groups for
// this request.
//
for (idx = 0; pbVal[idx] != (BYTE)0; idx++) {
// Is this a tag we're interested in.
//
if ((pbVal[idx] & 0x0F) == bTag) {
// If we're already encountered this tag, then we
// have an error (duplication of groups).
//
if ((pbVal[idx] & IPP_HIT) && !(pbVal[idx] & IPP_MULTIPLE))
return FALSE;
// Otherwise, mark this group as hit.
//
pbVal[idx] |= IPP_HIT;
return TRUE;
} else {
// If this is not our tag, then we need to check
// that this has at least been hit, or is an
// optional group (verifies order).
//
if (IS_RANGE_DELIMITER(bTag))
if (!(pbVal[idx] & (IPP_HIT | IPP_OPTIONAL)))
return FALSE;
}
}
return TRUE;
}
/*****************************************************************************\
* ipp_AllocVal (Local Routine)
*
* Allocates a byte-array of tags that specify order.
*
\*****************************************************************************/
PBYTE ipp_AllocVal(
WORD wReq)
{
DWORD cCnt;
DWORD idx;
PBYTE pbGrp;
PBYTE pbVal = NULL;
// Build the byte-array for validation of form.
//
cCnt = sizeof(s_pfnIpp) / sizeof(s_pfnIpp[0]);
for (idx = 0, pbGrp = NULL; idx < cCnt; idx++) {
if (wReq == s_pfnIpp[idx].wReq) {
pbGrp = s_pfnIpp[idx].pbReqForm;
break;
} else if (wReq == (IPP_RESPONSE | s_pfnIpp[idx].wReq)) {
pbGrp = s_pfnIpp[idx].pbRspForm;
break;
}
}
if (pbGrp) {
for (idx = 0; pbGrp[idx++] != (BYTE)0; );
if (idx && (pbVal = (PBYTE)webAlloc(idx)))
CopyMemory(pbVal, pbGrp, idx);
}
return pbVal;
}
/*****************************************************************************\
* ipp_ValidateRcvForm (Local Routine)
*
* Returns whether the header is well-formed.
*
\*****************************************************************************/
DWORD ipp_ValidateRcvForm(
LPIPPOBJ lpObj,
LPDWORD lpcbSize)
{
LPBYTE lpbTag;
BYTE bTag;
DWORD cbIdx;
PBYTE pbVal;
DWORD dwRet = WEBIPP_MOREDATA;
// Zero out the return buffer.
//
*lpcbSize = 0;
// Allocate our array of tags that represent order.
//
if (pbVal = ipp_AllocVal(lpObj->wReq)) {
// Advance our pointer to the start of our attributes
// in the byte-stream (i.e. skip version/request).
//
lpbTag = lpObj->lpIppHdr + IPP_SIZEOFHDR;
// Hack! Check to be sure that our headers always start
// off with an operations-attribute-tag.
//
if (IS_TAG_DELIMITER(ipp_ReadByte(lpbTag, 0))) {
// Traverse through the header, advancing through the attributes,
// until the IPP_TAG_DEL_DATA is encountered. This will verify
// that we have a well-formed header.
//
for (cbIdx = IPP_SIZEOFHDR; lpbTag; ) {
// Get the tag.
//
bTag = ipp_ReadByte(lpbTag, 0);
// Only check our delimiter tags for this
// validation.
//
if (IS_TAG_DELIMITER(bTag)) {
if (bTag == IPP_TAG_DEL_DATA) {
if (ipp_ValForm(bTag, pbVal)) {
*lpcbSize = (cbIdx + 1);
dwRet = WEBIPP_OK;
goto EndVal;
} else {
goto BadFrm;
}
} else {
if (ipp_ValForm(bTag, pbVal) == FALSE)
goto BadFrm;
}
}
// Advance to next Tag. This routine also increments
// the (cbIdx) count. If we run out of bytes in the
// header before we can get to the next-tag, then this
// will return NULL.
//
lpbTag = ipp_NextTag(lpObj->lpIppHdr, &cbIdx, lpObj->cbIppHdr);
}
} else {
BadFrm:
lpObj->wError = IPPRSP_ERROR_400;
dwRet = WEBIPP_FAIL;
}
EndVal:
webFree(pbVal);
} else {
lpObj->wError = IPPRSP_ERROR_505;
dwRet = WEBIPP_NOMEMORY;
}
return dwRet;
}
/*****************************************************************************\
* ipp_ValidateRcvCharSet (Local Routine)
*
* Returns whether we support the character-set.
*
\*****************************************************************************/
DWORD ipp_ValidateRcvCharSet(
LPIPPOBJ lpObj)
{
LPIPPATTR lpAttr;
LPBYTE lpbTag;
BYTE bTag;
DWORD cbIdx;
DWORD dwRet = WEBIPP_FAIL;
// Advance our pointer to the start of our attributes
// in the byte-stream (i.e. skip version/request).
//
lpbTag = lpObj->lpIppHdr + IPP_SIZEOFHDR;
// Traverse through the header, advancing through the attributes,
// until the IPP_TAG_DEL_DATA is encountered. This will verify
// that we have a well-formed header.
//
for (cbIdx = IPP_SIZEOFHDR; lpbTag; ) {
bTag = ipp_ReadByte(lpbTag, 0);
// If we walked through the end of our stream, then
// the stream does not contain character-set information.
//
if (IS_TAG_DELIMITER(bTag) && (bTag != IPP_TAG_DEL_OPERATION))
break;
// If we are pointing at an attribute, then retrieve
// it in a format we understand.
//
if (lpAttr = ipp_GetAttr(lpbTag, cbIdx, lpObj)) {
// Check the name-type to see how to handle the value.
//
if (lpAttr->lpszName) {
if (lstrcmpi(lpAttr->lpszName, s_szCharSet) == 0) {
if (lpObj->fState & IPPFLG_CHARSET) {
lpObj->wError = IPPRSP_ERROR_400;
dwRet = WEBIPP_FAIL;
} else {
lpObj->fState |= IPPFLG_CHARSET;
if (lpAttr->cbValue > SIZE_CHARSET) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
if (lstrcmpi((LPTSTR)lpAttr->lpValue, s_szUtf8) == 0) {
lpObj->uCPRcv = CP_UTF8;
dwRet = WEBIPP_OK;
} else if (lstrcmpi((LPTSTR)lpAttr->lpValue, s_szUsAscii) == 0) {
lpObj->uCPRcv = CP_ACP;
dwRet = WEBIPP_OK;
} else {
lpObj->wError = IPPRSP_ERROR_40D;
}
}
}
}
}
ipp_RelAttr(lpAttr);
}
if (ERROR_RANGE(lpObj->wError))
break;
// Advance to next Tag. This routine also increments
// the (cbIdx) count. If we run out of bytes in the
// header before we can get to the next-tag, then this
// will return NULL.
//
lpbTag = ipp_NextTag(lpObj->lpIppHdr, &cbIdx, lpObj->cbIppHdr);
}
if ((dwRet != WEBIPP_OK) && (lpObj->wError == IPPRSP_SUCCESS))
lpObj->wError = IPPRSP_ERROR_400;
return dwRet;
}
/*****************************************************************************\
* ipp_ValidateRcvLang (Local Routine)
*
* Returns whether we support the natural-language.
*
\*****************************************************************************/
DWORD ipp_ValidateRcvLang(
LPIPPOBJ lpObj)
{
LPIPPATTR lpAttr;
LPBYTE lpbTag;
BYTE bTag;
DWORD cbIdx;
DWORD dwRet = WEBIPP_FAIL;
// Advance our pointer to the start of our attributes
// in the byte-stream (i.e. skip version/request).
//
lpbTag = lpObj->lpIppHdr + IPP_SIZEOFHDR;
// Traverse through the header, advancing through the attributes,
// until the IPP_TAG_DEL_DATA is encountered. This will verify
// that we have a well-formed header.
//
for (cbIdx = IPP_SIZEOFHDR; lpbTag; ) {
bTag = ipp_ReadByte(lpbTag, 0);
// If we walked through the end of our stream, then
// the stream does not contain natural-language information.
//
if (IS_TAG_DELIMITER(bTag) && (bTag != IPP_TAG_DEL_OPERATION))
break;
// If we are pointing at an attribute, then retrieve
// it in a format we understand.
//
if (lpAttr = ipp_GetAttr(lpbTag, cbIdx, lpObj)) {
// Check the name-type to see how to handle the value.
//
if (lpAttr->lpszName) {
if (lstrcmpi(lpAttr->lpszName, s_szNaturalLanguage) == 0) {
if (lpObj->fState & IPPFLG_NATLANG) {
lpObj->wError = IPPRSP_ERROR_400;
dwRet = WEBIPP_FAIL;
} else {
lpObj->fState |= IPPFLG_NATLANG;
if (lpAttr->cbValue > SIZE_NATLANG) {
lpObj->wError = IPPRSP_ERROR_409;
} else {
if (lstrcmpi((LPTSTR)lpAttr->lpValue, s_szEnUS) == 0) {
dwRet = WEBIPP_OK;
} else {
dwRet = WEBIPP_OK;
}
}
}
}
}
ipp_RelAttr(lpAttr);
}
if (ERROR_RANGE(lpObj->wError))
break;
// Advance to next Tag. This routine also increments
// the (cbIdx) count. If we run out of bytes in the
// header before we can get to the next-tag, then this
// will return NULL.
//
lpbTag = ipp_NextTag(lpObj->lpIppHdr, &cbIdx, lpObj->cbIppHdr);
}
if ((dwRet != WEBIPP_OK) && (lpObj->wError == IPPRSP_SUCCESS))
lpObj->wError = IPPRSP_ERROR_400;
return dwRet;
}
/*****************************************************************************\
* ipp_ValidateRcvHdr (Local Routine)
*
* Parses through the (lpbHdr) and returns whether it's a full (complete)
* header. Essentially, this need only look through the byte-stream until
* it finds the IPP_TAG_DEL_DATA attribute.
*
* Returns the size of the header (in bytes).
*
\*****************************************************************************/
DWORD ipp_ValidateRcvHdr(
LPIPPOBJ lpObj,
LPDWORD lpcbSize)
{
LPBYTE lpbTag;
DWORD cbIdx;
DWORD cbSize;
DWORD dwRet;
// Initialize our return-size so that we are reporting
// clean data.
//
*lpcbSize = 0;
// Make sure we have enough in our header to handle
// the basic verification.
//
if (lpObj->cbIppHdr <= (IPP_SIZEOFHDR + IPP_SIZEOFTAG))
return WEBIPP_MOREDATA;
// Set the request-type for the header. This will help
// us determine the appropriate conversion to the data-
// structure.
//
lpObj->idReq = ipp_ReadDWord(lpObj->lpIppHdr, IPP_SIZEOFINT);
// Validate the fixed header values, then proceed with
// other validation of the operational-attributes.
//
if ((dwRet = ipp_ValidateRcvReq(lpObj)) == WEBIPP_OK) {
if ((dwRet = ipp_ValidateRcvForm(lpObj, &cbSize)) == WEBIPP_OK) {
if ((dwRet = ipp_ValidateRcvCharSet(lpObj)) == WEBIPP_OK) {
if ((dwRet = ipp_ValidateRcvLang(lpObj)) == WEBIPP_OK) {
*lpcbSize = cbSize;
}
}
}
}
return dwRet;
}
/*****************************************************************************\
* ipp_ConvertIppToW32 (Local Routine)
*
* This routine takes in an IPP stream-buffer and generates the appropriate
* structure in which NT-Spooler-API's can process.
*
* Returns the pointer to the converted-header as well as the bytes that
* this converted header occupies.
*
\*****************************************************************************/
DWORD ipp_ConvertIppToW32(
LPIPPOBJ lpObj,
LPBYTE* lplpRawHdr,
LPDWORD lpcbRawHdr)
{
DWORD cCnt;
DWORD idx;
// Perform the request. If the request has NULL function-pointers, then
// the request/response is not supported.
//
cCnt = sizeof(s_pfnIpp) / sizeof(s_pfnIpp[0]);
for (idx = 0; idx < cCnt; idx++) {
// Check for request
//
if (lpObj->wReq == s_pfnIpp[idx].wReq)
return ipp_IppToW32(lpObj, lplpRawHdr, lpcbRawHdr);
// Check for response
//
if (lpObj->wReq == (IPP_RESPONSE | s_pfnIpp[idx].wReq))
return s_pfnIpp[idx].pfnRcvRet(lpObj, lplpRawHdr, lpcbRawHdr);
}
lpObj->wError = IPPRSP_ERROR_501;
return WEBIPP_FAIL;
}
/*****************************************************************************\
* WebIppSndData
*
* This routine takes the (lpRawHdr) and packages it up in IPP 1.1 protocol
* and returns the pointer to the Ipp-Header.
*
* Parameters:
* ----------
* dwReq - Describes the type of IPP-Header to package.
* lpRawHdr - Input pointer to raw (spooler) data-structure.
* cbRawHdr - Input byte-count of (lpRawHdr).
* lplpIppHdr - Output pointer to IPP-Header stream.
* lpcbIppHdr - Output to byte-count of Ipp-Header stream (lplpIppHdr).
*
\*****************************************************************************/
DWORD WebIppSndData(
WORD wReq,
LPREQINFO lpri,
LPBYTE lpRawHdr,
DWORD cbRawHdr,
LPBYTE* lplpIppHdr,
LPDWORD lpcbIppHdr)
{
DWORD cCnt;
DWORD idx;
LPIPPATTRX pSnd;
DWORD cSnd;
// Zero out the return pointers/sizes.
//
*lplpIppHdr = NULL;
*lpcbIppHdr = 0;
// Make sure the code-pages are something we can support.
//
if ((lpri->cpReq == CP_ACP) || (lpri->cpReq == CP_UTF8)) {
// Perform the request. If the request has NULL function-pointers,
// then the request/response is not supported.
//
cCnt = sizeof(s_pfnIpp) / sizeof(s_pfnIpp[0]);
for (idx = 0; idx < cCnt; idx++) {
// Check for request.
//
if (wReq == s_pfnIpp[idx].wReq) {
pSnd = s_pfnIpp[idx].paReq;
cSnd = s_pfnIpp[idx].cbReq / sizeof(IPPATTRX);
return ipp_W32ToIpp(wReq, lpri, lpRawHdr, pSnd, cSnd, lplpIppHdr, lpcbIppHdr);
}
// Check for response.
//
if (wReq == (IPP_RESPONSE | s_pfnIpp[idx].wReq)) {
// Check response for any fail-cases.
//
if (SUCCESS_RANGE(((LPIPPRET_ALL)lpRawHdr)->wRsp)) {
pSnd = s_pfnIpp[idx].paRsp;
cSnd = s_pfnIpp[idx].cbRsp / sizeof(IPPATTRX);
return ipp_W32ToIpp(wReq, lpri, lpRawHdr, pSnd, cSnd, lplpIppHdr, lpcbIppHdr);
}
break;
}
}
// If this was sent by our server, then we want to reply to the client
// with an ipp-stream.
//
return ipp_FailureToIpp(wReq, lpri, lpRawHdr, lplpIppHdr, lpcbIppHdr);
}
return WEBIPP_FAIL;
}
/*****************************************************************************\
* WebIppRcvOpen
*
* This routine creates an IPP-state-object which parses IPP stream-data. The
* parameter (dwReq) specifies which request we expect the stream to provide.
*
* We allocate a default-size buffer to contain the header. If more memory
* is necessary, then it is reallocated to append the data.
*
\*****************************************************************************/
HANDLE WebIppRcvOpen(
WORD wReq)
{
LPIPPOBJ lpObj;
if (lpObj = (LPIPPOBJ)webAlloc(sizeof(IPPOBJ))) {
if (lpObj->pwlUns = (PWEBLST)new CWebLst()) {
lpObj->wReq = wReq;
lpObj->wError = IPPRSP_SUCCESS;
lpObj->idReq = 0;
lpObj->uCPRcv = CP_UTF8;
lpObj->fState = 0;
lpObj->cbIppHdr = 0;
lpObj->cbIppMax = IPP_BLOCK_SIZE;
lpObj->lpRawDta = NULL;
x_SetReq(lpObj->fReq, (wReq == IPP_REQ_ENUJOB ? IPP_REQENU : IPP_REQALL));
// Allocate a default buffer-size to hold the IPP
// header. This may not be large enough to hold
// the complete header so we reserve the right to
// reallocate it until it contains the entire header.
//
if (lpObj->lpIppHdr = (LPBYTE)webAlloc(lpObj->cbIppMax)) {
return (HANDLE)lpObj;
}
delete lpObj->pwlUns;
}
webFree(lpObj);
}
return NULL;
}
/*****************************************************************************\
* WebIppRcvData
*
* This routine takes in IPP stream-data and builds a complete IPP-Header. It
* is possible that the header-information is not provided in one chunk of
* stream-data. Therefore, we will not return the converted header information
* until our header is complete.
*
* Once the header is complete, it's returned in the output-buffer in the
* format that the caller can utilized in spooler-related calls.
*
* Not only does this handle the header, but it is also used to process raw
* stream-data which is returned unmodified to the caller. In the case that
* we encounter data during the processing of the IPP-Header, we need to
* return an allocated buffer pointing to DWORD-Aligned bits.
*
* Parameters:
* ----------
* hObj - Handle to the Ipp-Parse-Object.
* lpIppDta - Input pointer to ipp-stream-data. This is header and/or data.
* cbIppDta - Input byte-count contained in the (lpIppData).
* lplpRawHdr - Output pointer to spooler-define (raw) structure.
* lpcbRawHdr - Output pointer to byte-count in (lplpRawHdr).
* lplpRawDta - Output pointer to data-stream.
* lpcbRawDta - Output pointer to byte-count in (lplpRawDta).
*
* Returns:
* -------
* WEBIPP_OK - Information in lplpHdr or lplpData is valid.
* WEBIPP_FAIL - Failed in validation. Use WebIppGetError.
* WEBIPP_MOREDATA - Needs more data to complete header.
* WEBIPP_BADHANDLE - Ipp-Object-Handle is invalid.
* WEBIPP_NOMEMORY - Failed allocation request (out-of-memory).
*
\*****************************************************************************/
DWORD WebIppRcvData(
HANDLE hObj,
LPBYTE lpIppDta,
DWORD cbIppDta,
LPBYTE* lplpRawHdr,
LPDWORD lpcbRawHdr,
LPBYTE* lplpRawDta,
LPDWORD lpcbRawDta)
{
LPIPPOBJ lpObj;
LPBYTE lpNew;
DWORD cbSize;
DWORD cbData;
DWORD cBlks;
DWORD dwRet;
// Initialize the output pointers to NULL. We return two distinct
// references since it is possible that the buffer passed in contains
// both header and data.
//
*lplpRawHdr = NULL;
*lpcbRawHdr = 0;
*lplpRawDta = NULL;
*lpcbRawDta = 0;
// Process the stream-data.
//
if (lpObj = (LPIPPOBJ)hObj) {
// If our header is complete, then the stream is raw-data meant
// to be return directly. In this case we only need to return the
// data-stream passed in.
//
// Otherwise, the default-case is that we are building our header
// from the stream-data.
//
if (lpObj->fState & IPPFLG_VALID) {
// Free up the memory occupied by our header (only done on
// the first hit of this block). Since we aren't using
// this anymore during the processing of the stream, we
// shouldn't occupy any more memory than necessary.
//
if (lpObj->lpIppHdr) {
webFree(lpObj->lpIppHdr);
lpObj->lpIppHdr = NULL;
lpObj->cbIppHdr = 0;
// Likewise, if we had need of a temporary data-buffer
// to hold aligned-bits, then we need to free this up
// as well.
//
webFree(lpObj->lpRawDta);
lpObj->lpRawDta = NULL;
}
// Return the data-stream passed in.
//
dwRet = WEBIPP_OK;
*lplpRawDta = lpIppDta;
*lpcbRawDta = cbIppDta;
} else {
// Check to see if our buffer can accomodate the
// size of the buffer being passed in. If not, realloc
// a new buffer to accomodate the new chunk.
//
if ((lpObj->cbIppHdr + cbIppDta) >= lpObj->cbIppMax) {
// Determine the number of memory-blocks that we
// need to hold the (cbData) coming in.
//
cBlks = (cbIppDta / IPP_BLOCK_SIZE) + 1;
cbSize = lpObj->cbIppMax + (IPP_BLOCK_SIZE * cBlks);
lpNew = (LPBYTE)webRealloc(lpObj->lpIppHdr,
lpObj->cbIppMax,
cbSize);
if (lpNew != NULL) {
lpObj->lpIppHdr = lpNew;
lpObj->cbIppMax = cbSize;
} else {
return WEBIPP_NOMEMORY;
}
}
// Copy/Append the stream-data to our header-buffer.
//
memcpy(lpObj->lpIppHdr + lpObj->cbIppHdr, lpIppDta, cbIppDta);
lpObj->cbIppHdr += cbIppDta;
// Validate the header. If this is successful, then we have
// a well-formed-header. Otherwise, we need to request
// more data from the caller. This returns the actual size
// of the header in (cbSize).
//
if ((dwRet = ipp_ValidateRcvHdr(lpObj, &cbSize)) == WEBIPP_OK) {
// Convert the IPP-Heade to a structure (stream)
// that the caller understands (depends on dwReq).
//
dwRet = ipp_ConvertIppToW32(lpObj, lplpRawHdr, lpcbRawHdr);
if (dwRet == WEBIPP_OK) {
// The validation returns the actual-size occupied by
// the header. Therefore, if our (cbHdr) is larger, then
// the remaining information is pointing at data.
//
if (cbSize < lpObj->cbIppHdr) {
cbData = (lpObj->cbIppHdr - cbSize);
lpObj->lpRawDta = ipp_CopyAligned(lpObj->lpIppHdr + cbSize, cbData);
*lplpRawDta = lpObj->lpRawDta;
*lpcbRawDta = cbData;
}
// Set the flag indicating we have a full-header. This
// assures that subsequent calls to this routine returns
// only the lpData.
//
lpObj->fState |= IPPFLG_VALID;
}
}
}
} else {
dwRet = WEBIPP_BADHANDLE;
}
return dwRet;
}
/*****************************************************************************\
* WebIppRcvClose
*
* This routine Frees up our IPP object. This is called once the caller wishes
* to end the parsing/handling of ipp-stream-data.
*
\*****************************************************************************/
BOOL WebIppRcvClose(
HANDLE hObj)
{
LPIPPOBJ lpObj;
if (lpObj = (LPIPPOBJ)hObj) {
webFree(lpObj->lpIppHdr);
webFree(lpObj->lpRawDta);
delete lpObj->pwlUns;
webFree(lpObj);
return TRUE;
}
return FALSE;
}
/*****************************************************************************\
* WebIppGetError
*
* This routine returns the specific error in the ipp-object. This is called
* on a failure during the receive.
*
\*****************************************************************************/
WORD WebIppGetError(
HANDLE hIpp)
{
LPIPPOBJ lpObj;
if (lpObj = (LPIPPOBJ)hIpp)
return lpObj->wError;
return IPPRSP_ERROR_500;
}
/*****************************************************************************\
* WebIppGetReqInfo
*
* This routine returns the request-info.
*
\*****************************************************************************/
BOOL WebIppGetReqInfo(
HANDLE hIpp,
LPREQINFO lpri)
{
LPIPPOBJ lpObj;
if ((lpObj = (LPIPPOBJ)hIpp) && lpri) {
lpri->idReq = lpObj->idReq;
lpri->cpReq = lpObj->uCPRcv;
lpri->pwlUns = lpObj->pwlUns;
lpri->bFidelity = (lpObj->fState & IPPFLG_USEFIDELITY);
CopyMemory(lpri->fReq, lpObj->fReq, IPPOBJ_MASK_SIZE * sizeof(DWORD));
return TRUE;
}
return FALSE;
}
/*****************************************************************************\
* WebIppLeToRsp
*
* This routine returns an IPP-Response-Code from a Win32-LastError.
*
\*****************************************************************************/
WORD WebIppLeToRsp(
DWORD dwLastError)
{
DWORD idx;
DWORD cErrors;
if (dwLastError == ERROR_SUCCESS)
return IPPRSP_SUCCESS;
// Lookup lasterror.
//
cErrors = sizeof(s_LEDef) / sizeof(s_LEDef[0]);
for (idx = 0; idx < cErrors; idx++) {
if (dwLastError == s_LEDef[idx].dwLE)
return s_LEDef[idx].wRsp;
}
return IPPRSP_ERROR_500;
}
/*****************************************************************************\
* WebIppRspToLe
*
* This routine returns a Win32 LastError from an IPP-Response-Code.
*
\*****************************************************************************/
DWORD WebIppRspToLe(
WORD wRsp)
{
DWORD idx;
DWORD cErrors;
if (SUCCESS_RANGE(wRsp))
return ERROR_SUCCESS;
// Lookup lasterror.
//
cErrors = sizeof(s_LEIpp) / sizeof(s_LEIpp[0]);
for (idx = 0; idx < cErrors; idx++) {
if (wRsp == s_LEIpp[idx].wRsp)
return s_LEIpp[idx].dwLE;
}
return ERROR_INVALID_DATA;
}
/*****************************************************************************\
* WebIppCreatePrtJobReq
*
* Creates a IPPREQ_PRTJOB structure. This is the structure necessary
* for calling WebIpp* API's.
*
\*****************************************************************************/
PIPPREQ_PRTJOB WebIppCreatePrtJobReq(
BOOL bValidate,
LPCTSTR lpszUser,
LPCTSTR lpszDoc,
LPCTSTR lpszPrnUri)
{
PIPPREQ_PRTJOB ppj;
DWORD cbSize;
LPTSTR* lpszSrc;
LPTSTR aszSrc[(sizeof(IPPREQ_PRTJOB) / sizeof(LPTSTR))];
static DWORD s_Offs[] = {
offs(LPIPPREQ_PRTJOB, pDocument),
offs(LPIPPREQ_PRTJOB, pUserName),
offs(LPIPPREQ_PRTJOB, pPrnUri),
0xFFFFFFFF
};
// Calculate the size in bytes that are necesary for
// holding the IPPREQ_PRTJOB information.
//
cbSize = sizeof(IPPREQ_PRTJOB) +
webStrSize(lpszUser) +
webStrSize(lpszDoc) +
webStrSize(lpszPrnUri);
// Allocate the print-job-request structure. The string
// values are appended at the end of the structure.
//
if (ppj = (PIPPREQ_PRTJOB)webAlloc(cbSize)) {
ppj->cbSize = cbSize;
ppj->bValidate = bValidate;
lpszSrc = aszSrc;
*lpszSrc++ = (LPTSTR)lpszDoc;
*lpszSrc++ = (LPTSTR)lpszUser;
*lpszSrc++ = (LPTSTR)lpszPrnUri;
ipp_PackStrings(aszSrc, (LPBYTE)ppj, s_Offs, ((LPBYTE)ppj) + cbSize);
}
return ppj;
}
/*****************************************************************************\
* WebIppCreateGetJobReq
*
* Creates a IPPREQ_GETJOB structure. This is the structure necessary
* for calling WebIpp* API's.
*
\*****************************************************************************/
PIPPREQ_GETJOB WebIppCreateGetJobReq(
DWORD idJob,
LPCTSTR lpszPrnUri)
{
PIPPREQ_GETJOB pgj;
DWORD cbSize;
LPTSTR* lpszSrc;
LPTSTR aszSrc[(sizeof(IPPREQ_GETJOB) / sizeof(LPTSTR))];
static DWORD s_Offs[] = {
offs(LPIPPREQ_GETJOB, pPrnUri),
0xFFFFFFFF
};
// Calculate the size in bytes that are necesary for
// holding the IPPREQ_GETJOB information.
//
cbSize = sizeof(IPPREQ_GETJOB) + webStrSize(lpszPrnUri);
// Allocate the cancel-job-request structure. The string
// values are appended at the end of the structure.
//
if (pgj = (PIPPREQ_GETJOB)webAlloc(cbSize)) {
pgj->cbSize = cbSize;
pgj->idJob = idJob;
lpszSrc = aszSrc;
*lpszSrc++ = (LPTSTR)lpszPrnUri;
ipp_PackStrings(aszSrc, (LPBYTE)pgj, s_Offs, ((LPBYTE)pgj) + cbSize);
}
return pgj;
}
/*****************************************************************************\
* WebIppCreateSetJobReq
*
* Creates a IPPREQ_SETJOB structure. This is the structure necessary
* for calling WebIpp* API's.
*
\*****************************************************************************/
PIPPREQ_SETJOB WebIppCreateSetJobReq(
DWORD idJob,
DWORD dwCmd,
LPCTSTR lpszPrnUri)
{
PIPPREQ_SETJOB psj;
DWORD cbSize;
LPTSTR* lpszSrc;
LPTSTR aszSrc[(sizeof(IPPREQ_SETJOB) / sizeof(LPTSTR))];
static DWORD s_Offs[] = {
offs(LPIPPREQ_SETJOB, pPrnUri),
0xFFFFFFFF
};
// Calculate the size in bytes that are necesary for
// holding the IPPREQ_SETJOB information.
//
cbSize = sizeof(IPPREQ_SETJOB) + webStrSize(lpszPrnUri);
// Allocate the cancel-job-request structure. The string
// values are appended at the end of the structure.
//
if (psj = (PIPPREQ_SETJOB)webAlloc(cbSize)) {
psj->cbSize = cbSize;
psj->idJob = idJob;
psj->dwCmd = dwCmd;
lpszSrc = aszSrc;
*lpszSrc++ = (LPTSTR)lpszPrnUri;
ipp_PackStrings(aszSrc, (LPBYTE)psj, s_Offs, ((LPBYTE)psj) + cbSize);
}
return psj;
}
/*****************************************************************************\
* WebIppCreateEnuJobReq
*
* Creates a IPPREQ_ENUJOB structure. This is the structure necessary
* for calling WebIpp* API's.
*
\*****************************************************************************/
PIPPREQ_ENUJOB WebIppCreateEnuJobReq(
DWORD cJobs,
LPCTSTR lpszPrnUri)
{
PIPPREQ_ENUJOB pgj;
DWORD cbSize;
LPTSTR* lpszSrc;
LPTSTR aszSrc[(sizeof(IPPREQ_ENUJOB) / sizeof(LPTSTR))];
static DWORD s_Offs[] = {
offs(LPIPPREQ_ENUJOB, pPrnUri),
0xFFFFFFFF
};
// Calculate the size in bytes that are necesary for
// holding the IPPREQ_ENUJOB information.
//
cbSize = sizeof(IPPREQ_ENUJOB) + webStrSize(lpszPrnUri);
// Allocate the cancel-job-request structure. The string
// values are appended at the end of the structure.
//
if (pgj = (PIPPREQ_ENUJOB)webAlloc(cbSize)) {
pgj->cbSize = cbSize;
pgj->cJobs = cJobs;
lpszSrc = aszSrc;
*lpszSrc++ = (LPTSTR)lpszPrnUri;
ipp_PackStrings(aszSrc, (LPBYTE)pgj, s_Offs, ((LPBYTE)pgj) + cbSize);
}
return pgj;
}
/*****************************************************************************\
* WebIppCreateSetPrnReq
*
* Creates a IPPREQ_SETPRN structure. This is the structure necessary
* for calling WebIpp* API's.
*
\*****************************************************************************/
PIPPREQ_SETPRN WebIppCreateSetPrnReq(
DWORD dwCmd,
LPCTSTR lpszUsrName,
LPCTSTR lpszPrnUri)
{
PIPPREQ_SETPRN psp;
DWORD cbSize;
LPTSTR* lpszSrc;
LPTSTR aszSrc[(sizeof(IPPREQ_SETPRN) / sizeof(LPTSTR))];
static DWORD s_Offs[] = {
offs(LPIPPREQ_SETPRN, pUserName),
offs(LPIPPREQ_SETPRN, pPrnUri),
0xFFFFFFFF
};
// Calculate the size in bytes that are necesary for
// holding the IPPREQ_SETPRN information.
//
cbSize = sizeof(IPPREQ_SETPRN) +
webStrSize(lpszUsrName) +
webStrSize(lpszPrnUri);
// Allocate the set-prn-request structure. The string
// values are appended at the end of the structure.
//
if (psp = (PIPPREQ_SETPRN)webAlloc(cbSize)) {
psp->cbSize = cbSize;
psp->dwCmd = dwCmd;
lpszSrc = aszSrc;
*lpszSrc++ = (LPTSTR)lpszUsrName;
*lpszSrc++ = (LPTSTR)lpszPrnUri;
ipp_PackStrings(aszSrc, (LPBYTE)psp, s_Offs, ((LPBYTE)psp) + cbSize);
}
return psp;
}
/*****************************************************************************\
* WebIppCreateGetPrnReq
*
* Creates a IPPREQ_GETPRN structure. This is the structure necessary
* for calling WebIpp* API's.
*
\*****************************************************************************/
PIPPREQ_GETPRN WebIppCreateGetPrnReq(
DWORD dwAttr,
LPCTSTR lpszPrnUri)
{
PIPPREQ_GETPRN pgp;
DWORD cbSize;
LPTSTR* lpszSrc;
LPTSTR aszSrc[(sizeof(IPPREQ_GETPRN) / sizeof(LPTSTR))];
static DWORD s_Offs[] = {
offs(LPIPPREQ_GETPRN, pPrnUri),
0xFFFFFFFF
};
// Calculate the size in bytes that are necesary for
// holding the IPPREQ_GETPRN information.
//
cbSize = sizeof(IPPREQ_GETPRN) + webStrSize(lpszPrnUri);
// Allocate the get-prt-attribute-request structure. The string
// values are appended at the end of the structure.
//
if (pgp = (PIPPREQ_GETPRN)webAlloc(cbSize)) {
pgp->cbSize = cbSize;
pgp->dwAttr = dwAttr;
lpszSrc = aszSrc;
*lpszSrc++ = (LPTSTR)lpszPrnUri;
ipp_PackStrings(aszSrc, (LPBYTE)pgp, s_Offs, ((LPBYTE)pgp) + cbSize);
}
return pgp;
}
/*****************************************************************************\
* WebIppCreateAuthReq
*
* Creates a IPPREQ_AUTH structure. This is the structure necessary
* for calling WebIpp* API's.
*
\*****************************************************************************/
PIPPREQ_AUTH WebIppCreateAuthReq(VOID)
{
PIPPREQ_AUTH pfa;
DWORD cbSize;
// Calculate the size in bytes that are necesary for
// holding the IPPREQ_AUTH information.
//
cbSize = sizeof(IPPREQ_AUTH);
// Allocate the request structure.
//
if (pfa = (PIPPREQ_AUTH)webAlloc(cbSize)) {
pfa->cbSize = cbSize;
}
return pfa;
}
/*****************************************************************************\
* WebIppCreateJobRet
*
* Creates a IPPRET_JOB structure. This is the structure necessary
* for calling WebIpp* API's.
*
\*****************************************************************************/
PIPPRET_JOB WebIppCreateJobRet(
WORD wRsp,
BOOL bRet,
BOOL bValidate,
LPJOB_INFO_2 lpji2,
LPJOB_INFO_IPP lpipp)
{
PIPPRET_JOB pjr;
DWORD cbSize;
// Calculate our structure size.
//
cbSize = sizeof(IPPRET_JOB) + ipp_SizeofIPPJI2(lpji2, lpipp);
// Build our response.
//
if (pjr = (PIPPRET_JOB)webAlloc(cbSize)) {
pjr->cbSize = cbSize;
pjr->dwLastError = WebIppRspToLe(wRsp);
pjr->wRsp = wRsp;
pjr->bRet = bRet;
pjr->bValidate = bValidate;
ipp_BuildJI2(&pjr->ji, lpji2, lpipp, ((LPBYTE)pjr) + cbSize);
}
return pjr;
}
/*****************************************************************************\
* WebIppCreatePrnRet
*
* Creates a IPPRET_PRN structure. This is the structure necessary
* for calling WebIpp* API's.
*
\*****************************************************************************/
PIPPRET_PRN WebIppCreatePrnRet(
WORD wRsp,
BOOL bRet,
LPPRINTER_INFO_2 lppi2,
LPPRINTER_INFO_IPP lpipp)
{
PIPPRET_PRN ppr;
DWORD cbSize;
// Calculate our structure size.
//
cbSize = sizeof(IPPRET_PRN) + ipp_SizeofIPPPI2(lppi2, lpipp);
// Build our response.
//
if (ppr = (PIPPRET_PRN)webAlloc(cbSize)) {
ppr->cbSize = cbSize;
ppr->dwLastError = WebIppRspToLe(wRsp);
ppr->wRsp = wRsp;
ppr->bRet = bRet;
ipp_BuildPI2(&ppr->pi, lppi2, lpipp, ((LPBYTE)ppr) + cbSize);
}
return ppr;
}
/*****************************************************************************\
* WebIppCreateEnuJobRet
*
* Creates a IPPRET_ENUJOB structure. This is the structure necessary
* for calling WebIpp* API's.
*
\*****************************************************************************/
PIPPRET_ENUJOB WebIppCreateEnuJobRet(
WORD wRsp,
BOOL bRet,
DWORD cbJobs,
DWORD cJobs,
LPIPPJI2 lpjiSrc)
{
PIPPRET_ENUJOB pgj;
LPIPPJI2 lpjiDst;
LPBYTE lpbEnd;
DWORD idx;
DWORD cbSize;
cbSize = sizeof(IPPRET_ENUJOB) + ((cJobs && cbJobs && lpjiSrc) ? cbJobs : 0);
if (pgj = (PIPPRET_ENUJOB)webAlloc(cbSize)) {
pgj->cbSize = cbSize;
pgj->dwLastError = WebIppRspToLe(wRsp);
pgj->wRsp = wRsp;
pgj->bRet = bRet;
pgj->cItems = 0;
pgj->cbItems = 0;
pgj->pItems = NULL;
if (cJobs && cbJobs && lpjiSrc) {
// Initialize defaults.
//
pgj->cItems = cJobs;
pgj->cbItems = cbJobs;
pgj->pItems = (LPIPPJI2)(((LPBYTE)pgj) + sizeof(IPPRET_ENUJOB));
lpjiDst = pgj->pItems;
lpbEnd = ((LPBYTE)lpjiDst) + cbJobs;
for (idx = 0; idx < cJobs; idx++) {
lpbEnd = ipp_BuildJI2(&lpjiDst[idx], &lpjiSrc[idx].ji2, &lpjiSrc[idx].ipp, lpbEnd);
}
}
}
return pgj;
}
/*****************************************************************************\
* WebIppCreateBadRet
*
* Creates a IPPRET_ALL structure. This is the structure necessary
* for calling WebIpp* API's.
*
\*****************************************************************************/
PIPPRET_ALL WebIppCreateBadRet(
WORD wRsp,
BOOL bRet)
{
PIPPRET_ALL pra;
DWORD cbSize;
cbSize = sizeof(IPPRET_ALL);
if (pra = (PIPPRET_ALL)webAlloc(cbSize)) {
pra->cbSize = cbSize;
pra->dwLastError = WebIppRspToLe(wRsp);
pra->wRsp = wRsp;
pra->bRet = bRet;
}
return pra;
}
/*****************************************************************************\
* WebIppCreateAuthRet
*
* Creates a IPPRET_AUTH structure. This is the structure necessary
* for calling WebIpp* API's.
*
\*****************************************************************************/
PIPPRET_AUTH WebIppCreateAuthRet(
WORD wRsp,
BOOL bRet)
{
return (PIPPRET_AUTH)WebIppCreateBadRet(wRsp, bRet);
}
/*****************************************************************************\
* WebIppFreeMem
*
* Free memory allocated through the WebIpp routines.
*
\*****************************************************************************/
BOOL WebIppFreeMem(
LPVOID lpMem)
{
return webFree(lpMem);
}
/*****************************************************************************\
* WebIppCvtJI2toIPPJI2
*
* Converts an array of JOB_INFO_2 structures to an array of IPPJI2 structures.
*
* This code is only called from inetsrv/spool.cxx. It was better to change the
* the buffer calculation here than in the calling function since IPPJI2 is a
* web printing only call. This will return the new required Job size in the
* cbJobs Parameter that is passed in.
*
\*****************************************************************************/
LPIPPJI2 WebIppCvtJI2toIPPJI2(
LPCTSTR lpszJobBase,
LPDWORD lpcbJobs,
DWORD cJobs,
LPJOB_INFO_2 lpjiSrc)
{
LPBYTE lpbEnd;
DWORD idx;
DWORD cbSize;
DWORD cbUri;
LPIPPJI2 lpjiDst = NULL;
WEB_IPP_ASSERT(lpcbJobs);
if (*lpcbJobs && cJobs && lpjiSrc) {
// For each job, we need to add enough to hold the extra
// information.
//
cbUri = 2*(webStrSize(lpszJobBase) + sizeof(DWORD)) * cJobs;
// There can be two of these strings allocated, one for the JobUri and the
// other for the Printer Uri
cbSize = (sizeof(IPPJI2) - sizeof(JOB_INFO_2)) * cJobs + *lpcbJobs + cbUri;
// cbJobs already contains the correct size for the JOB_INFO_2 structure and its
// strings we need the space for the JOB_INFO_IPP part of the structure plus the
// extra strings that will be added.
*lpcbJobs = cbSize; // Pass the required size back
if (lpjiDst = (LPIPPJI2)webAlloc(cbSize)) {
// Position string end at the end of our buffer.
//
lpbEnd = ((LPBYTE)lpjiDst) + cbSize;
// For each job, copy.
//
for (idx = 0; idx < cJobs; idx++) {
lpbEnd = ipp_CopyJI2toIPPJI2(&lpjiDst[idx],
&lpjiSrc[idx],
(LPTSTR)lpszJobBase,
lpbEnd);
}
}
}
return lpjiDst;
}
/*****************************************************************************\
* WebIppPackJI2
*
* This takes in a JOB_INFO_2 structure whose members are note packed correctly
* and returns a correctly filled out and allocated JOB_INFO_2. It does not
* copy the DEVMODE and SECURITY-DESCRIPTOR fields.
*
\*****************************************************************************/
LPJOB_INFO_2 WebIppPackJI2(
IN LPJOB_INFO_2 lpji2,
OUT LPDWORD lpcbSize,
IN ALLOCATORFN pfnAlloc
) {
WEB_IPP_ASSERT(lpji2);
WEB_IPP_ASSERT(pfnAlloc);
WEB_IPP_ASSERT(lpcbSize);
*lpcbSize = 0;
// This is used to perform the ipp_PackStrings operation
LPTSTR aszSrc[(sizeof(IPPJI2) / sizeof(LPTSTR))];
// First get the required allocation size
DWORD dwSize = ipp_SizeofIPPJI2( lpji2, NULL ) + sizeof(JOB_INFO_2);
// Allocate the memory required to store the data
LPJOB_INFO_2 pji2out = (LPJOB_INFO_2)pfnAlloc( dwSize );
if (pji2out) {
// First, do a straight copy of the memory from the incoming JI2 to the outgoing
// ji2
LPTSTR* lpszSrc = aszSrc;
LPBYTE lpbEnd = (LPBYTE)pji2out + dwSize;
*lpcbSize = dwSize;
CopyMemory( pji2out, lpji2, sizeof(JOB_INFO_2) );
pji2out->pDevMode = NULL; // These two pointers cannot be set
pji2out->pSecurityDescriptor = NULL;
*lpszSrc++ = lpji2->pPrinterName;
*lpszSrc++ = lpji2->pMachineName;
*lpszSrc++ = lpji2->pUserName;
*lpszSrc++ = lpji2->pDocument;
*lpszSrc++ = lpji2->pNotifyName;
*lpszSrc++ = lpji2->pDatatype;
*lpszSrc++ = lpji2->pPrintProcessor;
*lpszSrc++ = lpji2->pParameters;
*lpszSrc++ = lpji2->pDriverName;
*lpszSrc++ = lpji2->pStatus;
ipp_PackStrings(aszSrc, (LPBYTE)pji2out, s_JI2Off, lpbEnd);
}
return pji2out;
}