NT4/private/windows/spooler/localspl/getprn.c
2020-09-30 17:12:29 +02:00

1371 lines
39 KiB
C

/*++
Copyright (c) 1990 - 1995 Microsoft Corporation
Module Name:
getprn.c
Abstract:
This module provides all the public exported APIs relating to Printer
management for the Local Print Providor
SplGetPrinter
LocalEnumPrinters
Author:
Dave Snipp (DaveSn) 15-Mar-1991
Revision History:
--*/
#define NOMINMAX
#include <precomp.h>
#include <offsets.h>
WCHAR *szNull = L"";
WCHAR *szPrintProvidorName = L"Windows NT Local Print Providor";
WCHAR *szPrintProvidorDescription=L"Windows NT Local Printers";
WCHAR *szPrintProvidorComment=L"Locally connected Printers";
#define Nulwcslen(psz) ((psz) ? wcslen(psz)*sizeof(WCHAR)+sizeof(WCHAR) : 0)
#define PRINTER_STATUS_INTERNAL 0
#define PRINTER_STATUS_EXTERNAL 1
DWORD SettablePrinterStatusMappings[] = {
// INTERNAL: EXTERNAL:
PRINTER_OFFLINE, PRINTER_STATUS_OFFLINE,
PRINTER_PAPEROUT, PRINTER_STATUS_PAPER_OUT,
PRINTER_PAPER_JAM, PRINTER_STATUS_PAPER_JAM,
PRINTER_MANUAL_FEED, PRINTER_STATUS_MANUAL_FEED,
PRINTER_PAPER_PROBLEM, PRINTER_STATUS_PAPER_PROBLEM,
PRINTER_IO_ACTIVE, PRINTER_STATUS_IO_ACTIVE,
PRINTER_BUSY, PRINTER_STATUS_BUSY,
PRINTER_PRINTING, PRINTER_STATUS_PRINTING,
PRINTER_OUTPUT_BIN_FULL, PRINTER_STATUS_OUTPUT_BIN_FULL,
PRINTER_NOT_AVAILABLE, PRINTER_STATUS_NOT_AVAILABLE,
PRINTER_WAITING, PRINTER_STATUS_WAITING,
PRINTER_PROCESSING, PRINTER_STATUS_PROCESSING,
PRINTER_INITIALIZING, PRINTER_STATUS_INITIALIZING,
PRINTER_WARMING_UP, PRINTER_STATUS_WARMING_UP,
PRINTER_TONER_LOW, PRINTER_STATUS_TONER_LOW,
PRINTER_NO_TONER, PRINTER_STATUS_NO_TONER,
PRINTER_PAGE_PUNT, PRINTER_STATUS_PAGE_PUNT,
PRINTER_USER_INTERVENTION, PRINTER_STATUS_USER_INTERVENTION,
PRINTER_OUT_OF_MEMORY, PRINTER_STATUS_OUT_OF_MEMORY,
PRINTER_DOOR_OPEN, PRINTER_STATUS_DOOR_OPEN,
PRINTER_SERVER_UNKNOWN, PRINTER_STATUS_SERVER_UNKNOWN,
PRINTER_POWER_SAVE, PRINTER_STATUS_POWER_SAVE,
0, 0
};
DWORD ReadablePrinterStatusMappings[] = {
// INTERNAL: EXTERNAL:
PRINTER_PAUSED, PRINTER_STATUS_PAUSED,
PRINTER_PENDING_DELETION, PRINTER_STATUS_PENDING_DELETION,
PRINTER_OFFLINE, PRINTER_STATUS_OFFLINE,
PRINTER_PAPEROUT, PRINTER_STATUS_PAPER_OUT,
PRINTER_PAPER_JAM, PRINTER_STATUS_PAPER_JAM,
PRINTER_MANUAL_FEED, PRINTER_STATUS_MANUAL_FEED,
PRINTER_PAPER_PROBLEM, PRINTER_STATUS_PAPER_PROBLEM,
PRINTER_IO_ACTIVE, PRINTER_STATUS_IO_ACTIVE,
PRINTER_BUSY, PRINTER_STATUS_BUSY,
PRINTER_PRINTING, PRINTER_STATUS_PRINTING,
PRINTER_OUTPUT_BIN_FULL, PRINTER_STATUS_OUTPUT_BIN_FULL,
PRINTER_NOT_AVAILABLE, PRINTER_STATUS_NOT_AVAILABLE,
PRINTER_WAITING, PRINTER_STATUS_WAITING,
PRINTER_PROCESSING, PRINTER_STATUS_PROCESSING,
PRINTER_INITIALIZING, PRINTER_STATUS_INITIALIZING,
PRINTER_WARMING_UP, PRINTER_STATUS_WARMING_UP,
PRINTER_TONER_LOW, PRINTER_STATUS_TONER_LOW,
PRINTER_NO_TONER, PRINTER_STATUS_NO_TONER,
PRINTER_PAGE_PUNT, PRINTER_STATUS_PAGE_PUNT,
PRINTER_USER_INTERVENTION, PRINTER_STATUS_USER_INTERVENTION,
PRINTER_OUT_OF_MEMORY, PRINTER_STATUS_OUT_OF_MEMORY,
PRINTER_DOOR_OPEN, PRINTER_STATUS_DOOR_OPEN,
PRINTER_SERVER_UNKNOWN, PRINTER_STATUS_SERVER_UNKNOWN,
PRINTER_POWER_SAVE, PRINTER_STATUS_POWER_SAVE,
0, 0
};
DWORD
MapPrinterStatus(
DWORD Type,
DWORD SourceStatus)
{
DWORD TargetStatus;
PDWORD pMappings;
INT MapFrom;
INT MapTo;
if (Type == MAP_READABLE) {
MapFrom = PRINTER_STATUS_INTERNAL;
MapTo = PRINTER_STATUS_EXTERNAL;
pMappings = ReadablePrinterStatusMappings;
} else {
MapFrom = PRINTER_STATUS_EXTERNAL;
MapTo = PRINTER_STATUS_INTERNAL;
pMappings = SettablePrinterStatusMappings;
}
TargetStatus = 0;
while(*pMappings) {
if (SourceStatus & pMappings[MapFrom])
TargetStatus |= pMappings[MapTo];
pMappings += 2;
}
return TargetStatus;
}
DWORD
GetIniNetPrintSize(
PININETPRINT pIniNetPrint
)
{
return sizeof(PRINTER_INFO_1) +
wcslen(pIniNetPrint->pName)*sizeof(WCHAR) + sizeof(WCHAR) +
Nulwcslen(pIniNetPrint->pDescription) +
Nulwcslen(pIniNetPrint->pComment);
}
DWORD
GetPrinterSize(
PINIPRINTER pIniPrinter,
DWORD Level,
DWORD Flags,
BOOL Remote,
LPDEVMODE pDevMode
)
{
DWORD cb;
DWORD cbNeeded;
LPWSTR pszPorts;
switch (Level) {
case STRESSINFOLEVEL:
cb = sizeof(PRINTER_INFO_STRESS) +
wcslen(pIniPrinter->pName)*sizeof(WCHAR) + sizeof(WCHAR);
if( Remote ){
//
// Allocate space for ServerName "\\foobar" and the prefix
// for PrinterName "\\foobar\." The rest of PrinterName
// is allocated above.
//
// ServerName + NULL + ServerName +'\'
//
cb += 2 * wcslen(pIniPrinter->pIniSpooler->pMachineName) * sizeof(WCHAR) +
sizeof(WCHAR) + sizeof(WCHAR);
}
break;
case 4:
cb = sizeof(PRINTER_INFO_4) +
wcslen(pIniPrinter->pName)*sizeof(WCHAR) + sizeof(WCHAR);
if( Remote ){
cb += 2 * wcslen(pIniPrinter->pIniSpooler->pMachineName) * sizeof(WCHAR) +
sizeof(WCHAR) + sizeof(WCHAR);
}
break;
case 1:
//
// Local:
//
// "pName,pDriver,pLocation"
// "pName"
// "pComment"
//
// Remote:
//
// "pMachine\pName,pDriver,<pLocation>"
// "pMachine\pName"
// "pComment"
//
//
// Mandatory items, plus NULLs for _all_ strings.
// 2 * PrinterName +
// DriverName +
// 2 commas, 3 NULL terminators.
//
cb = 2 * wcslen( pIniPrinter->pName ) +
wcslen( pIniPrinter->pIniDriver->pName ) +
2 + 3;
//
// Add items that may be NULL.
//
if( pIniPrinter->pLocation ){
cb += wcslen( pIniPrinter->pLocation );
}
if( pIniPrinter->pComment ){
cb += wcslen( pIniPrinter->pComment );
}
//
// Remote case adds prefix.
// 2 * ( MachineName + BackSlash )
//
if( Remote ){
cb += 2 * ( wcslen( pIniPrinter->pIniSpooler->pMachineName ) + 1 );
}
//
// cb was a char count, convert to byte count.
//
cb *= sizeof( WCHAR );
cb += sizeof( PRINTER_INFO_1 );
break;
case 2:
cbNeeded = 0;
GetPrinterPorts(pIniPrinter, 0, &cbNeeded);
cb = sizeof(PRINTER_INFO_2) +
wcslen(pIniPrinter->pName)*sizeof(WCHAR) + sizeof(WCHAR) +
Nulwcslen(pIniPrinter->pShareName) +
cbNeeded +
wcslen(pIniPrinter->pIniDriver->pName)*sizeof(WCHAR) + sizeof(WCHAR) +
Nulwcslen(pIniPrinter->pComment) +
Nulwcslen(pIniPrinter->pLocation) +
Nulwcslen(pIniPrinter->pSepFile) +
wcslen(pIniPrinter->pIniPrintProc->pName)*sizeof(WCHAR) + sizeof(WCHAR) +
Nulwcslen(pIniPrinter->pDatatype) +
Nulwcslen(pIniPrinter->pParameters);
if( Remote ){
cb += 2 * wcslen(pIniPrinter->pIniSpooler->pMachineName) * sizeof(WCHAR) +
sizeof(WCHAR) + sizeof(WCHAR);
}
if (pDevMode) {
cb += pDevMode->dmSize + pDevMode->dmDriverExtra;
cb = (cb + sizeof(DWORD)-1) & ~(sizeof(DWORD)-1);
}
if (pIniPrinter->pSecurityDescriptor) {
cb += GetSecurityDescriptorLength(pIniPrinter->pSecurityDescriptor);
cb = (cb + sizeof(DWORD)-1) & ~(sizeof(DWORD)-1);
}
break;
case 3:
cb = sizeof(PRINTER_INFO_3);
cb += GetSecurityDescriptorLength(pIniPrinter->pSecurityDescriptor);
cb = (cb + sizeof(DWORD)-1) & ~(sizeof(DWORD)-1);
break;
case 5:
cbNeeded = 0;
GetPrinterPorts(pIniPrinter, 0, &cbNeeded);
cb = sizeof(PRINTER_INFO_5) +
wcslen(pIniPrinter->pName)*sizeof(WCHAR) + sizeof(WCHAR) +
cbNeeded;
//
// Allocate space for just the PrinterName prefix:
// "\\server\."
//
if( Remote ){
cb += wcslen(pIniPrinter->pIniSpooler->pMachineName) * sizeof(WCHAR) +
sizeof(WCHAR);
}
break;
default:
cb = 0;
break;
}
return cb;
}
LPBYTE
CopyIniNetPrintToPrinter(
PININETPRINT pIniNetPrint,
LPBYTE pPrinterInfo,
LPBYTE pEnd
)
{
LPWSTR SourceStrings[sizeof(PRINTER_INFO_1)/sizeof(LPWSTR)];
LPWSTR *pSourceStrings=SourceStrings;
PPRINTER_INFO_1 pPrinterInfo1 = (PPRINTER_INFO_1)pPrinterInfo;
*pSourceStrings++=pIniNetPrint->pDescription;
*pSourceStrings++=pIniNetPrint->pName;
*pSourceStrings++=pIniNetPrint->pComment;
pEnd = PackStrings(SourceStrings, pPrinterInfo, PrinterInfo1Strings, pEnd);
pPrinterInfo1->Flags = PRINTER_ENUM_NAME;
return pEnd;
}
/* CopyIniPrinterSecurityDescriptor
*
* Copies the security descriptor for the printer to the buffer provided
* on a call to GetPrinter. The portions of the security descriptor which
* will be copied are determined by the accesses granted when the printer
* was opened. If it was opened with both READ_CONTROL and ACCESS_SYSTEM_SECURITY,
* all of the security descriptor will be made available. Otherwise a
* partial descriptor is built containing those portions to which the caller
* has access.
*
* Parameters
*
* pIniPrinter - Spooler's private structure for this printer.
*
* Level - Should be 2 or 3. Any other will cause AV.
*
* pPrinterInfo - Pointer to the buffer to receive the PRINTER_INFO_*
* structure. The pSecurityDescriptor field will be filled in with
* a pointer to the security descriptor.
*
* pEnd - Current position in the buffer to receive the data.
* This will be decremented to point to the next free bit of the
* buffer and will be returned.
*
* GrantedAccess - An access mask used to determine how much of the
* security descriptor the caller has access to.
*
* Returns
*
* Updated position in the buffer.
*
* NULL if an error occurred copying the security descriptor.
* It is assumed that no other errors are possible.
*
*/
LPBYTE
CopyIniPrinterSecurityDescriptor(
PINIPRINTER pIniPrinter,
DWORD Level,
LPBYTE pPrinterInfo,
LPBYTE pEnd,
ACCESS_MASK GrantedAccess
)
{
PSECURITY_DESCRIPTOR pPartialSecurityDescriptor = NULL;
DWORD SecurityDescriptorLength = 0;
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
PSECURITY_DESCRIPTOR *ppSecurityDescriptorCopy;
BOOL ErrorOccurred = FALSE;
if(!(AreAllAccessesGranted(GrantedAccess,
READ_CONTROL | ACCESS_SYSTEM_SECURITY)))
{
/* Caller doesn't have full access, so we'll have to build
* a partial descriptor:
*/
if(!BuildPartialSecurityDescriptor(GrantedAccess,
pIniPrinter->pSecurityDescriptor,
&pPartialSecurityDescriptor,
&SecurityDescriptorLength))
ErrorOccurred = TRUE;
else
pSecurityDescriptor = pPartialSecurityDescriptor;
}
else
{
pSecurityDescriptor = pIniPrinter->pSecurityDescriptor;
SecurityDescriptorLength = GetSecurityDescriptorLength(pSecurityDescriptor);
}
if(ErrorOccurred)
return NULL;
pEnd -= SecurityDescriptorLength;
pEnd = (LPBYTE)((DWORD)pEnd & ~3);
switch( Level )
{
case 2:
ppSecurityDescriptorCopy =
&((LPPRINTER_INFO_2)pPrinterInfo)->pSecurityDescriptor;
break;
case 3:
ppSecurityDescriptorCopy =
&((LPPRINTER_INFO_3)pPrinterInfo)->pSecurityDescriptor;
break;
default:
/* This should never happen */
DBGMSG( DBG_ERROR, ("Invalid level %d in CopyIniPrinterSecurityDescriptor\n", Level ));
}
// Copy the descriptor into the buffer that will be returned:
*ppSecurityDescriptorCopy = (PSECURITY_DESCRIPTOR)pEnd;
memcpy(*ppSecurityDescriptorCopy, pSecurityDescriptor,
SecurityDescriptorLength);
if(pPartialSecurityDescriptor)
FreeSplMem(pPartialSecurityDescriptor);
return pEnd;
}
/* CopyIniPrinterToPrinter
*
* Copies the spooler's internal printer data to the caller's buffer,
* depending on the level of information requested.
*
* Parameters
*
* pIniPrinter - A pointer to the spooler's internal data structure
* for the printer concerned.
*
* Level - Level of information requested (1, 2 or 3). Any level
* other than those supported will cause the routine to return
* immediately.
*
* pPrinterInfo - Pointer to the buffer to receive the PRINTER_INFO_*
* structure.
*
* pEnd - Current position in the buffer to receive the data.
* This will be decremented to point to the next free bit of the
* buffer and will be returned.
*
* pSecondPrinter - If the printer has a port which is being controlled
* by a monitor, this parameter points to information retrieved
* about a network printer. This allows us, e.g., to return
* the number of jobs on the printer that the output of the
* printer is currently being directed to.
*
* Remote - Indicates whether the caller is remote. If so we have to
* include the machine name in the printer name returned.
*
* CopySecurityDescriptor - Indicates whether the security descriptor
* should be copied. The security descriptor should not be copied
* on EnumPrinters calls, because this API requires
* SERVER_ACCESS_ENUMERATE access, and we'd have to do an access
* check on every printer enumerated to determine how much of the
* security descriptor could be copied. This would be costly,
* and the caller would probably not need the information anyway.
*
* GrantedAccess - An access mask used to determine how much of the
* security descriptor the caller has access to.
*
*
* Returns
*
* A pointer to the point in the buffer reached after the requested
* data has been copied.
*
* If there was an error, the return value is NULL.
*
*
* Assumes
*
* The largest PRINTER_INFO_* structure is PRINTER_INFO_2.
*
*/
LPBYTE
CopyIniPrinterToPrinter(
PINIPRINTER pIniPrinter,
DWORD Level,
LPBYTE pPrinterInfo,
LPBYTE pEnd,
LPBYTE pSecondPrinter,
BOOL Remote,
BOOL CopySecurityDescriptor,
ACCESS_MASK GrantedAccess,
PDEVMODE pDevMode
)
{
LPWSTR SourceStrings[sizeof(PRINTER_INFO_2)/sizeof(LPWSTR)];
LPWSTR *pSourceStrings=SourceStrings;
//
// Max string: "\\Computer\Printer,Driver,Location"
//
WCHAR string[ MAX_PRINTER_BROWSE_NAME ];
WCHAR printerString[ MAX_UNC_PRINTER_NAME ];
LPWSTR pszPorts;
PPRINTER_INFO_3 pPrinter3 = (PPRINTER_INFO_3)pPrinterInfo;
PPRINTER_INFO_2 pPrinter2 = (PPRINTER_INFO_2)pPrinterInfo;
PPRINTER_INFO_2 pSecondPrinter2 = (PPRINTER_INFO_2)pSecondPrinter;
PPRINTER_INFO_1 pPrinter1 = (PPRINTER_INFO_1)pPrinterInfo;
PPRINTER_INFO_4 pPrinter4 = (PPRINTER_INFO_4)pPrinterInfo;
PPRINTER_INFO_5 pPrinter5 = (PPRINTER_INFO_5)pPrinterInfo;
PPRINTER_INFO_STRESS pPrinter0 = (PPRINTER_INFO_STRESS)pPrinterInfo;
PSECURITY_DESCRIPTOR pPartialSecurityDescriptor = NULL;
DWORD *pOffsets;
SYSTEM_INFO si;
DWORD cbNeeded;
switch (Level) {
case STRESSINFOLEVEL:
pOffsets = PrinterInfoStressStrings;
break;
case 4:
pOffsets = PrinterInfo4Strings;
break;
case 1:
pOffsets = PrinterInfo1Strings;
break;
case 2:
pOffsets = PrinterInfo2Strings;
break;
case 3:
pOffsets = PrinterInfo3Strings;
break;
case 5:
pOffsets = PrinterInfo5Strings;
break;
default:
return pEnd;
}
switch (Level) {
case STRESSINFOLEVEL:
if (Remote) {
wsprintf(string, L"%ws\\%ws", pIniPrinter->pIniSpooler->pMachineName, pIniPrinter->pName);
*pSourceStrings++=string;
*pSourceStrings++= pIniPrinter->pIniSpooler->pMachineName;
} else {
*pSourceStrings++=pIniPrinter->pName;
*pSourceStrings++=NULL;
}
pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter0, pOffsets, pEnd);
pPrinter0->cJobs = pIniPrinter->cJobs;
pPrinter0->cTotalJobs = pIniPrinter->cTotalJobs;
pPrinter0->cTotalBytes = pIniPrinter->cTotalBytes.LowPart;
pPrinter0->dwHighPartTotalBytes = pIniPrinter->cTotalBytes.HighPart;
pPrinter0->stUpTime = pIniPrinter->stUpTime;
pPrinter0->MaxcRef = pIniPrinter->MaxcRef;
pPrinter0->cTotalPagesPrinted = pIniPrinter->cTotalPagesPrinted;
pPrinter0->dwGetVersion = GetVersion();
#if DBG
pPrinter0->fFreeBuild = FALSE;
#else
pPrinter0->fFreeBuild = TRUE;
#endif
GetSystemInfo(&si);
pPrinter0->dwProcessorType = si.dwProcessorType;
pPrinter0->dwNumberOfProcessors = si.dwNumberOfProcessors;
pPrinter0->cSpooling = pIniPrinter->cSpooling;
pPrinter0->cMaxSpooling = pIniPrinter->cMaxSpooling;
pPrinter0->cRef = pIniPrinter->cRef;
pPrinter0->cErrorOutOfPaper = pIniPrinter->cErrorOutOfPaper;
pPrinter0->cErrorNotReady = pIniPrinter->cErrorNotReady;
pPrinter0->cJobError = pIniPrinter->cJobError;
pPrinter0->cChangeID = pIniPrinter->cChangeID;
pPrinter0->dwLastError = pIniPrinter->dwLastError;
pPrinter0->Status = MapPrinterStatus(MAP_READABLE,
pIniPrinter->Status) |
pIniPrinter->PortStatus;
pPrinter0->cEnumerateNetworkPrinters = pIniPrinter->pIniSpooler->cEnumerateNetworkPrinters;
pPrinter0->cAddNetPrinters = pIniPrinter->pIniSpooler->cAddNetPrinters;
pPrinter0->wProcessorArchitecture = si.wProcessorArchitecture;
pPrinter0->wProcessorLevel = si.wProcessorLevel;
break;
case 4:
if (Remote) {
wsprintf(string, L"%ws\\%ws", pIniPrinter->pIniSpooler->pMachineName, pIniPrinter->pName);
*pSourceStrings++=string;
*pSourceStrings++= pIniPrinter->pIniSpooler->pMachineName;
} else {
*pSourceStrings++=pIniPrinter->pName;
*pSourceStrings++=NULL;
}
pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter4, pOffsets, pEnd);
//
// Add additional info later
//
pPrinter4->Attributes = pIniPrinter->Attributes | PRINTER_ATTRIBUTE_LOCAL;
break;
case 1:
if (Remote) {
wsprintf(string, L"%ws\\%ws,%ws,%ws", pIniPrinter->pIniSpooler->pMachineName,
pIniPrinter->pName,
pIniPrinter->pIniDriver->pName,
pIniPrinter->pLocation ?
pIniPrinter->pLocation :
szNull);
wsprintf(printerString, L"%ws\\%ws", pIniPrinter->pIniSpooler->pMachineName,
pIniPrinter->pName);
} else {
wsprintf(string, L"%ws,%ws,%ws", pIniPrinter->pName,
pIniPrinter->pIniDriver->pName,
pIniPrinter->pLocation ?
pIniPrinter->pLocation :
szNull);
wcscpy(printerString, pIniPrinter->pName);
}
*pSourceStrings++=string;
*pSourceStrings++=printerString;
*pSourceStrings++=pIniPrinter->pComment;
pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter1, pOffsets, pEnd);
pPrinter1->Flags = PRINTER_ENUM_ICON8;
break;
case 2:
if (Remote) {
*pSourceStrings++= pIniPrinter->pIniSpooler->pMachineName;
wsprintf(string, L"%ws\\%ws", pIniPrinter->pIniSpooler->pMachineName, pIniPrinter->pName);
*pSourceStrings++=string;
} else {
*pSourceStrings++=NULL;
*pSourceStrings++=pIniPrinter->pName;
}
*pSourceStrings++=pIniPrinter->pShareName;
cbNeeded = 0;
GetPrinterPorts(pIniPrinter, 0, &cbNeeded);
if (pszPorts = AllocSplMem(cbNeeded)) {
GetPrinterPorts(pIniPrinter, pszPorts, &cbNeeded);
*pSourceStrings++=pszPorts;
*pSourceStrings++=pIniPrinter->pIniDriver->pName;
*pSourceStrings++=pIniPrinter->pComment;
*pSourceStrings++=pIniPrinter->pLocation;
*pSourceStrings++=pIniPrinter->pSepFile;
*pSourceStrings++=pIniPrinter->pIniPrintProc->pName;
*pSourceStrings++=pIniPrinter->pDatatype;
*pSourceStrings++=pIniPrinter->pParameters;
pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter2, pOffsets, pEnd);
FreeSplMem(pszPorts);
}
else {
pEnd = NULL;
break;
}
if (pDevMode) {
pEnd -= pDevMode->dmSize + pDevMode->dmDriverExtra;
pEnd = (LPBYTE)((DWORD)pEnd & ~3);
pPrinter2->pDevMode=(LPDEVMODE)pEnd;
memcpy(pPrinter2->pDevMode, pDevMode, pDevMode->dmSize + pDevMode->dmDriverExtra);
//
// In the remote case, append the name of the server
// in the devmode.dmDeviceName. This allows dmDeviceName
// to always match win.ini's [devices] section.
//
FixDevModeDeviceName(Remote ?
string :
pIniPrinter->pName,
pPrinter2->pDevMode,
pIniPrinter->cbDevMode);
} else {
pPrinter2->pDevMode=NULL;
}
pPrinter2->Attributes = pIniPrinter->Attributes | PRINTER_ATTRIBUTE_LOCAL;
pPrinter2->Priority = pIniPrinter->Priority;
pPrinter2->DefaultPriority = pIniPrinter->DefaultPriority;
pPrinter2->StartTime = pIniPrinter->StartTime;
pPrinter2->UntilTime = pIniPrinter->UntilTime;
if (pSecondPrinter2) {
pPrinter2->cJobs = pSecondPrinter2->cJobs;
pPrinter2->Status = pSecondPrinter2->Status;
} else {
pPrinter2->cJobs=pIniPrinter->cJobs;
pPrinter2->Status = MapPrinterStatus(MAP_READABLE,
pIniPrinter->Status) |
pIniPrinter->PortStatus;
}
pPrinter2->AveragePPM=pIniPrinter->AveragePPM;
if( CopySecurityDescriptor ) {
pEnd = CopyIniPrinterSecurityDescriptor(pIniPrinter,
Level,
pPrinterInfo,
pEnd,
GrantedAccess);
} else {
pPrinter2->pSecurityDescriptor = NULL;
}
break;
case 3:
pEnd = CopyIniPrinterSecurityDescriptor(pIniPrinter,
Level,
pPrinterInfo,
pEnd,
GrantedAccess);
break;
case 5:
if (Remote) {
wsprintf(string, L"%ws\\%ws", pIniPrinter->pIniSpooler->pMachineName, pIniPrinter->pName);
*pSourceStrings++=string;
} else {
*pSourceStrings++=pIniPrinter->pName;
}
cbNeeded = 0;
GetPrinterPorts(pIniPrinter, 0, &cbNeeded);
if (pszPorts = AllocSplMem(cbNeeded)) {
GetPrinterPorts(pIniPrinter, pszPorts, &cbNeeded);
*pSourceStrings++ = pszPorts;
pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter5, pOffsets, pEnd);
pPrinter5->Attributes = pIniPrinter->Attributes |
PRINTER_ATTRIBUTE_LOCAL;
pPrinter5->DeviceNotSelectedTimeout = pIniPrinter->dnsTimeout;
pPrinter5->TransmissionRetryTimeout = pIniPrinter->txTimeout;
FreeSplMem(pszPorts);
}
else
pEnd = NULL;
break;
default:
return pEnd;
}
return pEnd;
}
BOOL
SplGetPrinter(
HANDLE hPrinter,
DWORD Level,
LPBYTE pPrinter,
DWORD cbBuf,
LPDWORD pcbNeeded
)
{
PSPOOL pSpool = (PSPOOL)hPrinter;
BOOL AccessIsGranted = FALSE; // Must intialize
LPBYTE pSecondPrinter=NULL;
DWORD cb, cbNeeded;
LPBYTE pEnd;
BOOL remote;
BOOL bReturn = FALSE;
PDEVMODE pDevMode = NULL;
PINIPRINTER pIniPrinter;
BOOL bNt3xClient;
EnterSplSem();
if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )) {
goto Cleanup;
}
pIniPrinter = pSpool->pIniPrinter;
bNt3xClient = (pSpool->TypeofHandle & PRINTER_HANDLE_3XCLIENT);
//
// If Nt3x client we will converted devmode. If driver can't convert we will not return devmode
//
if ( bNt3xClient && Level == 2 && pIniPrinter->pDevMode ) {
//
// Call driver to get a Nt3x DevMode (if fails no devmode is given)
//
pDevMode = ConvertDevModeToSpecifiedVersion(pIniPrinter,
pIniPrinter->pDevMode,
NULL,
NULL,
NT3X_VERSION);
}
SplInSem();
if (( pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE ) ||
( pSpool->pIniSpooler != pLocalIniSpooler )) {
remote = TRUE;
} else {
remote = FALSE;
}
switch (Level) {
case STRESSINFOLEVEL:
case 1:
case 2:
case 4:
case 5:
if ( !AccessGranted(SPOOLER_OBJECT_PRINTER,
PRINTER_ACCESS_USE,
pSpool) ) {
SetLastError(ERROR_ACCESS_DENIED);
goto Cleanup;
}
break;
case 3:
if (!AreAnyAccessesGranted(pSpool->GrantedAccess,
READ_CONTROL | ACCESS_SYSTEM_SECURITY)) {
SetLastError(ERROR_ACCESS_DENIED);
goto Cleanup;
}
break;
}
if (pSpool->pIniPort && !(pSpool->pIniPort->Status & PP_MONITOR)) {
HANDLE hPort = pSpool->hPort;
if (hPort == INVALID_PORT_HANDLE) {
DBGMSG(DBG_WARNING, ("GetPrinter called with bad port handle. Setting error %d\n",
pSpool->OpenPortError));
//
// If this value is 0, then when we return GetLastError,
// the client will think we succeeded.
//
SPLASSERT(pSpool->OpenPortError);
goto PartialSuccess;
}
cb = 4096;
pSecondPrinter = AllocSplMem(cb);
LeaveSplSem();
if (!GetPrinter(hPort, Level, pSecondPrinter, cb, &cbNeeded)) {
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
pSecondPrinter = ReallocSplMem(pSecondPrinter, 0, cbNeeded);
cb = cbNeeded;
if (!GetPrinter(hPort, Level, pSecondPrinter, cb, &cbNeeded)) {
goto CleanupFromOutsideSplSem;
}
} else {
goto CleanupFromOutsideSplSem;
}
}
EnterSplSem();
/* Re-validate the handle, since it might possibly have been closed
* while we were outside the semaphore:
*/
if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )) {
goto Cleanup;
}
}
PartialSuccess:
*pcbNeeded = GetPrinterSize(pIniPrinter, Level, 0, remote,
bNt3xClient ? pDevMode : pIniPrinter->pDevMode);
if (*pcbNeeded > cbBuf) {
DBGMSG(DBG_TRACE, ("SplGetPrinter Failure with ERROR_INSUFFICIENT_BUFFER cbBuf is %d and pcbNeeded is %d\n", cbBuf, *pcbNeeded));
SetLastError(ERROR_INSUFFICIENT_BUFFER);
goto Cleanup;
}
pEnd = CopyIniPrinterToPrinter(pIniPrinter, Level, pPrinter,
pPrinter+cbBuf, pSecondPrinter,
remote,
TRUE, pSpool->GrantedAccess,
bNt3xClient ? pDevMode : pIniPrinter->pDevMode);
if ( pEnd != NULL)
bReturn = TRUE;
Cleanup:
LeaveSplSem();
CleanupFromOutsideSplSem:
SplOutSem();
FreeSplMem(pSecondPrinter);
FreeSplMem(pDevMode);
if ( bReturn == FALSE ) {
SPLASSERT(GetLastError() != ERROR_SUCCESS);
}
return bReturn;
}
BOOL
EnumerateNetworkPrinters(
LPBYTE pPrinter,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned,
PINISPOOLER pIniSpooler
)
{
PININETPRINT pIniNetPrint;
DWORD cb;
LPBYTE pEnd;
BOOL bReturnValue = FALSE;
EnterSplSem();
RemoveOldNetPrinters( NULL );
//
// If the Server has not been up long enough, then fail
// so the client will ask another Server for the Browse List.
//
if ( bNetInfoReady == FALSE ) {
SetLastError( ERROR_CAN_NOT_COMPLETE );
goto Done;
}
cb = 0;
pIniNetPrint = pIniSpooler->pIniNetPrint;
while (pIniNetPrint) {
cb += GetIniNetPrintSize( pIniNetPrint );
pIniNetPrint = pIniNetPrint->pNext;
}
*pcbNeeded = cb;
if (cb > cbBuf) {
SetLastError( ERROR_INSUFFICIENT_BUFFER );
goto Done;
}
pIniNetPrint = pIniSpooler->pIniNetPrint;
pEnd = pPrinter + cbBuf;
while ( pIniNetPrint ) {
pEnd = CopyIniNetPrintToPrinter( pIniNetPrint, pPrinter, pEnd );
(*pcReturned)++;
pPrinter += sizeof(PRINTER_INFO_1);
pIniNetPrint = pIniNetPrint->pNext;
}
if ( *pcReturned == 0 ) {
bNetInfoReady = FALSE;
FirstAddNetPrinterTickCount = 0;
SetLastError( ERROR_CAN_NOT_COMPLETE );
DBGMSG( DBG_TRACE, ("EnumerateNetworkPrinters returning ERROR_CAN_NOT_COMPELTE becase there is no browse list\n"));
} else {
pIniSpooler->cEnumerateNetworkPrinters++; // Stats only
bReturnValue = TRUE;
DBGMSG( DBG_TRACE, (" EnumerateNetworkPrnters called %d times returning %d printers\n", pIniSpooler->cEnumerateNetworkPrinters, *pcReturned ));
}
Done:
LeaveSplSem();
SplOutSem();
return bReturnValue;
}
/*
EnumPrinters can be called with the following combinations:
Flags Name Meaning
PRINTER_ENUM_LOCAL NULL Enumerate all Printers on this machine
PRINTER_ENUM_NAME MachineName Enumerate all Printers on this machine
PRINTER_ENUM_NAME | MachineName Enumerate all shared Printers on this
PRINTER_ENUM_SHARED MachineName machine
PRINTER_ENUM_NETWORK MachineName Enumerate all added remote printers
PRINTER_ENUM_REMOTE ? Return error - let win32spl handle it
PRINTER_ENUM_NAME NULL Give back Print Providor name
PRINTER_ENUM_NAME "Windows NT Local Print Providor"
same as PRINTER_ENUM_LOCAL
It is not an error if no known flag is specified.
In this case we just return TRUE without any data
(This is so that other print providers may define
their own flags.)
*/
BOOL
LocalEnumPrinters(
DWORD Flags,
LPWSTR Name,
DWORD Level,
LPBYTE pPrinter,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
)
{
return ( SplEnumPrinters( Flags,
Name,
Level,
pPrinter,
cbBuf,
pcbNeeded,
pcReturned,
pLocalIniSpooler ) );
}
BOOL
SplEnumPrinters(
DWORD Flags,
LPWSTR Name,
DWORD Level,
LPBYTE pPrinter,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned,
PINISPOOLER pIniSpooler
)
{
PINIPRINTER pIniPrinter;
PPRINTER_INFO_1 pPrinter1=(PPRINTER_INFO_1)pPrinter;
DWORD cb;
LPBYTE pEnd;
BOOL Remote;
SplOutSem();
*pcbNeeded = 0;
*pcReturned = 0;
if ( Flags & PRINTER_ENUM_NAME ) {
if ( Name && *Name ) {
if (lstrcmpi(Name, szPrintProvidorName) && !MyName( Name, pIniSpooler)) {
return FALSE;
}
// If it's PRINTER_ENUM_NAME of our name,
// do the same as PRINTER_ENUM_LOCAL:
Flags |= PRINTER_ENUM_LOCAL;
// Also if it is for us then ignore the REMOTE flag.
// Otherwise the call will get passed to Win32Spl which
// will end up calling us back forever.
Flags &= ~PRINTER_ENUM_REMOTE;
}
}
if ( Flags & PRINTER_ENUM_REMOTE ) {
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
Remote = FALSE;
if ( Name && *Name ) {
if ( MyName( Name, pIniSpooler ) ) {
Remote = TRUE;
}
}
if ((Level == 1) && (Flags & PRINTER_ENUM_NETWORK))
return EnumerateNetworkPrinters( pPrinter, cbBuf, pcbNeeded, pcReturned, pIniSpooler );
EnterSplSem();
if ((Level == 1 ) && (Flags & PRINTER_ENUM_NAME) && !Name) {
LPWSTR SourceStrings[sizeof(PRINTER_INFO_1)/sizeof(LPWSTR)];
LPWSTR *pSourceStrings=SourceStrings;
cb = wcslen(szPrintProvidorName)*sizeof(WCHAR) + sizeof(WCHAR) +
wcslen(szPrintProvidorDescription)*sizeof(WCHAR) + sizeof(WCHAR) +
wcslen(szPrintProvidorComment)*sizeof(WCHAR) + sizeof(WCHAR) +
sizeof(PRINTER_INFO_1);
*pcbNeeded=cb;
if (cb > cbBuf) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
LeaveSplSem();
SplOutSem();
return FALSE;
}
*pcReturned = 1;
pPrinter1->Flags = PRINTER_ENUM_CONTAINER | PRINTER_ENUM_ICON1;
*pSourceStrings++=szPrintProvidorDescription;
*pSourceStrings++=szPrintProvidorName;
*pSourceStrings++=szPrintProvidorComment;
PackStrings(SourceStrings, pPrinter, PrinterInfo1Strings,
pPrinter+cbBuf);
LeaveSplSem();
SplOutSem();
return TRUE;
}
cb=0;
if (Flags & (PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME)) {
//
// Calculate the size required
//
for ( pIniPrinter = pIniSpooler->pIniPrinter;
pIniPrinter != NULL;
pIniPrinter = pIniPrinter->pNext ) {
//
// If they only want shared Printers
//
if ( ( Flags & PRINTER_ENUM_SHARED ) &&
!( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED )) {
continue;
}
//
// Only allow them to see printers which are being deleted if they have jobs
// This allows remote admin to work well.
if ( ( pIniPrinter->Status & PRINTER_PENDING_DELETION ) &&
( pIniPrinter->cJobs == 0 ) ) {
continue;
}
//
// Don't count printers which are partially created
//
if ( pIniPrinter->Status & PRINTER_PENDING_CREATION ) {
continue;
}
cb += GetPrinterSize(pIniPrinter, Level, Flags, Remote, pIniPrinter->pDevMode);
}
}
*pcbNeeded=cb;
if (cb > cbBuf) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
LeaveSplSem();
SplOutSem();
return FALSE;
}
if (Flags & (PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME)) {
for ( pIniPrinter = pIniSpooler->pIniPrinter, pEnd = pPrinter + cbBuf;
pIniPrinter != NULL;
pIniPrinter = pIniPrinter->pNext ) {
//
// If they only want shared Printers
//
if ( ( Flags & PRINTER_ENUM_SHARED ) &&
!( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED )) {
continue;
}
//
// Only allow them to see printers which are being deleted if they have jobs
// This allows remote admin to work well.
if ( ( pIniPrinter->Status & PRINTER_PENDING_DELETION ) &&
( pIniPrinter->cJobs == 0 ) ) {
continue;
}
//
// Don't count printers which are partially created
//
if ( pIniPrinter->Status & PRINTER_PENDING_CREATION ) {
continue;
}
pEnd = CopyIniPrinterToPrinter( pIniPrinter, Level, pPrinter,
pEnd, NULL, Remote, FALSE, 0,
pIniPrinter->pDevMode );
(*pcReturned)++;
switch (Level) {
case STRESSINFOLEVEL:
pPrinter+=sizeof(PRINTER_INFO_STRESS);
break;
case 1:
pPrinter+=sizeof(PRINTER_INFO_1);
break;
case 2:
pPrinter+=sizeof(PRINTER_INFO_2);
break;
case 4:
pPrinter+=sizeof(PRINTER_INFO_4);
break;
case 5:
pPrinter+=sizeof(PRINTER_INFO_5);
break;
}
}
}
LeaveSplSem();
SplOutSem();
return TRUE;
}