|
|
/*****************************************************************************\
* 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. * * NOTE: Make sure that cbData is never greater than size of lplpPtr in bytes. * \*****************************************************************************/ 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) {
// 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; }
/*******************************************************************************
** 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
{ 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; }
/*****************************************************************************\
* 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; }
// 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.
if (IS_TAG_COMPOUND(bTag)) {
if (ipp_ReadWord(lpTag, 0)) {
lpTag += IPP_SIZEOFLEN; lpTag += ipp_ReadWord(lpTag, 0); lpTag += IPP_SIZEOFLEN; } }
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)) StringCbPrintf(lpszJobUri, webStrSize(lpszJobBase)+80, 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; }
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; }
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; }
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; }
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;
//
// 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; }
|