2409 lines
59 KiB
C
2409 lines
59 KiB
C
/*++
|
||
|
||
Copyright (c) 1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
spool.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the Netware print provider.
|
||
|
||
Author:
|
||
|
||
Yi-Hsin Sung (yihsins) 15-May-1993
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <nw.h>
|
||
#include <nwreg.h>
|
||
#include <nwpkstr.h>
|
||
#include <splutil.h>
|
||
#include <queue.h>
|
||
#include <nwmisc.h>
|
||
|
||
//------------------------------------------------------------------
|
||
//
|
||
// Local Definitions
|
||
//
|
||
//------------------------------------------------------------------
|
||
|
||
#define NW_SIGNATURE 0x574E /* "NW" is the signature */
|
||
|
||
#define SPOOL_STATUS_STARTDOC 0x00000001
|
||
#define SPOOL_STATUS_ADDJOB 0x00000002
|
||
#define SPOOL_STATUS_ABORT 0x00000003
|
||
|
||
#define PRINTER_CHANGE_VALID 0x55770F07
|
||
#define PRINTER_CHANGE_DEFAULT_TIMEOUT_VALUE 10000
|
||
#define PRINTER_CHANGE_MINIMUM_TIMEOUT_VALUE 1000
|
||
#define REG_TIMEOUT_PATH L"System\\CurrentControlSet\\Services\\NWCWorkstation\\Parameters"
|
||
#define REG_TIMEOUT_VALUE_NAME L"PrintNotifyTimeout"
|
||
|
||
#define NDS_MAX_NAME_CHARS 256
|
||
#define NDS_MAX_NAME_SIZE ( NDS_MAX_NAME_CHARS * 2 )
|
||
|
||
//
|
||
// Printer structure
|
||
//
|
||
typedef struct _NWPRINTER {
|
||
LPWSTR pszServer; // Server Name
|
||
LPWSTR pszQueue; // Queue Name
|
||
LPWSTR pszUncConnection; // UNC Connection Name
|
||
// (only present if NDS print queue
|
||
DWORD nQueueId; // Queue Id
|
||
struct _NWPRINTER *pNextPrinter; // Points to the next printer
|
||
struct _NWSPOOL *pSpoolList; // Points to the list of open handles
|
||
} NWPRINTER, *PNWPRINTER;
|
||
|
||
//
|
||
// Handle structure
|
||
//
|
||
typedef struct _NWSPOOL {
|
||
DWORD nSignature; // Signature
|
||
DWORD errOpenPrinter; // OpenPrinter API will always return
|
||
// success on known printers. This will
|
||
// contain the error that we get
|
||
// if something went wrong in the API.
|
||
PNWPRINTER pPrinter; // Points to the corresponding printer
|
||
HANDLE hServer; // Opened handle to the server
|
||
struct _NWSPOOL *pNextSpool; // Points to the next handle
|
||
DWORD nStatus; // Status
|
||
DWORD nJobNumber; // StartDocPrinter/AddJob: Job Number
|
||
HANDLE hChangeEvent; // WaitForPrinterChange: event to wait on
|
||
DWORD nWaitFlags; // WaitForPrinterChange: flags to wait on
|
||
DWORD nChangeFlags; // Changes that occurred to the printer
|
||
} NWSPOOL, *PNWSPOOL;
|
||
|
||
//------------------------------------------------------------------
|
||
//
|
||
// Global Variables
|
||
//
|
||
//------------------------------------------------------------------
|
||
|
||
|
||
// Stores the timeout value used in WaitForPrinterChange ( in milliseconds )
|
||
STATIC DWORD NwTimeOutValue = PRINTER_CHANGE_DEFAULT_TIMEOUT_VALUE;
|
||
|
||
// Points to the link list of printers
|
||
STATIC PNWPRINTER NwPrinterList = NULL;
|
||
|
||
//------------------------------------------------------------------
|
||
//
|
||
// Local Function Prototypes
|
||
//
|
||
//------------------------------------------------------------------
|
||
|
||
VOID
|
||
NwSetPrinterChange(
|
||
IN PNWSPOOL pSpool,
|
||
IN DWORD nFlags
|
||
);
|
||
|
||
PNWPRINTER
|
||
NwFindPrinterEntry(
|
||
IN LPWSTR pszServer,
|
||
IN LPWSTR pszQueue
|
||
);
|
||
|
||
DWORD
|
||
NwCreatePrinterEntry(
|
||
IN LPWSTR pszServer,
|
||
IN LPWSTR pszQueue,
|
||
OUT PNWPRINTER *ppPrinter,
|
||
OUT PHANDLE phServer
|
||
);
|
||
|
||
VOID
|
||
NwRemovePrinterEntry(
|
||
IN PNWPRINTER pPrinter
|
||
);
|
||
|
||
LPWSTR
|
||
NwGetUncObjectName(
|
||
IN LPWSTR ContainerName
|
||
);
|
||
|
||
|
||
|
||
VOID
|
||
NwInitializePrintProvider(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the server side print provider when
|
||
the workstation service starts up.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
DWORD err;
|
||
HKEY hkey;
|
||
DWORD dwTemp;
|
||
DWORD dwSize = sizeof( dwTemp );
|
||
|
||
//
|
||
// Read the time out value from the registry.
|
||
// We will ignore all errors since we can always have a default time out.
|
||
// The default will be used if the key does not exist.
|
||
//
|
||
err = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
|
||
REG_TIMEOUT_PATH,
|
||
0,
|
||
KEY_READ,
|
||
&hkey );
|
||
|
||
if ( !err )
|
||
{
|
||
err = RegQueryValueExW( hkey,
|
||
REG_TIMEOUT_VALUE_NAME,
|
||
NULL,
|
||
NULL,
|
||
(LPBYTE) &dwTemp,
|
||
&dwSize );
|
||
|
||
if ( !err )
|
||
{
|
||
NwTimeOutValue = dwTemp;
|
||
|
||
//
|
||
// tommye - bug 139469 - removed
|
||
// if (NwTimeOutValue >= 0) because NwtimeOutValue is a DWORD
|
||
//
|
||
// Use the minimum timeout value if the
|
||
// value set in the registry is too small.
|
||
//
|
||
|
||
if (NwTimeOutValue <= PRINTER_CHANGE_MINIMUM_TIMEOUT_VALUE)
|
||
{
|
||
NwTimeOutValue = PRINTER_CHANGE_MINIMUM_TIMEOUT_VALUE;
|
||
}
|
||
}
|
||
|
||
RegCloseKey( hkey );
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
NwTerminatePrintProvider(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine cleans up the server side print provider when
|
||
the workstation service shut downs.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
PNWPRINTER pPrinter, pNext;
|
||
PNWSPOOL pSpool, pNextSpool;
|
||
|
||
for ( pPrinter = NwPrinterList; pPrinter; pPrinter = pNext )
|
||
{
|
||
pNext = pPrinter->pNextPrinter;
|
||
|
||
pPrinter->pNextPrinter = NULL;
|
||
|
||
for ( pSpool = pPrinter->pSpoolList; pSpool; pSpool = pNextSpool )
|
||
{
|
||
pNextSpool = pSpool->pNextSpool;
|
||
if ( pSpool->hChangeEvent )
|
||
CloseHandle( pSpool->hChangeEvent );
|
||
(VOID) NtClose( pSpool->hServer );
|
||
|
||
//
|
||
// Free all memory associated with the context handle
|
||
//
|
||
FreeNwSplMem( pSpool, sizeof( NWSPOOL) );
|
||
}
|
||
|
||
pPrinter->pSpoolList = NULL;
|
||
FreeNwSplStr( pPrinter->pszServer );
|
||
FreeNwSplStr( pPrinter->pszQueue );
|
||
if ( pPrinter->pszUncConnection )
|
||
{
|
||
(void) NwrDeleteConnection( NULL,
|
||
pPrinter->pszUncConnection,
|
||
FALSE );
|
||
FreeNwSplStr( pPrinter->pszUncConnection );
|
||
}
|
||
FreeNwSplMem( pPrinter, sizeof( NWPRINTER));
|
||
}
|
||
|
||
NwPrinterList = NULL;
|
||
NwTimeOutValue = PRINTER_CHANGE_DEFAULT_TIMEOUT_VALUE;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwrOpenPrinter(
|
||
IN LPWSTR Reserved,
|
||
IN LPWSTR pszPrinterName,
|
||
IN DWORD fKnownPrinter,
|
||
OUT LPNWWKSTA_PRINTER_CONTEXT phPrinter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine retrieves a handle identifying the specified printer.
|
||
|
||
Arguments:
|
||
|
||
Reserved - Unused
|
||
pszPrinterName - Name of the printer
|
||
fKnownPrinter - TRUE if we have successfully opened the printer before,
|
||
FALSE otherwise.
|
||
phPrinter - Receives the handle that identifies the given printer
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
DWORD err;
|
||
PNWSPOOL pSpool = NULL;
|
||
LPWSTR pszServer = NULL;
|
||
LPWSTR pszQueue = NULL;
|
||
PNWPRINTER pPrinter = NULL;
|
||
BOOL fImpersonate = FALSE ;
|
||
HANDLE hServer;
|
||
BOOL isPrinterNameValid;
|
||
|
||
UNREFERENCED_PARAMETER( Reserved );
|
||
|
||
if ( pszPrinterName[0] == L' ' &&
|
||
pszPrinterName[1] == L'\\' &&
|
||
pszPrinterName[2] == L'\\' )
|
||
{
|
||
if ( (pszServer = AllocNwSplStr( pszPrinterName + 1 )) == NULL )
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
isPrinterNameValid = ValidateUNCName( pszPrinterName + 1 );
|
||
}
|
||
else
|
||
{
|
||
if ( (pszServer = AllocNwSplStr( pszPrinterName )) == NULL )
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
isPrinterNameValid = ValidateUNCName( pszPrinterName );
|
||
}
|
||
|
||
CharUpperW( pszServer ); // convert in place
|
||
|
||
//
|
||
// ValidatePrinterName
|
||
//
|
||
if ( ( !isPrinterNameValid )
|
||
|| ( (pszQueue = wcschr( pszServer + 2, L'\\')) == NULL )
|
||
|| ( pszQueue == (pszServer + 2) )
|
||
|| ( *(pszQueue + 1) == L'\0' )
|
||
)
|
||
{
|
||
FreeNwSplStr( pszServer );
|
||
return ERROR_INVALID_NAME;
|
||
}
|
||
|
||
*pszQueue = L'\0'; // put a '\0' in place of '\\'
|
||
pszQueue++; // Get past the '\0'
|
||
|
||
if ( !(pSpool = AllocNwSplMem( LMEM_ZEROINIT, sizeof( NWSPOOL))))
|
||
{
|
||
err = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto ErrorExit;
|
||
}
|
||
|
||
//
|
||
// Impersonate the client
|
||
//
|
||
if ((err = NwImpersonateClient()) != NO_ERROR)
|
||
{
|
||
goto ErrorExit;
|
||
}
|
||
fImpersonate = TRUE ;
|
||
|
||
EnterCriticalSection( &NwPrintCritSec );
|
||
|
||
if ((err = NwCreatePrinterEntry( pszServer, pszQueue, &pPrinter, &hServer)))
|
||
{
|
||
if ( !fKnownPrinter )
|
||
{
|
||
LeaveCriticalSection( &NwPrintCritSec );
|
||
goto ErrorExit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Construct the print queue context handle to give back to the caller
|
||
//
|
||
pSpool->nSignature = NW_SIGNATURE;
|
||
pSpool->errOpenPrinter = err;
|
||
|
||
pSpool->hServer = hServer;
|
||
pSpool->nStatus = 0;
|
||
pSpool->nJobNumber = 0;
|
||
pSpool->hChangeEvent= NULL;
|
||
pSpool->nWaitFlags = 0;
|
||
pSpool->nChangeFlags= 0;
|
||
|
||
if ( !err )
|
||
{
|
||
pSpool->pPrinter = pPrinter;
|
||
pSpool->pNextSpool = pPrinter->pSpoolList;
|
||
pPrinter->pSpoolList= pSpool;
|
||
}
|
||
else
|
||
{
|
||
pSpool->pPrinter = NULL;
|
||
pSpool->pNextSpool = NULL;
|
||
}
|
||
|
||
// We know about this printer before but failed to retrieve
|
||
// it this time. Clean up the error and return successfully.
|
||
// The error code is stored in the handle above which
|
||
// will be returned on subsequent calls using this
|
||
// dummy handle.
|
||
err = NO_ERROR;
|
||
|
||
LeaveCriticalSection( &NwPrintCritSec );
|
||
|
||
ErrorExit:
|
||
|
||
if (fImpersonate)
|
||
(void) NwRevertToSelf() ;
|
||
|
||
if ( err )
|
||
{
|
||
if ( pSpool )
|
||
FreeNwSplMem( pSpool, sizeof( NWSPOOL) );
|
||
}
|
||
else
|
||
{
|
||
*phPrinter = (NWWKSTA_PRINTER_CONTEXT) pSpool;
|
||
}
|
||
|
||
//
|
||
// Free up all allocated memories
|
||
//
|
||
*(pszServer + wcslen( pszServer)) = L'\\';
|
||
FreeNwSplStr( pszServer );
|
||
|
||
return err;
|
||
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwrClosePrinter(
|
||
IN OUT LPNWWKSTA_PRINTER_CONTEXT phPrinter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine closes the given printer object.
|
||
|
||
Arguments:
|
||
|
||
phPrinter - Handle of the printer object
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
PNWSPOOL pSpool = (PNWSPOOL) *phPrinter;
|
||
PNWPRINTER pPrinter;
|
||
PNWSPOOL pCur, pPrev = NULL;
|
||
|
||
|
||
if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE ))
|
||
return ERROR_INVALID_HANDLE;
|
||
|
||
//
|
||
// If OpenPrinter failed, then this is a dummy handle.
|
||
// We just need to free up the memory.
|
||
//
|
||
if ( pSpool->errOpenPrinter )
|
||
{
|
||
//
|
||
// invalidate the signature, but leave a recognizable value
|
||
//
|
||
pSpool->nSignature += 1 ;
|
||
FreeNwSplMem( pSpool, sizeof( NWSPOOL) );
|
||
*phPrinter = NULL;
|
||
return NO_ERROR;
|
||
}
|
||
|
||
pPrinter = pSpool->pPrinter;
|
||
ASSERT( pPrinter );
|
||
|
||
//
|
||
// Call EndDocPrinter if the user has not already done so
|
||
//
|
||
if ( pSpool->nStatus == SPOOL_STATUS_STARTDOC )
|
||
{
|
||
(void) NwrEndDocPrinter( *phPrinter );
|
||
}
|
||
else if ( pSpool->nStatus == SPOOL_STATUS_ADDJOB )
|
||
{
|
||
(void) NwrScheduleJob( *phPrinter, pSpool->nJobNumber );
|
||
}
|
||
|
||
if ( pSpool->hChangeEvent )
|
||
CloseHandle( pSpool->hChangeEvent );
|
||
|
||
pSpool->hChangeEvent = NULL;
|
||
pSpool->nChangeFlags = 0;
|
||
(VOID) NtClose( pSpool->hServer );
|
||
|
||
|
||
EnterCriticalSection( &NwPrintCritSec );
|
||
|
||
for ( pCur = pPrinter->pSpoolList; pCur;
|
||
pPrev = pCur, pCur = pCur->pNextSpool )
|
||
{
|
||
if ( pCur == pSpool )
|
||
{
|
||
if ( pPrev )
|
||
pPrev->pNextSpool = pCur->pNextSpool;
|
||
else
|
||
pPrinter->pSpoolList = pCur->pNextSpool;
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
ASSERT( pCur );
|
||
|
||
if ( pPrinter->pSpoolList == NULL )
|
||
{
|
||
#if DBG
|
||
IF_DEBUG(PRINT)
|
||
{
|
||
KdPrint(("*************DELETED PRINTER ENTRY: %ws\\%ws\n\n",
|
||
pPrinter->pszServer, pPrinter->pszQueue ));
|
||
}
|
||
#endif
|
||
|
||
NwRemovePrinterEntry( pPrinter );
|
||
}
|
||
|
||
LeaveCriticalSection( &NwPrintCritSec );
|
||
|
||
//
|
||
// invalidate the signature, but leave a recognizable value
|
||
//
|
||
pSpool->nSignature += 1 ;
|
||
|
||
pSpool->pNextSpool = NULL;
|
||
pSpool->pPrinter = NULL;
|
||
|
||
//
|
||
// Free all memory associated with the context handle
|
||
//
|
||
FreeNwSplMem( pSpool, sizeof( NWSPOOL) );
|
||
|
||
//
|
||
// indicate to RPC we are done
|
||
//
|
||
*phPrinter = NULL;
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwrGetPrinter(
|
||
IN NWWKSTA_PRINTER_CONTEXT hPrinter,
|
||
IN DWORD dwLevel,
|
||
IN OUT LPBYTE pbPrinter,
|
||
IN DWORD cbBuf,
|
||
OUT LPDWORD pcbNeeded
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine retrieves information about the given printer.
|
||
|
||
Arguments:
|
||
|
||
hPrinter - Handle of the printer
|
||
dwLevel - Specifies the level of the structure to which pbPrinter points.
|
||
pbPrinter - Points to a buffer that receives the PRINTER_INFO object.
|
||
cbBuf - Size, in bytes of the array pbPrinter points to.
|
||
pcbNeeded - Points to a value which specifies the number of bytes copied
|
||
if the function succeeds or the number of bytes required if
|
||
cbBuf was too small.
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
|
||
PNWPRINTER pPrinter;
|
||
|
||
LPBYTE pbEnd = pbPrinter + cbBuf;
|
||
BOOL fFitInBuffer;
|
||
DWORD_PTR *pOffsets;
|
||
|
||
if ( !pSpool || pSpool->nSignature != NW_SIGNATURE )
|
||
{
|
||
return ERROR_INVALID_HANDLE;
|
||
}
|
||
else if ( pSpool->errOpenPrinter )
|
||
{
|
||
return pSpool->errOpenPrinter;
|
||
}
|
||
else if ( ( dwLevel != 1 ) && ( dwLevel != 2 ) && ( dwLevel != 3 ))
|
||
{
|
||
return ERROR_INVALID_LEVEL;
|
||
}
|
||
|
||
if ( !pbPrinter )
|
||
{
|
||
if ( cbBuf == 0 )
|
||
{
|
||
//
|
||
// Calculate size needed
|
||
//
|
||
pPrinter = pSpool->pPrinter;
|
||
ASSERT( pPrinter );
|
||
|
||
if ( dwLevel == 1 )
|
||
{
|
||
*pcbNeeded = sizeof( PRINTER_INFO_1W ) +
|
||
( wcslen( pPrinter->pszServer )
|
||
+ wcslen( pPrinter->pszQueue ) + 2 ) * sizeof( WCHAR );
|
||
}
|
||
else if ( dwLevel == 2 )
|
||
{
|
||
*pcbNeeded = sizeof( PRINTER_INFO_2W ) +
|
||
( 2*wcslen( pPrinter->pszServer ) +
|
||
2*wcslen( pPrinter->pszQueue ) + 4 ) * sizeof( WCHAR );
|
||
}
|
||
else // Level == 3
|
||
{
|
||
PRINTER_INFO_3 *pPrinterInfo3 = (PRINTER_INFO_3 *) pbPrinter;
|
||
|
||
*pcbNeeded = sizeof( PRINTER_INFO_3 );
|
||
}
|
||
return ERROR_INSUFFICIENT_BUFFER;
|
||
}
|
||
else
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
pPrinter = pSpool->pPrinter;
|
||
ASSERT( pPrinter );
|
||
|
||
if ( dwLevel == 1 )
|
||
{
|
||
PRINTER_INFO_1W *pPrinterInfo1 = (PRINTER_INFO_1W *) pbPrinter;
|
||
LPBYTE pbFixedEnd = pbPrinter + sizeof( PRINTER_INFO_1W );
|
||
|
||
//
|
||
// Calculate size needed
|
||
//
|
||
*pcbNeeded = sizeof( PRINTER_INFO_1W ) +
|
||
( wcslen( pPrinter->pszServer )
|
||
+ wcslen( pPrinter->pszQueue ) + 2 ) * sizeof( WCHAR );
|
||
|
||
if ( cbBuf < *pcbNeeded )
|
||
return ERROR_INSUFFICIENT_BUFFER;
|
||
|
||
pOffsets = PrinterInfo1Offsets;
|
||
|
||
//
|
||
// Fill in the structure
|
||
//
|
||
pPrinterInfo1->Flags = PRINTER_ENUM_REMOTE | PRINTER_ENUM_NAME;
|
||
pPrinterInfo1->pComment = NULL;
|
||
|
||
fFitInBuffer = NwlibCopyStringToBuffer(
|
||
pPrinter->pszServer,
|
||
wcslen( pPrinter->pszServer ),
|
||
(LPWSTR) pbFixedEnd,
|
||
(LPWSTR *) &pbEnd,
|
||
&pPrinterInfo1->pDescription );
|
||
|
||
ASSERT( fFitInBuffer );
|
||
|
||
fFitInBuffer = NwlibCopyStringToBuffer(
|
||
pPrinter->pszQueue,
|
||
wcslen( pPrinter->pszQueue ),
|
||
(LPWSTR) pbFixedEnd,
|
||
(LPWSTR *) &pbEnd,
|
||
&pPrinterInfo1->pName );
|
||
|
||
ASSERT( fFitInBuffer );
|
||
|
||
}
|
||
else if ( dwLevel == 2 )
|
||
{
|
||
DWORD err;
|
||
BYTE nQueueStatus;
|
||
BYTE nNumJobs;
|
||
PRINTER_INFO_2W *pPrinterInfo2 = (PRINTER_INFO_2W *) pbPrinter;
|
||
LPBYTE pbFixedEnd = pbPrinter + sizeof( PRINTER_INFO_2W );
|
||
|
||
//
|
||
// Check if the buffer is big enough to hold all the data
|
||
//
|
||
|
||
*pcbNeeded = sizeof( PRINTER_INFO_2W ) +
|
||
( 2*wcslen( pPrinter->pszServer ) +
|
||
2*wcslen( pPrinter->pszQueue ) + 4 ) * sizeof( WCHAR );
|
||
|
||
if ( cbBuf < *pcbNeeded )
|
||
return ERROR_INSUFFICIENT_BUFFER;
|
||
|
||
pOffsets = PrinterInfo2Offsets;
|
||
|
||
err = NwReadQueueCurrentStatus( pSpool->hServer,
|
||
pPrinter->nQueueId,
|
||
&nQueueStatus,
|
||
&nNumJobs );
|
||
|
||
if ( err )
|
||
return err;
|
||
|
||
pPrinterInfo2->Status = (nQueueStatus & 0x05)? PRINTER_STATUS_PAUSED
|
||
: 0;
|
||
pPrinterInfo2->cJobs = nNumJobs;
|
||
|
||
fFitInBuffer = NwlibCopyStringToBuffer(
|
||
pPrinter->pszServer,
|
||
wcslen( pPrinter->pszServer ),
|
||
(LPCWSTR) pbFixedEnd,
|
||
(LPWSTR *) &pbEnd,
|
||
&pPrinterInfo2->pServerName );
|
||
|
||
ASSERT( fFitInBuffer );
|
||
|
||
pbEnd -= ( wcslen( pPrinter->pszQueue) + 1 ) * sizeof( WCHAR );
|
||
wcscpy( (LPWSTR) pbEnd, pPrinter->pszQueue );
|
||
pbEnd -= ( wcslen( pPrinter->pszServer) + 1 ) * sizeof( WCHAR );
|
||
wcscpy( (LPWSTR) pbEnd, pPrinter->pszServer );
|
||
*(pbEnd + wcslen( pPrinter->pszServer )*sizeof(WCHAR))= L'\\';
|
||
pPrinterInfo2->pPrinterName = (LPWSTR) pbEnd;
|
||
|
||
fFitInBuffer = NwlibCopyStringToBuffer(
|
||
pPrinter->pszQueue,
|
||
wcslen( pPrinter->pszQueue ),
|
||
(LPCWSTR) pbFixedEnd,
|
||
(LPWSTR *) &pbEnd,
|
||
&pPrinterInfo2->pShareName );
|
||
|
||
ASSERT( fFitInBuffer );
|
||
|
||
pPrinterInfo2->pPortName = NULL;
|
||
pPrinterInfo2->pDriverName = NULL;
|
||
pPrinterInfo2->pComment = NULL;
|
||
pPrinterInfo2->pLocation = NULL;
|
||
pPrinterInfo2->pDevMode = NULL;
|
||
pPrinterInfo2->pSepFile = NULL;
|
||
pPrinterInfo2->pPrintProcessor = NULL;
|
||
pPrinterInfo2->pDatatype = NULL;
|
||
pPrinterInfo2->pParameters = NULL;
|
||
pPrinterInfo2->pSecurityDescriptor = NULL;
|
||
pPrinterInfo2->Attributes = PRINTER_ATTRIBUTE_QUEUED;
|
||
pPrinterInfo2->Priority = 0;
|
||
pPrinterInfo2->DefaultPriority = 0;
|
||
pPrinterInfo2->StartTime = 0;
|
||
pPrinterInfo2->UntilTime = 0;
|
||
pPrinterInfo2->AveragePPM = 0;
|
||
}
|
||
else // Level == 3
|
||
{
|
||
PRINTER_INFO_3 *pPrinterInfo3 = (PRINTER_INFO_3 *) pbPrinter;
|
||
|
||
*pcbNeeded = sizeof( PRINTER_INFO_3 );
|
||
|
||
if ( cbBuf < *pcbNeeded )
|
||
return ERROR_INSUFFICIENT_BUFFER;
|
||
|
||
pOffsets = PrinterInfo3Offsets;
|
||
pPrinterInfo3->pSecurityDescriptor = NULL;
|
||
}
|
||
|
||
MarshallDownStructure( pbPrinter, pOffsets, pbPrinter );
|
||
return NO_ERROR;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwrSetPrinter(
|
||
IN NWWKSTA_PRINTER_CONTEXT hPrinter,
|
||
IN DWORD dwCommand
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine sets information about the given printer.
|
||
|
||
Arguments:
|
||
|
||
hPrinter - Handle of the printer
|
||
dwCommand - Specifies the new printer state
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
|
||
DWORD err = NO_ERROR;
|
||
PNWPRINTER pPrinter;
|
||
|
||
if ( !pSpool || pSpool->nSignature != NW_SIGNATURE )
|
||
{
|
||
return ERROR_INVALID_HANDLE;
|
||
}
|
||
else if ( pSpool->errOpenPrinter )
|
||
{
|
||
return pSpool->errOpenPrinter;
|
||
}
|
||
|
||
pPrinter = pSpool->pPrinter;
|
||
ASSERT( pPrinter );
|
||
|
||
switch ( dwCommand )
|
||
{
|
||
case PRINTER_CONTROL_PAUSE:
|
||
case PRINTER_CONTROL_RESUME:
|
||
{
|
||
BYTE nQueueStatus = 0;
|
||
BYTE nNumJobs;
|
||
|
||
//
|
||
// Get the original queue status so that we don't overwrite
|
||
// some of the bits.
|
||
//
|
||
err = NwReadQueueCurrentStatus( pSpool->hServer,
|
||
pPrinter->nQueueId,
|
||
&nQueueStatus,
|
||
&nNumJobs );
|
||
|
||
if ( !err )
|
||
{
|
||
//
|
||
// Clear the pause bits, and leave the rest alone.
|
||
//
|
||
nQueueStatus &= ~0x05;
|
||
}
|
||
|
||
if ( dwCommand == PRINTER_CONTROL_PAUSE )
|
||
{
|
||
nQueueStatus |= 0x04;
|
||
}
|
||
|
||
err = NwSetQueueCurrentStatus( pSpool->hServer,
|
||
pPrinter->nQueueId,
|
||
nQueueStatus );
|
||
if ( !err )
|
||
NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_PRINTER );
|
||
break;
|
||
}
|
||
|
||
case PRINTER_CONTROL_PURGE:
|
||
|
||
err = NwRemoveAllJobsFromQueue( pSpool->hServer,
|
||
pPrinter->nQueueId );
|
||
if ( !err )
|
||
NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_PRINTER |
|
||
PRINTER_CHANGE_DELETE_JOB );
|
||
break;
|
||
|
||
default:
|
||
//
|
||
// dwCommand is 0 so that means
|
||
// some properties of the printer has changed.
|
||
// We will ignore the properties that
|
||
// are being modified since most properties
|
||
// are stored in the registry by spooler.
|
||
// All we need to do is to signal WaitForPrinterChange to
|
||
// return so that print manager will refresh its data.
|
||
//
|
||
|
||
ASSERT( dwCommand == 0 );
|
||
NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_PRINTER );
|
||
break;
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwrEnumPrinters(
|
||
IN LPWSTR Reserved,
|
||
IN LPWSTR pszName,
|
||
IN OUT LPBYTE pbPrinter,
|
||
IN DWORD cbBuf,
|
||
OUT LPDWORD pcbNeeded,
|
||
OUT LPDWORD pcReturned
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine enumerates the available providers, servers, printers
|
||
depending on the given pszName.
|
||
|
||
Arguments:
|
||
|
||
Reserved - Unused
|
||
pszName - The name of the container object
|
||
pbPrinter - Points to the array to receive the PRINTER_INFO objects
|
||
cbBuf - Size, in bytes of pbPrinter
|
||
pcbNeeded - Count of bytes needed
|
||
pcReturned - Count of PRINTER_INFO objects
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
PRINTER_INFO_1W *pPrinterInfo1 = (PRINTER_INFO_1W *) pbPrinter;
|
||
|
||
*pcbNeeded = 0;
|
||
*pcReturned = 0;
|
||
|
||
if ( ( cbBuf != 0 ) && !pbPrinter )
|
||
{
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
if ( !pszName ) // Enumerate the provider name
|
||
{
|
||
BOOL fFitInBuffer;
|
||
LPBYTE pbFixedEnd = pbPrinter + sizeof( PRINTER_INFO_1W );
|
||
LPBYTE pbEnd = pbPrinter + cbBuf;
|
||
|
||
*pcbNeeded = sizeof( PRINTER_INFO_1W ) +
|
||
( 2 * wcslen( NwProviderName ) +
|
||
+ 2) * sizeof(WCHAR);
|
||
|
||
if ( *pcbNeeded > cbBuf )
|
||
return ERROR_INSUFFICIENT_BUFFER;
|
||
|
||
pPrinterInfo1->Flags = PRINTER_ENUM_ICON1 |
|
||
PRINTER_ENUM_CONTAINER |
|
||
PRINTER_ENUM_EXPAND;
|
||
pPrinterInfo1->pComment = NULL;
|
||
|
||
fFitInBuffer = NwlibCopyStringToBuffer(
|
||
NwProviderName,
|
||
wcslen( NwProviderName ),
|
||
(LPWSTR) pbFixedEnd,
|
||
(LPWSTR *) &pbEnd,
|
||
&pPrinterInfo1->pDescription );
|
||
|
||
ASSERT( fFitInBuffer );
|
||
|
||
fFitInBuffer = NwlibCopyStringToBuffer(
|
||
NwProviderName,
|
||
wcslen( NwProviderName ),
|
||
(LPWSTR) pbFixedEnd,
|
||
(LPWSTR *) &pbEnd,
|
||
&pPrinterInfo1->pName );
|
||
|
||
ASSERT( fFitInBuffer );
|
||
|
||
MarshallDownStructure( pbPrinter, PrinterInfo1Offsets, pbPrinter );
|
||
*pcReturned = 1;
|
||
}
|
||
|
||
else if ( pszName && *pszName )
|
||
{
|
||
DWORD err;
|
||
LPWSTR pszFullName;
|
||
LPWSTR pszServer;
|
||
NWWKSTA_CONTEXT_HANDLE handle;
|
||
BYTE bTemp = 0;
|
||
LPBYTE pbTempBuf = pbPrinter ? pbPrinter : &bTemp;
|
||
|
||
if ( (pszFullName = LocalAlloc( 0, (wcslen( pszName ) + 1) *
|
||
sizeof(WCHAR) ) ) == NULL )
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
||
wcscpy( pszFullName, pszName );
|
||
pszServer = wcschr( pszFullName, L'!');
|
||
|
||
if ( pszServer )
|
||
*pszServer++ = 0;
|
||
|
||
if ( lstrcmpiW( pszFullName, NwProviderName ) )
|
||
{
|
||
LocalFree( pszFullName );
|
||
return ERROR_INVALID_NAME;
|
||
}
|
||
|
||
if ( !pszServer ) // Enumerate servers
|
||
{
|
||
LocalFree( pszFullName );
|
||
|
||
err = NwOpenEnumPrintServers( &handle );
|
||
|
||
if ( err != NO_ERROR )
|
||
{
|
||
return err;
|
||
}
|
||
|
||
err = NwrEnum( handle,
|
||
(DWORD_PTR) -1,
|
||
pbTempBuf,
|
||
cbBuf,
|
||
pcbNeeded,
|
||
pcReturned );
|
||
|
||
if ( err != NO_ERROR )
|
||
{
|
||
NwrCloseEnum( &handle );
|
||
return err;
|
||
}
|
||
|
||
err = NwrCloseEnum( &handle );
|
||
|
||
if ( err != NO_ERROR )
|
||
{
|
||
return err;
|
||
}
|
||
}
|
||
else // Enumerate NDS sub-trees or print queues
|
||
{
|
||
LPWSTR tempStrPtr = pszServer;
|
||
DWORD dwClassType = 0;
|
||
|
||
if ( tempStrPtr[0] == L'\\' &&
|
||
tempStrPtr[1] == L'\\' &&
|
||
tempStrPtr[2] == L' ' )
|
||
tempStrPtr = &tempStrPtr[1];
|
||
|
||
err = NwrOpenEnumNdsSubTrees_Print( NULL, tempStrPtr, &dwClassType, &handle );
|
||
|
||
if ( err == ERROR_NETWORK_ACCESS_DENIED && dwClassType == CLASS_TYPE_NCP_SERVER )
|
||
{
|
||
// An error code from the above NwOpenEnumNdsSubTrees could have
|
||
// failed because the object was a server, which cannot be enumerated
|
||
// with the NDS tree APIs. If so we try to get the print queues with the
|
||
// regular NW APIs.
|
||
|
||
tempStrPtr = NwGetUncObjectName( tempStrPtr );
|
||
|
||
err = NwOpenEnumPrintQueues( tempStrPtr, &handle );
|
||
|
||
if ( err != NO_ERROR )
|
||
{
|
||
LocalFree( pszFullName );
|
||
return err;
|
||
}
|
||
}
|
||
|
||
if ( err != NO_ERROR )
|
||
{
|
||
// An error code from the above NwOpenEnumNdsSubTrees could have
|
||
// failed because the object was not a part of an NDS tree.
|
||
// So we try to get the print queues with the regular NW APIs.
|
||
|
||
err = NwOpenEnumPrintQueues( tempStrPtr, &handle );
|
||
|
||
if ( err != NO_ERROR )
|
||
{
|
||
LocalFree( pszFullName );
|
||
return err;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Get rid of the allocated temp buffer that we've been using
|
||
// indirectly through tempStrPtr and pszServer.
|
||
//
|
||
LocalFree( pszFullName );
|
||
|
||
err = NwrEnum( handle,
|
||
0xFFFFFFFF,
|
||
pbTempBuf,
|
||
cbBuf,
|
||
pcbNeeded,
|
||
pcReturned );
|
||
|
||
if ( err != NO_ERROR )
|
||
{
|
||
NwrCloseEnum( &handle );
|
||
return err;
|
||
}
|
||
|
||
err = NwrCloseEnum( &handle );
|
||
|
||
if ( err != NO_ERROR )
|
||
{
|
||
return err;
|
||
}
|
||
}
|
||
}
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
|
||
DWORD
|
||
NwrStartDocPrinter(
|
||
IN NWWKSTA_PRINTER_CONTEXT hPrinter,
|
||
IN LPWSTR pszDocument,
|
||
IN LPWSTR pszUser,
|
||
IN DWORD PrintOptions, //Multi-User Addition
|
||
IN DWORD fGateway
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine informs the print spooler that a document is to be spooled
|
||
for printing.
|
||
|
||
Arguments:
|
||
|
||
hPrinter - Handle of the printer
|
||
pszDocument - Name of the document to be printed
|
||
pszUser - Name of the user submitting the print job
|
||
fGateway - TRUE if it is gateway printing
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
DWORD err;
|
||
PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
|
||
|
||
if ( !pSpool || (pSpool->nSignature != NW_SIGNATURE) )
|
||
{
|
||
err = ERROR_INVALID_HANDLE;
|
||
}
|
||
else if ( pSpool->errOpenPrinter )
|
||
{
|
||
err = pSpool->errOpenPrinter;
|
||
}
|
||
else if ( pSpool->nStatus != 0 )
|
||
{
|
||
err = ERROR_INVALID_PARAMETER;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Get pSpool->nJobNumber from CreateQueueJobAndFile
|
||
//
|
||
|
||
PNWPRINTER pPrinter = pSpool->pPrinter;
|
||
WORD nJobNumber = 0;
|
||
|
||
ASSERT( pPrinter );
|
||
err = NwCreateQueueJobAndFile( pSpool->hServer,
|
||
pPrinter->nQueueId,
|
||
pszDocument,
|
||
pszUser,
|
||
fGateway,
|
||
PrintOptions, //Multi-User addition
|
||
pPrinter->pszQueue,
|
||
&nJobNumber );
|
||
|
||
if ( !err )
|
||
{
|
||
pSpool->nJobNumber = nJobNumber;
|
||
pSpool->nStatus = SPOOL_STATUS_STARTDOC;
|
||
NwSetPrinterChange( pSpool, PRINTER_CHANGE_ADD_JOB |
|
||
PRINTER_CHANGE_SET_PRINTER );
|
||
}
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwrWritePrinter(
|
||
IN NWWKSTA_PRINTER_CONTEXT hPrinter,
|
||
IN LPBYTE pBuf,
|
||
IN DWORD cbBuf,
|
||
OUT LPDWORD pcbWritten
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine informs the print spooler that the specified data should be
|
||
written to the given printer.
|
||
|
||
Arguments:
|
||
|
||
hPrinter - Handle of the printer object
|
||
pBuf - Address of array that contains printer data
|
||
cbBuf - Size, in bytes of pBuf
|
||
pcbWritten - Receives the number of bytes actually written to the printer
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
DWORD err = NO_ERROR;
|
||
PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
|
||
|
||
if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE))
|
||
{
|
||
err = ERROR_INVALID_HANDLE;
|
||
}
|
||
else if ( pSpool->errOpenPrinter )
|
||
{
|
||
err = pSpool->errOpenPrinter;
|
||
}
|
||
else if ( pSpool->nStatus != SPOOL_STATUS_STARTDOC )
|
||
{
|
||
err = ERROR_INVALID_PARAMETER;
|
||
}
|
||
else
|
||
{
|
||
NTSTATUS ntstatus;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
PNWPRINTER pPrinter = pSpool->pPrinter;
|
||
|
||
ASSERT( pPrinter );
|
||
ntstatus = NtWriteFile( pSpool->hServer,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&IoStatusBlock,
|
||
pBuf,
|
||
cbBuf,
|
||
NULL,
|
||
NULL );
|
||
|
||
if ( NT_SUCCESS(ntstatus))
|
||
ntstatus = IoStatusBlock.Status;
|
||
|
||
if ( NT_SUCCESS(ntstatus) )
|
||
{
|
||
*pcbWritten = (DWORD) IoStatusBlock.Information;
|
||
NwSetPrinterChange( pSpool, PRINTER_CHANGE_WRITE_JOB );
|
||
}
|
||
else
|
||
{
|
||
KdPrint(("NWWORKSTATION: NtWriteFile failed 0x%08lx\n", ntstatus));
|
||
*pcbWritten = 0;
|
||
err = RtlNtStatusToDosError( ntstatus );
|
||
}
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwrAbortPrinter(
|
||
IN NWWKSTA_PRINTER_CONTEXT hPrinter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine deletes a printer's spool file if the printer is configured
|
||
for spooling.
|
||
|
||
Arguments:
|
||
|
||
hPrinter - Handle of the printer object
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
DWORD err;
|
||
PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
|
||
|
||
if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE ))
|
||
{
|
||
err = ERROR_INVALID_HANDLE;
|
||
}
|
||
else if ( pSpool->errOpenPrinter )
|
||
{
|
||
err = pSpool->errOpenPrinter;
|
||
}
|
||
else if ( pSpool->nStatus != SPOOL_STATUS_STARTDOC )
|
||
{
|
||
err = ERROR_INVALID_PARAMETER;
|
||
}
|
||
else
|
||
{
|
||
PNWPRINTER pPrinter = pSpool->pPrinter;
|
||
|
||
ASSERT( pPrinter );
|
||
err = NwRemoveJobFromQueue( pSpool->hServer,
|
||
pPrinter->nQueueId,
|
||
(WORD) pSpool->nJobNumber );
|
||
|
||
if ( !err )
|
||
{
|
||
pSpool->nJobNumber = 0;
|
||
pSpool->nStatus = SPOOL_STATUS_ABORT;
|
||
NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_JOB );
|
||
}
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwrEndDocPrinter(
|
||
IN NWWKSTA_PRINTER_CONTEXT hPrinter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine ends the print job for the given printer.
|
||
|
||
Arguments:
|
||
|
||
hPrinter - Handle of the printer object
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
DWORD err = NO_ERROR;
|
||
PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
|
||
|
||
if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE ))
|
||
{
|
||
err = ERROR_INVALID_HANDLE;
|
||
}
|
||
else if ( pSpool->errOpenPrinter )
|
||
{
|
||
err = pSpool->errOpenPrinter;
|
||
}
|
||
else if ( ( pSpool->nStatus != SPOOL_STATUS_STARTDOC )
|
||
&& ( pSpool->nStatus != SPOOL_STATUS_ABORT )
|
||
)
|
||
{
|
||
err = ERROR_INVALID_PARAMETER;
|
||
}
|
||
else
|
||
{
|
||
PNWPRINTER pPrinter = pSpool->pPrinter;
|
||
|
||
ASSERT( pPrinter );
|
||
|
||
if ( pSpool->nStatus == SPOOL_STATUS_STARTDOC )
|
||
{
|
||
err = NwCloseFileAndStartQueueJob( pSpool->hServer,
|
||
pPrinter->nQueueId,
|
||
(WORD) pSpool->nJobNumber );
|
||
|
||
if ( !err )
|
||
NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_JOB );
|
||
}
|
||
|
||
if ( !err )
|
||
{
|
||
pSpool->nJobNumber = 0;
|
||
pSpool->nStatus = 0;
|
||
}
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwrGetJob(
|
||
IN NWWKSTA_PRINTER_CONTEXT hPrinter,
|
||
IN DWORD dwJobId,
|
||
IN DWORD dwLevel,
|
||
IN OUT LPBYTE pbJob,
|
||
IN DWORD cbBuf,
|
||
OUT LPDWORD pcbNeeded
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
hPrinter - Handle of the printer
|
||
dwJobId -
|
||
dwLevel -
|
||
pbJob -
|
||
cbBuf -
|
||
pcbNeeded -
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
DWORD err;
|
||
PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
|
||
|
||
if ( !pSpool || pSpool->nSignature != NW_SIGNATURE )
|
||
{
|
||
err = ERROR_INVALID_HANDLE;
|
||
}
|
||
// allow NULL for bpJob if cbBuf is 0.
|
||
// Relies on NwGetQueueJobInfo to properly handle NULL pointer in request to fill pcbNeeded
|
||
else if ( (cbBuf != 0) && ( !pbJob ) )
|
||
{
|
||
err = ERROR_INVALID_PARAMETER;
|
||
}
|
||
else if ( pSpool->errOpenPrinter )
|
||
{
|
||
err = pSpool->errOpenPrinter;
|
||
}
|
||
else if (( dwLevel != 1 ) && ( dwLevel != 2 ))
|
||
{
|
||
err = ERROR_INVALID_LEVEL;
|
||
}
|
||
else
|
||
{
|
||
DWORD nPrinterLen;
|
||
LPWSTR pszPrinter;
|
||
LPBYTE FixedPortion = pbJob;
|
||
LPWSTR EndOfVariableData = (LPWSTR) (pbJob + cbBuf);
|
||
PNWPRINTER pPrinter = pSpool->pPrinter;
|
||
|
||
ASSERT( pPrinter );
|
||
|
||
pszPrinter = AllocNwSplMem( LMEM_ZEROINIT,
|
||
nPrinterLen = ( wcslen( pPrinter->pszServer) +
|
||
wcslen( pPrinter->pszQueue) + 2) * sizeof(WCHAR));
|
||
|
||
if ( pszPrinter == NULL )
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
||
wcscpy( pszPrinter, pPrinter->pszServer );
|
||
wcscat( pszPrinter, L"\\" );
|
||
wcscat( pszPrinter, pPrinter->pszQueue );
|
||
|
||
*pcbNeeded = 0;
|
||
err = NwGetQueueJobInfo( pSpool->hServer,
|
||
pPrinter->nQueueId,
|
||
(WORD) dwJobId,
|
||
pszPrinter,
|
||
dwLevel,
|
||
&FixedPortion,
|
||
&EndOfVariableData,
|
||
pcbNeeded );
|
||
|
||
FreeNwSplMem( pszPrinter, nPrinterLen );
|
||
|
||
if ( !err )
|
||
{
|
||
switch( dwLevel )
|
||
{
|
||
case 1:
|
||
MarshallDownStructure( pbJob, JobInfo1Offsets, pbJob );
|
||
break;
|
||
|
||
case 2:
|
||
MarshallDownStructure( pbJob, JobInfo2Offsets, pbJob );
|
||
break;
|
||
|
||
default:
|
||
ASSERT( FALSE );
|
||
break;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwrEnumJobs(
|
||
IN NWWKSTA_PRINTER_CONTEXT hPrinter,
|
||
IN DWORD dwFirstJob,
|
||
IN DWORD dwNoJobs,
|
||
IN DWORD dwLevel,
|
||
IN OUT LPBYTE pbJob,
|
||
IN DWORD cbBuf,
|
||
OUT LPDWORD pcbNeeded,
|
||
OUT LPDWORD pcReturned
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
hPrinter - Handle of the printer
|
||
dwFirstJob -
|
||
dwNoJobs -
|
||
dwLevel -
|
||
pbJob -
|
||
cbBuf -
|
||
pcbNeeded -
|
||
pcReturned -
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
DWORD err;
|
||
PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
|
||
|
||
|
||
if ( !pSpool || pSpool->nSignature != NW_SIGNATURE )
|
||
{
|
||
err = ERROR_INVALID_HANDLE;
|
||
}
|
||
// allow NULL for bpJob if cbBuf is 0.
|
||
// Relies on NwGetQueueJobInfo to properly handle NULL pointer in request to fill pcbNeeded
|
||
else if ( (cbBuf != 0) && ( !pbJob ) )
|
||
{
|
||
err = ERROR_INVALID_PARAMETER;
|
||
}
|
||
else if ( pSpool->errOpenPrinter )
|
||
{
|
||
err = pSpool->errOpenPrinter;
|
||
}
|
||
else if ( ( dwLevel != 1 ) && ( dwLevel != 2 ) )
|
||
{
|
||
err = ERROR_INVALID_LEVEL;
|
||
}
|
||
else
|
||
{
|
||
PNWPRINTER pPrinter = pSpool->pPrinter;
|
||
LPWSTR pszPrinter;
|
||
DWORD nPrinterLen;
|
||
|
||
ASSERT( pPrinter );
|
||
pszPrinter = AllocNwSplMem( LMEM_ZEROINIT,
|
||
nPrinterLen = ( wcslen( pPrinter->pszServer ) +
|
||
wcslen( pPrinter->pszQueue) + 2) * sizeof(WCHAR));
|
||
|
||
if ( pszPrinter == NULL )
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
||
wcscpy( pszPrinter, pPrinter->pszServer );
|
||
wcscat( pszPrinter, L"\\" );
|
||
wcscat( pszPrinter, pPrinter->pszQueue );
|
||
|
||
err = NwGetQueueJobs( pSpool->hServer,
|
||
pPrinter->nQueueId,
|
||
pszPrinter,
|
||
dwFirstJob,
|
||
dwNoJobs,
|
||
dwLevel,
|
||
pbJob,
|
||
cbBuf,
|
||
pcbNeeded,
|
||
pcReturned );
|
||
|
||
FreeNwSplMem( pszPrinter, nPrinterLen );
|
||
|
||
if ( !err )
|
||
{
|
||
DWORD_PTR *pOffsets;
|
||
DWORD cbStruct;
|
||
DWORD cReturned = *pcReturned;
|
||
LPBYTE pbBuffer = pbJob;
|
||
|
||
switch( dwLevel )
|
||
{
|
||
case 1:
|
||
pOffsets = JobInfo1Offsets;
|
||
cbStruct = sizeof( JOB_INFO_1W );
|
||
break;
|
||
|
||
case 2:
|
||
pOffsets = JobInfo2Offsets;
|
||
cbStruct = sizeof( JOB_INFO_2W );
|
||
break;
|
||
|
||
default:
|
||
ASSERT( FALSE );
|
||
break;
|
||
}
|
||
|
||
while ( cReturned-- )
|
||
{
|
||
MarshallDownStructure( pbBuffer, pOffsets, pbJob );
|
||
pbBuffer += cbStruct;
|
||
}
|
||
}
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwrSetJob(
|
||
IN NWWKSTA_PRINTER_CONTEXT hPrinter,
|
||
IN DWORD dwJobId,
|
||
IN DWORD dwLevel,
|
||
IN PNW_JOB_INFO pNwJobInfo,
|
||
IN DWORD dwCommand
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
hPrinter - Handle of the printer
|
||
dwJobId -
|
||
dwLevel -
|
||
pNwJobInfo-
|
||
dwCommand -
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
DWORD err = NO_ERROR;
|
||
PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
|
||
PNWPRINTER pPrinter;
|
||
|
||
if ( !pSpool || pSpool->nSignature != NW_SIGNATURE )
|
||
{
|
||
err = ERROR_INVALID_HANDLE;
|
||
}
|
||
else if ( ( dwLevel != 0 ) && ( !pNwJobInfo ) )
|
||
{
|
||
err = ERROR_INVALID_PARAMETER;
|
||
}
|
||
else if ( pSpool->errOpenPrinter )
|
||
{
|
||
err = pSpool->errOpenPrinter;
|
||
}
|
||
else if ( ( dwLevel != 0 ) && ( dwLevel != 1 ) && ( dwLevel != 2 ) )
|
||
{
|
||
err = ERROR_INVALID_LEVEL;
|
||
}
|
||
|
||
if ( err )
|
||
return err;
|
||
|
||
pPrinter = pSpool->pPrinter;
|
||
ASSERT( pPrinter );
|
||
|
||
if ( ( dwCommand == JOB_CONTROL_CANCEL ) ||
|
||
( dwCommand == JOB_CONTROL_DELETE ) )
|
||
{
|
||
err = NwRemoveJobFromQueue( pSpool->hServer,
|
||
pPrinter->nQueueId,
|
||
(WORD) dwJobId );
|
||
|
||
if ( !err )
|
||
NwSetPrinterChange( pSpool, PRINTER_CHANGE_DELETE_JOB |
|
||
PRINTER_CHANGE_SET_PRINTER );
|
||
|
||
// Since the job is removed, we don't need to change other
|
||
// information about it.
|
||
}
|
||
else
|
||
{
|
||
if ( dwLevel != 0 )
|
||
{
|
||
if ( pNwJobInfo->nPosition != JOB_POSITION_UNSPECIFIED )
|
||
{
|
||
err = NwChangeQueueJobPosition( pSpool->hServer,
|
||
pPrinter->nQueueId,
|
||
(WORD) dwJobId,
|
||
(BYTE) pNwJobInfo->nPosition );
|
||
}
|
||
}
|
||
|
||
if ( ( !err ) && ( dwCommand == JOB_CONTROL_RESTART ))
|
||
{
|
||
err = ERROR_NOT_SUPPORTED;
|
||
}
|
||
else if ( !err )
|
||
{
|
||
err = NwChangeQueueJobEntry( pSpool->hServer,
|
||
pPrinter->nQueueId,
|
||
(WORD) dwJobId,
|
||
dwCommand,
|
||
pNwJobInfo );
|
||
}
|
||
|
||
if ( !err )
|
||
NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_JOB );
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwrAddJob(
|
||
IN NWWKSTA_PRINTER_CONTEXT hPrinter,
|
||
OUT LPADDJOB_INFO_1W pAddInfo1,
|
||
IN DWORD cbBuf,
|
||
OUT LPDWORD pcbNeeded
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
hPrinter - Handle of the printer.
|
||
pAddInfo1 - Output buffer to hold ADDJOB_INFO_1W structure.
|
||
cbBuf - Output buffer size in bytes.
|
||
pcbNeeded - Required output buffer size in bytes.
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
|
||
PNWPRINTER pPrinter;
|
||
|
||
|
||
if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE )) {
|
||
return ERROR_INVALID_HANDLE;
|
||
}
|
||
|
||
if ( pSpool->errOpenPrinter ) {
|
||
return pSpool->errOpenPrinter;
|
||
}
|
||
|
||
if ( pSpool->nStatus != 0 ) {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
pPrinter = pSpool->pPrinter;
|
||
ASSERT( pPrinter );
|
||
|
||
*pcbNeeded = sizeof(ADDJOB_INFO_1W) +
|
||
(wcslen(pPrinter->pszServer) +
|
||
wcslen(pPrinter->pszQueue) + 2) * sizeof(WCHAR);
|
||
|
||
if (cbBuf < *pcbNeeded) {
|
||
return ERROR_INSUFFICIENT_BUFFER;
|
||
}
|
||
|
||
//
|
||
// Write UNC path name into the output buffer.
|
||
//
|
||
// dfergus 19 Apr 2001 - 348006
|
||
// DWORD cast
|
||
pAddInfo1->Path = (LPWSTR) ((DWORD) pAddInfo1 + sizeof(ADDJOB_INFO_1W));
|
||
//
|
||
wcscpy(pAddInfo1->Path, pPrinter->pszServer);
|
||
wcscat(pAddInfo1->Path, L"\\" );
|
||
wcscat(pAddInfo1->Path, pPrinter->pszQueue);
|
||
|
||
//
|
||
// Return special job id value which the client (winspool.drv) looks
|
||
// for and does an FSCTL call to our redirector to get the real
|
||
// job id. We cannot return a real job id at this point because
|
||
// the CreateQueueJobAndFile NCP is not issue until the client opens
|
||
// the UNC name we return in this API.
|
||
//
|
||
pAddInfo1->JobId = (DWORD) -1;
|
||
|
||
//
|
||
// Save context information
|
||
//
|
||
pSpool->nJobNumber = pAddInfo1->JobId;
|
||
pSpool->nStatus = SPOOL_STATUS_ADDJOB;
|
||
|
||
#if DBG
|
||
IF_DEBUG(PRINT) {
|
||
KdPrint(("NWWORKSTATION: NwrAddJob Path=%ws, JobId=%lu, BytesNeeded=%lu\n",
|
||
pAddInfo1->Path, pAddInfo1->JobId, *pcbNeeded));
|
||
}
|
||
#endif
|
||
|
||
NwSetPrinterChange( pSpool, PRINTER_CHANGE_ADD_JOB |
|
||
PRINTER_CHANGE_SET_PRINTER );
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwrScheduleJob(
|
||
IN NWWKSTA_PRINTER_CONTEXT hPrinter,
|
||
IN DWORD dwJobId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
hPrinter - Handle of the printer
|
||
dwJobId - Job identification number
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
|
||
PNWPRINTER pPrinter;
|
||
|
||
|
||
if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE )) {
|
||
return ERROR_INVALID_HANDLE;
|
||
}
|
||
|
||
if ( pSpool->errOpenPrinter ) {
|
||
return pSpool->errOpenPrinter;
|
||
}
|
||
|
||
if (pSpool->nStatus != SPOOL_STATUS_ADDJOB) {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
pPrinter = pSpool->pPrinter;
|
||
ASSERT( pPrinter );
|
||
|
||
pSpool->nJobNumber = 0;
|
||
pSpool->nStatus = 0;
|
||
|
||
NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_JOB );
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwrWaitForPrinterChange(
|
||
IN NWWKSTA_PRINTER_CONTEXT hPrinter,
|
||
IN OUT LPDWORD pdwFlags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
hPrinter - Handle of the printer
|
||
pdwFlags -
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
|
||
HANDLE hChangeEvent = NULL;
|
||
DWORD nRetVal;
|
||
HANDLE ahWaitEvents[2];
|
||
DWORD err = NO_ERROR;
|
||
|
||
if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE ))
|
||
{
|
||
return ERROR_INVALID_HANDLE;
|
||
}
|
||
else if ( pSpool->errOpenPrinter )
|
||
{
|
||
return pSpool->errOpenPrinter;
|
||
}
|
||
else if ( pSpool->hChangeEvent )
|
||
{
|
||
return ERROR_ALREADY_WAITING;
|
||
}
|
||
else if ( !(*pdwFlags & PRINTER_CHANGE_VALID ))
|
||
{
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
|
||
if ( pSpool->nChangeFlags & *pdwFlags )
|
||
{
|
||
//
|
||
// There is a change since we last called
|
||
//
|
||
|
||
*pdwFlags &= pSpool->nChangeFlags;
|
||
|
||
EnterCriticalSection( &NwPrintCritSec );
|
||
pSpool->nChangeFlags = 0;
|
||
LeaveCriticalSection( &NwPrintCritSec );
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
hChangeEvent = CreateEvent( NULL,
|
||
FALSE, // automatic reset
|
||
FALSE, // initial state not signalled
|
||
NULL );
|
||
|
||
if ( !hChangeEvent )
|
||
{
|
||
KdPrint(("WaitForPrinterChange: CreateEvent failed with error %d\n",
|
||
GetLastError() ));
|
||
return GetLastError();
|
||
}
|
||
|
||
|
||
pSpool->nWaitFlags = *pdwFlags;
|
||
|
||
EnterCriticalSection( &NwPrintCritSec );
|
||
pSpool->hChangeEvent = hChangeEvent;
|
||
pSpool->nChangeFlags = 0;
|
||
LeaveCriticalSection( &NwPrintCritSec );
|
||
|
||
ahWaitEvents[0] = pSpool->hChangeEvent;
|
||
ahWaitEvents[1] = NwDoneEvent;
|
||
|
||
nRetVal = WaitForMultipleObjects( 2, // Two events to wait for
|
||
ahWaitEvents,
|
||
FALSE, // Wait for one to signal
|
||
NwTimeOutValue );
|
||
|
||
switch ( nRetVal )
|
||
{
|
||
case WAIT_FAILED:
|
||
err = GetLastError();
|
||
break;
|
||
|
||
case WAIT_TIMEOUT:
|
||
case WAIT_OBJECT_0 + 1: // treats service stopping as timeout
|
||
*pdwFlags |= PRINTER_CHANGE_TIMEOUT;
|
||
break;
|
||
|
||
case WAIT_OBJECT_0:
|
||
*pdwFlags &= pSpool->nChangeFlags;
|
||
break;
|
||
|
||
default:
|
||
KdPrint(("WaitForPrinterChange: WaitForMultipleObjects returned with %d\n", nRetVal ));
|
||
*pdwFlags |= PRINTER_CHANGE_TIMEOUT;
|
||
break;
|
||
}
|
||
|
||
if ( ( !err ) && ( nRetVal != WAIT_OBJECT_0 + 1 ) )
|
||
{
|
||
pSpool->nWaitFlags = 0;
|
||
|
||
EnterCriticalSection( &NwPrintCritSec );
|
||
pSpool->nChangeFlags = 0;
|
||
pSpool->hChangeEvent = NULL;
|
||
LeaveCriticalSection( &NwPrintCritSec );
|
||
}
|
||
|
||
if ( !CloseHandle( hChangeEvent ) )
|
||
{
|
||
KdPrint(("WaitForPrinterChange: CloseHandle failed with error %d\n",
|
||
GetLastError()));
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
NwSetPrinterChange(
|
||
PNWSPOOL pSpool,
|
||
DWORD nFlags
|
||
)
|
||
{
|
||
PNWPRINTER pPrinter = pSpool->pPrinter;
|
||
PNWSPOOL pCurSpool = pSpool;
|
||
|
||
EnterCriticalSection( &NwPrintCritSec );
|
||
|
||
do {
|
||
|
||
if ( pCurSpool->nWaitFlags & nFlags )
|
||
{
|
||
pCurSpool->nChangeFlags |= nFlags;
|
||
|
||
if ( pCurSpool->hChangeEvent )
|
||
{
|
||
SetEvent( pCurSpool->hChangeEvent );
|
||
pCurSpool->hChangeEvent = NULL;
|
||
}
|
||
}
|
||
|
||
pCurSpool = pCurSpool->pNextSpool;
|
||
if ( pCurSpool == NULL )
|
||
pCurSpool = pPrinter->pSpoolList;
|
||
|
||
} while ( pCurSpool && (pCurSpool != pSpool) );
|
||
|
||
LeaveCriticalSection( &NwPrintCritSec );
|
||
}
|
||
|
||
|
||
|
||
PNWPRINTER
|
||
NwFindPrinterEntry(
|
||
IN LPWSTR pszServer,
|
||
IN LPWSTR pszQueue
|
||
)
|
||
{
|
||
PNWPRINTER pPrinter = NULL;
|
||
|
||
//
|
||
// Check to see if we already have the given printer in our printer
|
||
// link list. If yes, return the printer.
|
||
//
|
||
|
||
for ( pPrinter = NwPrinterList; pPrinter; pPrinter = pPrinter->pNextPrinter)
|
||
{
|
||
if ( ( lstrcmpiW( pPrinter->pszServer, pszServer ) == 0 )
|
||
&& ( lstrcmpiW( pPrinter->pszQueue, pszQueue ) == 0 )
|
||
)
|
||
{
|
||
return pPrinter;
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwCreatePrinterEntry(
|
||
IN LPWSTR pszServer,
|
||
IN LPWSTR pszQueue,
|
||
OUT PNWPRINTER *ppPrinter,
|
||
OUT PHANDLE phServer
|
||
)
|
||
{
|
||
DWORD err = NO_ERROR;
|
||
DWORD nQueueId = 0;
|
||
HANDLE TreeHandle = NULL;
|
||
UNICODE_STRING TreeName;
|
||
PNWPRINTER pNwPrinter = NULL;
|
||
BOOL fCreatedNWConnection = FALSE;
|
||
|
||
LPWSTR lpRemoteName = NULL;
|
||
DWORD dwBufSize = ( wcslen(pszServer) + wcslen(pszQueue) + 2 )
|
||
* sizeof(WCHAR);
|
||
|
||
lpRemoteName = (LPWSTR) AllocNwSplMem( LMEM_ZEROINIT, dwBufSize );
|
||
|
||
if ( lpRemoteName == NULL )
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
||
wcscpy( lpRemoteName, pszServer );
|
||
wcscat( lpRemoteName, L"\\" );
|
||
wcscat( lpRemoteName, pszQueue );
|
||
|
||
*ppPrinter = NULL;
|
||
*phServer = NULL;
|
||
|
||
//
|
||
// See if we already know about this print queue.
|
||
//
|
||
pNwPrinter = NwFindPrinterEntry( pszServer, pszQueue );
|
||
|
||
/* Changing to get queue status to verify access instead
|
||
if ( pNwPrinter == NULL )
|
||
{
|
||
// We don't know about this NetWare print queue. We need to see if
|
||
// we are authorized to use this queue. If so, then go ahead
|
||
// and continue to open printer. Otherwise, fail with not
|
||
// authorized error code.
|
||
|
||
err = NwCreateConnection( NULL,
|
||
lpRemoteName,
|
||
RESOURCETYPE_PRINT,
|
||
NULL,
|
||
NULL );
|
||
|
||
if ( err != NO_ERROR )
|
||
{
|
||
if ( ( err == ERROR_INVALID_PASSWORD ) ||
|
||
( err == ERROR_ACCESS_DENIED ) ||
|
||
( err == ERROR_NO_SUCH_USER ) )
|
||
{
|
||
err = ERROR_ACCESS_DENIED;
|
||
}
|
||
|
||
FreeNwSplMem( lpRemoteName, dwBufSize );
|
||
|
||
return err;
|
||
}
|
||
|
||
fCreatedNWConnection = TRUE;
|
||
}
|
||
*/
|
||
|
||
//
|
||
// See if pszServer is really a NDS tree name, if so call
|
||
// NwNdsGetQueueInformation to get the QueueId and possible referred
|
||
// server for which we open handle.
|
||
//
|
||
|
||
RtlInitUnicodeString( &TreeName, pszServer + 2 );
|
||
|
||
err = NwNdsOpenTreeHandle( &TreeName, &TreeHandle );
|
||
|
||
if ( err == NO_ERROR )
|
||
{
|
||
NTSTATUS ntstatus;
|
||
WCHAR szRefServer[NDS_MAX_NAME_CHARS];
|
||
UNICODE_STRING ObjectName;
|
||
UNICODE_STRING QueuePath;
|
||
|
||
ObjectName.Buffer = szRefServer;
|
||
ObjectName.MaximumLength = NDS_MAX_NAME_CHARS;
|
||
ObjectName.Length = 0;
|
||
|
||
RtlInitUnicodeString( &QueuePath, pszQueue );
|
||
|
||
ntstatus = NwNdsGetQueueInformation( TreeHandle,
|
||
&QueuePath,
|
||
&ObjectName,
|
||
&nQueueId );
|
||
|
||
if ( TreeHandle )
|
||
{
|
||
CloseHandle( TreeHandle );
|
||
TreeHandle = NULL;
|
||
}
|
||
|
||
if ( ntstatus )
|
||
{
|
||
err = RtlNtStatusToDosError( ntstatus );
|
||
goto ErrorExit;
|
||
}
|
||
|
||
//
|
||
// If we got a referred server, it's name would look like:
|
||
// "CN=SERVER.OU=DEV.O=MICROSOFT" . . . Convert it to "C\\SERVER"
|
||
//
|
||
if ( ObjectName.Length > 0 )
|
||
{
|
||
WORD i;
|
||
LPWSTR EndOfServerName = NULL;
|
||
|
||
//
|
||
// First convert the referred server name to
|
||
// "C\\SERVER.OU=DEV.O=MICROSOFT"
|
||
//
|
||
szRefServer[1] = L'\\';
|
||
szRefServer[2] = L'\\';
|
||
|
||
//
|
||
// Put a NULL terminator at the first '.'
|
||
//
|
||
EndOfServerName = wcschr( szRefServer + 3, L'.' );
|
||
if (EndOfServerName)
|
||
*EndOfServerName = L'\0';
|
||
|
||
//
|
||
// pszServer now equals the referred server "C\\SERVER"
|
||
//
|
||
|
||
//
|
||
// Get the handle of the referred server skipping the 'C' character.
|
||
//
|
||
err = NwAttachToNetwareServer( szRefServer + 1, phServer);
|
||
}
|
||
}
|
||
else // Not an NDS tree, so get handle of server.
|
||
{
|
||
|
||
err = NwAttachToNetwareServer( pszServer, phServer);
|
||
|
||
if ( err == NO_ERROR )
|
||
{
|
||
if ( err = NwGetQueueId( *phServer, pszQueue, &nQueueId))
|
||
err = ERROR_INVALID_NAME;
|
||
}
|
||
}
|
||
|
||
if ( ( err == ERROR_INVALID_PASSWORD ) ||
|
||
( err == ERROR_ACCESS_DENIED ) ||
|
||
( err == ERROR_NO_SUCH_USER ) )
|
||
{
|
||
err = ERROR_ACCESS_DENIED;
|
||
goto ErrorExit;
|
||
}
|
||
else if ( err != NO_ERROR )
|
||
{
|
||
err = ERROR_INVALID_NAME;
|
||
goto ErrorExit;
|
||
}
|
||
|
||
//
|
||
// Test to see if there already was a entry for this print queue. If so,
|
||
// we can now return with NO_ERROR since pNwPrinter and phServer are
|
||
// now set.
|
||
//
|
||
if ( pNwPrinter )
|
||
{
|
||
if ( lpRemoteName )
|
||
{
|
||
FreeNwSplMem( lpRemoteName, dwBufSize );
|
||
}
|
||
|
||
*ppPrinter = pNwPrinter;
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
//
|
||
// The printer entry was not found in our list of printers in the
|
||
// call to NwFindPrinterEntry. So, we must create one.
|
||
//
|
||
// First, verify access rights
|
||
else
|
||
{
|
||
BYTE nQueueStatus;
|
||
BYTE nJobCount;
|
||
|
||
err = NwReadQueueCurrentStatus(*phServer, nQueueId, &nQueueStatus, &nJobCount);
|
||
|
||
if ( ( err == ERROR_INVALID_PASSWORD ) ||
|
||
( err == ERROR_ACCESS_DENIED ) ||
|
||
( err == ERROR_NO_SUCH_USER ) )
|
||
{
|
||
err = ERROR_ACCESS_DENIED;
|
||
goto ErrorExit;
|
||
}
|
||
else if ( err != NO_ERROR )
|
||
{
|
||
err = ERROR_INVALID_NAME;
|
||
goto ErrorExit;
|
||
}
|
||
|
||
}
|
||
|
||
if ( *ppPrinter = AllocNwSplMem( LMEM_ZEROINIT, sizeof(NWPRINTER) ))
|
||
{
|
||
if ( !( (*ppPrinter)->pszServer = AllocNwSplStr( pszServer )) )
|
||
{
|
||
err = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto ErrorExit;
|
||
}
|
||
else if ( !( (*ppPrinter)->pszQueue = AllocNwSplStr( pszQueue )))
|
||
{
|
||
err = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto ErrorExit;
|
||
}
|
||
|
||
if ( fCreatedNWConnection )
|
||
{
|
||
if ( !( (*ppPrinter)->pszUncConnection =
|
||
AllocNwSplStr( lpRemoteName )) )
|
||
{
|
||
err = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto ErrorExit;
|
||
}
|
||
|
||
FreeNwSplMem( lpRemoteName, dwBufSize );
|
||
lpRemoteName = NULL;
|
||
}
|
||
else
|
||
{
|
||
(*ppPrinter)->pszUncConnection = NULL;
|
||
}
|
||
|
||
#if DBG
|
||
IF_DEBUG(PRINT)
|
||
{
|
||
KdPrint(("*************CREATED PRINTER ENTRY: %ws\\%ws\n\n",
|
||
(*ppPrinter)->pszServer, (*ppPrinter)->pszQueue ));
|
||
}
|
||
#endif
|
||
|
||
(*ppPrinter)->nQueueId = nQueueId;
|
||
(*ppPrinter)->pSpoolList = NULL;
|
||
(*ppPrinter)->pNextPrinter = NwPrinterList;
|
||
NwPrinterList = *ppPrinter;
|
||
|
||
err = NO_ERROR;
|
||
}
|
||
else
|
||
{
|
||
err = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
if ( err == NO_ERROR )
|
||
return err;
|
||
|
||
ErrorExit:
|
||
|
||
if ( *phServer )
|
||
{
|
||
(VOID) NtClose( *phServer );
|
||
*phServer = NULL;
|
||
}
|
||
|
||
if ( *ppPrinter )
|
||
{
|
||
if ( (*ppPrinter)->pszServer )
|
||
{
|
||
FreeNwSplStr( (*ppPrinter)->pszServer );
|
||
}
|
||
|
||
if ( (*ppPrinter)->pszQueue )
|
||
{
|
||
FreeNwSplStr( (*ppPrinter)->pszQueue );
|
||
}
|
||
|
||
if ( (*ppPrinter)->pszUncConnection )
|
||
{
|
||
(void) NwrDeleteConnection( NULL,
|
||
(*ppPrinter)->pszUncConnection,
|
||
FALSE );
|
||
FreeNwSplStr( (*ppPrinter)->pszUncConnection );
|
||
}
|
||
|
||
FreeNwSplMem( *ppPrinter, sizeof( NWPRINTER));
|
||
*ppPrinter = NULL;
|
||
}
|
||
|
||
if ( lpRemoteName )
|
||
{
|
||
FreeNwSplMem( lpRemoteName, dwBufSize );
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
NwRemovePrinterEntry(
|
||
IN PNWPRINTER pPrinter
|
||
)
|
||
{
|
||
PNWPRINTER pCur, pPrev = NULL;
|
||
|
||
ASSERT( pPrinter->pSpoolList == NULL );
|
||
pPrinter->pSpoolList = NULL;
|
||
|
||
for ( pCur = NwPrinterList; pCur; pPrev = pCur, pCur = pCur->pNextPrinter )
|
||
{
|
||
if ( pCur == pPrinter )
|
||
{
|
||
if ( pPrev )
|
||
pPrev->pNextPrinter = pCur->pNextPrinter;
|
||
else
|
||
NwPrinterList = pCur->pNextPrinter;
|
||
break;
|
||
}
|
||
}
|
||
|
||
ASSERT( pCur );
|
||
|
||
pPrinter->pNextPrinter = NULL;
|
||
FreeNwSplStr( pPrinter->pszServer );
|
||
FreeNwSplStr( pPrinter->pszQueue );
|
||
if ( pPrinter->pszUncConnection )
|
||
{
|
||
(void) NwrDeleteConnection( NULL,
|
||
pPrinter->pszUncConnection,
|
||
FALSE );
|
||
FreeNwSplStr( pPrinter->pszUncConnection );
|
||
}
|
||
FreeNwSplMem( pPrinter, sizeof( NWPRINTER));
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
NWWKSTA_PRINTER_CONTEXT_rundown(
|
||
IN NWWKSTA_PRINTER_CONTEXT hPrinter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called by RPC when a client terminates with an
|
||
opened handle. This allows us to clean up and deallocate any context
|
||
data associated with the handle.
|
||
|
||
Arguments:
|
||
|
||
hPrinter - Supplies the opened handle
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
(void) NwrClosePrinter(&hPrinter);
|
||
}
|
||
|
||
|
||
|
||
LPWSTR
|
||
NwGetUncObjectName(
|
||
IN LPWSTR ContainerName
|
||
)
|
||
{
|
||
WORD length = 2;
|
||
WORD totalLength = (WORD) wcslen( ContainerName );
|
||
|
||
if ( totalLength < 2 )
|
||
return 0;
|
||
|
||
while ( length < totalLength )
|
||
{
|
||
if ( ContainerName[length] == L'.' )
|
||
ContainerName[length] = L'\0';
|
||
|
||
length++;
|
||
}
|
||
|
||
length = 2;
|
||
|
||
while ( length < totalLength && ContainerName[length] != L'\\' )
|
||
{
|
||
length++;
|
||
}
|
||
|
||
ContainerName[length + 2] = L'\\';
|
||
ContainerName[length + 3] = L'\\';
|
||
|
||
return (ContainerName + length + 2);
|
||
}
|
||
|