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