diff options
Diffstat (limited to '')
-rw-r--r-- | private/nw/svcdlls/nwwks/client/nwspl.c | 2924 |
1 files changed, 2924 insertions, 0 deletions
diff --git a/private/nw/svcdlls/nwwks/client/nwspl.c b/private/nw/svcdlls/nwwks/client/nwspl.c new file mode 100644 index 000000000..e92ad0f5e --- /dev/null +++ b/private/nw/svcdlls/nwwks/client/nwspl.c @@ -0,0 +1,2924 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + nwspl.c + +Abstract: + + This module contains the Netware print provider. + +Author: + + Yi-Hsin Sung (yihsins) 15-Apr-1993 + +Revision History: + Yi-Hsin Sung (yihsins) 15-May-1993 + Moved most of the functionality to the server side + + Ram Viswanathan (ramv) 09-Aug-1995 + Added functionality to Add and Delete Printer. + + +--*/ + +#include <stdio.h> + +#include <nwclient.h> +#include <winspool.h> +#include <winsplp.h> +#include <ntlsa.h> + +#include <nwpkstr.h> +#include <splutil.h> +#include <nwreg.h> +#include <nwspl.h> +#include <nwmisc.h> + +//------------------------------------------------------------------ +// +// Local Functions +// +//------------------------------------------------------------------ + +DWORD +InitializePortNames( + VOID +); + +VOID +NwpGetUserInfo( + LPWSTR *ppszUser, + BOOL *pfGateway +); + +DWORD +NwpGetThreadUserInfo( + LPWSTR *ppszUser, + LPWSTR *ppszUserSid +); + +DWORD +NwpGetUserNameFromSid( + PSID pUserSid, + LPWSTR *ppszUserName +); + +DWORD +NwpGetLogonUserInfo( + LPWSTR *ppszUserSid +); + +VOID +pFreeAllContexts(); + +//------------------------------------------------------------------ +// +// Global Variables +// +//------------------------------------------------------------------ + +HMODULE hmodNW = NULL; +BOOL fIsWinnt = FALSE ; +WCHAR *pszRegistryPath = NULL; +WCHAR *pszRegistryPortNames=L"PortNames"; +WCHAR szMachineName[MAX_COMPUTERNAME_LENGTH + 3]; +PNWPORT pNwFirstPort = NULL; +CRITICAL_SECTION NwSplSem; +CRITICAL_SECTION NwServiceListCriticalSection; // Used to protect linked + // list of registered services +STATIC HANDLE handleDummy; // This is a dummy handle used to + // return to the clients if we have previously + // opened the given printer successfully + // and the netware workstation service is not + // currently available. + +STATIC +PRINTPROVIDOR PrintProvidor = { OpenPrinter, + SetJob, + GetJob, + EnumJobs, + AddPrinter, // NOT SUPPORTED + DeletePrinter, // NOT SUPPORTED + SetPrinter, + GetPrinter, + EnumPrinters, + AddPrinterDriver, // NOT SUPPORTED + EnumPrinterDrivers, // NOT SUPPORTED + GetPrinterDriverW, // NOT SUPPORTED + GetPrinterDriverDirectory, // NOT SUPPORTED + DeletePrinterDriver, // NOT SUPPORTED + AddPrintProcessor, // NOT SUPPORTED + EnumPrintProcessors, // NOT SUPPORTED + GetPrintProcessorDirectory, // NOT SUPPORTED + DeletePrintProcessor, // NOT SUPPORTED + EnumPrintProcessorDatatypes,// NOT SUPPORTED + StartDocPrinter, + StartPagePrinter, // NOT SUPPORTED + WritePrinter, + EndPagePrinter, // NOT SUPPORTED + AbortPrinter, + ReadPrinter, // NOT SUPPORTED + EndDocPrinter, + AddJob, + ScheduleJob, + GetPrinterData, // NOT SUPPORTED + SetPrinterData, // NOT SUPPORTED + WaitForPrinterChange, + ClosePrinter, + AddForm, // NOT SUPPORTED + DeleteForm, // NOT SUPPORTED + GetForm, // NOT SUPPORTED + SetForm, // NOT SUPPORTED + EnumForms, // NOT SUPPORTED + EnumMonitors, // NOT SUPPORTED + EnumPorts, + AddPort, // NOT SUPPORTED + ConfigurePort, + DeletePort, + CreatePrinterIC, // NOT SUPPORTED + PlayGdiScriptOnPrinterIC, // NOT SUPPORTED + DeletePrinterIC, // NOT SUPPORTED + AddPrinterConnection, // NOT SUPPORTED + DeletePrinterConnection, // NOT SUPPORTED + PrinterMessageBox, // NOT SUPPORTED + AddMonitor, // NOT SUPPORTED + DeleteMonitor // NOT SUPPORTED +}; + + +//------------------------------------------------------------------ +// +// Initialization Functions +// +//------------------------------------------------------------------ + + +BOOL InitializeDll( + HINSTANCE hdll, + DWORD dwReason, + LPVOID lpReserved +) +{ + NT_PRODUCT_TYPE ProductType ; + + UNREFERENCED_PARAMETER( lpReserved ); + + if ( dwReason == DLL_PROCESS_ATTACH ) + { + DisableThreadLibraryCalls( hdll ); + + hmodNW = hdll; + + // + // are we a winnt machine? + // + fIsWinnt = RtlGetNtProductType(&ProductType) ? + (ProductType == NtProductWinNt) : + FALSE ; + + // + // Initialize the critical section for maintaining the registered + // service list + // + InitializeCriticalSection( &NwServiceListCriticalSection ); + } + else if ( dwReason == DLL_PROCESS_DETACH ) + { + // + // Free up memories used by the port link list + // + DeleteAllPortEntries(); + + // + // Get rid of Service List and Shutdown SAP library + // + NwTerminateServiceProvider(); + +#ifndef NT1057 + // + // Clean up shell extensions + // + NwCleanupShellExtensions(); +#endif + pFreeAllContexts(); // clean up RNR stuff + DeleteCriticalSection( &NwServiceListCriticalSection ); + } + + return TRUE; +} + + + +DWORD +InitializePortNames( + VOID +) +/*++ + +Routine Description: + + This is called by the InitializePrintProvidor to initialize the ports + names used in this providor. + +Arguments: + + None. + +Return Value: + + Returns NO_ERROR or the error that occurred. + +--*/ +{ + DWORD err; + HKEY hkeyPath; + HKEY hkeyPortNames; + + err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, + pszRegistryPath, + 0, + KEY_READ, + &hkeyPath ); + + if ( !err ) + { + err = RegOpenKeyEx( hkeyPath, + pszRegistryPortNames, + 0, + KEY_READ, + &hkeyPortNames ); + + if ( !err ) + { + DWORD i = 0; + WCHAR Buffer[MAX_PATH]; + DWORD BufferSize; + + while ( !err ) + { + BufferSize = sizeof Buffer; + + err = RegEnumValue( hkeyPortNames, + i, + Buffer, + &BufferSize, + NULL, + NULL, + NULL, + NULL ); + + if ( !err ) + CreatePortEntry( Buffer ); + + i++; + } + + /* We expect RegEnumKeyEx to return ERROR_NO_MORE_ITEMS + * when it gets to the end of the keys, so reset the status: + */ + if( err == ERROR_NO_MORE_ITEMS ) + err = NO_ERROR; + + RegCloseKey( hkeyPortNames ); + } +#if DBG + else + { + IF_DEBUG(PRINT) + KdPrint(("NWSPL [RegOpenKeyEx] (%ws) failed: Error = %d\n", + pszRegistryPortNames, err )); + } +#endif + + RegCloseKey( hkeyPath ); + } +#if DBG + else + { + IF_DEBUG(PRINT) + KdPrint(("NWSPL [RegOpenKeyEx] (%ws) failed: Error = %d\n", + pszRegistryPath, err )); + } +#endif + + return err; +} + +//------------------------------------------------------------------ +// +// Print Provider Functions supported by NetWare provider +// +//------------------------------------------------------------------ + + +BOOL +InitializePrintProvidor( + LPPRINTPROVIDOR pPrintProvidor, + DWORD cbPrintProvidor, + LPWSTR pszFullRegistryPath +) +/*++ + +Routine Description: + + This is called by the spooler subsystem to initialize the print + providor. + +Arguments: + + pPrintProvidor - Pointer to the print providor structure to be + filled in by this function + cbPrintProvidor - Count of bytes of the print providor structure + pszFullRegistryPath - Full path to the registry key of this print providor + +Return Value: + + Always TRUE. + +--*/ +{ + DWORD dwLen; + + if ( !pPrintProvidor || !pszFullRegistryPath || !*pszFullRegistryPath ) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + memcpy( pPrintProvidor, + &PrintProvidor, + min( sizeof(PRINTPROVIDOR), cbPrintProvidor) ); + + // + // Store the registry path for this print providor + // + if ( !(pszRegistryPath = AllocNwSplStr(pszFullRegistryPath)) ) + return FALSE; + + // + // Store the local machine name + // + szMachineName[0] = szMachineName[1] = L'\\'; + dwLen = MAX_COMPUTERNAME_LENGTH; + GetComputerName( szMachineName + 2, &dwLen ); + +#if DBG + IF_DEBUG(PRINT) + { + KdPrint(("NWSPL [InitializePrintProvidor] ")); + KdPrint(("RegistryPath = %ws, ComputerName = %ws\n", + pszRegistryPath, szMachineName )); + } +#endif + + InitializeCriticalSection( &NwSplSem ); + + // + // Ignore the error returned from InitializePortNames. + // The provider can still function if we cannot get all the port + // names. + // + InitializePortNames(); + + return TRUE; +} + + + +BOOL +OpenPrinterW( + LPWSTR pszPrinterName, + LPHANDLE phPrinter, + LPPRINTER_DEFAULTS pDefault +) +/*++ + +Routine Description: + + This routine retrieves a handle identifying the specified printer. + +Arguments: + + pszPrinterName - Name of the printer + phPrinter - Receives the handle that identifies the given printer + pDefault - Points to a PRINTER_DEFAULTS structure. Can be NULL. + +Return Value: + + TRUE if the function succeeds, FALSE otherwise. Use GetLastError() for + extended error information. + +--*/ +{ + DWORD err; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(( "NWSPL [OpenPrinter] Name = %ws\n", pszPrinterName )); +#endif + + UNREFERENCED_PARAMETER( pDefault ); + + if ( !pszPrinterName ) + { + SetLastError( ERROR_INVALID_NAME ); + return FALSE; + } + + RpcTryExcept + { + err = NwrOpenPrinter( NULL, + pszPrinterName, + PortKnown( pszPrinterName ), + (LPNWWKSTA_PRINTER_CONTEXT) phPrinter ); + + // + // Make sure there is a port of this name so that + // EnumPorts will return it. + // + + if ( !err ) + { + + if ( !PortExists( pszPrinterName, &err ) && !err ) + { + // + // We will ignore the errors since it is + // still OK if we can't add the port. + // BUG BUG :: Cannot delete once created,dont create + // We should not create port entry and registry entry + + if ( CreatePortEntry( pszPrinterName ) ) + CreateRegistryEntry( pszPrinterName ); + + } + + } + + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + { + if ( PortKnown( pszPrinterName )) + { + *phPrinter = &handleDummy; + err = NO_ERROR; + } + else + { + err = ERROR_INVALID_NAME; + } + } + else + { + err = NwpMapRpcError( code ); + } + } + RpcEndExcept + + if ( err ) + { + SetLastError( err ); + +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [OpenPrinter] err = %d\n", err)); +#endif + } + + return ( err == NO_ERROR ); + +} + + + +BOOL +ClosePrinter( + HANDLE hPrinter +) +/*++ + +Routine Description: + + This routine closes the given printer object. + +Arguments: + + hPrinter - Handle of the printer object + +Return Value: + + TRUE if the function succeeds, FALSE otherwise. Use GetLastError() for + extended error information. + +--*/ +{ + DWORD err; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(( "NWSPL [ClosePrinter]\n")); +#endif + + // + // Just return success if the handle is a dummy one + // + if ( hPrinter == &handleDummy ) + return TRUE; + + RpcTryExcept + { + err = NwrClosePrinter( (LPNWWKSTA_PRINTER_CONTEXT) &hPrinter ); + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + err = ERROR_INVALID_HANDLE; + else + err = NwpMapRpcError( code ); + } + RpcEndExcept + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; + +} + + + +BOOL +GetPrinter( + HANDLE hPrinter, + DWORD dwLevel, + LPBYTE pbPrinter, + DWORD cbBuf, + 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: + + TRUE if the function succeeds and FALSE otherwise. GetLastError() can be + used to retrieve extended error information. + +--*/ +{ + DWORD err; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(( "NWSPL [GetPrinter] Level = %d\n", dwLevel )); +#endif + + if ( hPrinter == &handleDummy ) + { + SetLastError( ERROR_NO_NETWORK ); + return FALSE; + } + else if ( ( dwLevel != 1 ) && ( dwLevel != 2 ) && (dwLevel != 3 )) + { + SetLastError( ERROR_INVALID_LEVEL ); + return FALSE; + } + + RpcTryExcept + { + err = NwrGetPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter, + dwLevel, + pbPrinter, + cbBuf, + pcbNeeded ); + + if ( !err ) + { + if ( dwLevel == 1 ) + MarshallUpStructure( pbPrinter, PrinterInfo1Offsets, pbPrinter); + else + MarshallUpStructure( pbPrinter, PrinterInfo2Offsets, pbPrinter); + } + + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + err = ERROR_INVALID_HANDLE; + else + err = NwpMapRpcError( code ); + } + RpcEndExcept + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; +} + + + +BOOL +SetPrinter( + HANDLE hPrinter, + DWORD dwLevel, + LPBYTE pbPrinter, + DWORD dwCommand +) +/*++ + +Routine Description: + + The routine sets the specified by pausing printing, resuming printing, or + clearing all print jobs. + +Arguments: + + hPrinter - Handle of the printer + dwLevel - Specifies the level of the structure to which pbPrinter points. + pbPrinter - Points to a buffer that supplies the PRINTER_INFO object. + dwCommand - Specifies the new printer state. + +Return Value: + + TRUE if the function succeeds and FALSE otherwise. GetLastError() can be + used to retrieve extended error information. + +--*/ +{ + DWORD err = NO_ERROR; + + UNREFERENCED_PARAMETER( pbPrinter ); + +#if DBG + IF_DEBUG(PRINT) + { + KdPrint(( "NWSPL [SetPrinter] Level = %d Command = %d\n", + dwLevel, dwCommand )); + } +#endif + + if ( hPrinter == &handleDummy ) + { + SetLastError( ERROR_NO_NETWORK ); + return FALSE; + } + + switch ( dwLevel ) + { + case 0: + case 1: + case 2: + case 3: + break; + + default: + SetLastError( ERROR_INVALID_LEVEL ); + return FALSE; + } + + RpcTryExcept + { + err = NwrSetPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter, + dwCommand ); + + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + err = ERROR_INVALID_HANDLE; + else + err = NwpMapRpcError( code ); + } + RpcEndExcept + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; +} + + + +BOOL +EnumPrintersW( + DWORD dwFlags, + LPWSTR pszName, + DWORD dwLevel, + LPBYTE pbPrinter, + DWORD cbBuf, + LPDWORD pcbNeeded, + LPDWORD pcReturned +) +/*++ + +Routine Description: + + This routine enumerates the available providers, servers, printers + depending on the given pszName. + +Arguments: + + dwFlags - Printer type requested + pszName - The name of the container object + dwLevel - The structure level requested + 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: + + TRUE if the function succeeds, FALSE otherwise. + +--*/ +{ + DWORD err = NO_ERROR; + +#if DBG + IF_DEBUG(PRINT) + { + KdPrint(("NWSPL [EnumPrinters] Flags = %d Level = %d",dwFlags,dwLevel)); + if ( pszName ) + KdPrint((" PrinterName = %ws\n", pszName )); + else + KdPrint(("\n")); + } +#endif + + if ( (dwLevel != 1) && (dwLevel != 2) ) + { + SetLastError( ERROR_INVALID_NAME ); // should be level, but winspool + // is silly. + return FALSE; + } + else if ( !pcbNeeded || !pcReturned ) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + RpcTryExcept + { + *pcReturned = 0; + *pcbNeeded = 0; + + if ( ( dwFlags & PRINTER_ENUM_NAME ) + && ( dwLevel == 1 ) + ) + { + err = NwrEnumPrinters( NULL, + pszName, + pbPrinter, + cbBuf, + pcbNeeded, + pcReturned ); + + if ( !err ) + { + DWORD i; + for ( i = 0; i < *pcReturned; i++ ) + MarshallUpStructure( pbPrinter + i*sizeof(PRINTER_INFO_1W), + PrinterInfo1Offsets, + pbPrinter ); + } + } + else + { + err = ERROR_INVALID_NAME; + } + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + err = ERROR_INVALID_NAME; + else + err = NwpMapRpcError( code ); + } + RpcEndExcept + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; +} + + + +DWORD +StartDocPrinter( + HANDLE hPrinter, + DWORD dwLevel, + LPBYTE lpbDocInfo +) +/*++ + +Routine Description: + + This routine informs the print spooler that a document is to be spooled + for printing. + +Arguments: + + hPrinter - Handle of the printer + dwLevel - Level of the structure pointed to by lpbDocInfo. Must be 1. + lpbDocInfo - Points to the DOC_INFO_1 object + +Return Value: + + TRUE if the function succeeds, FALSE otherwise. The extended error + can be retrieved through GetLastError(). + +--*/ +{ + DWORD err; + DOC_INFO_1 *pDocInfo1 = (DOC_INFO_1 *) lpbDocInfo; + LPWSTR pszUser = NULL; + BOOL fGateway = FALSE; + +#if DBG + IF_DEBUG(PRINT) + { + KdPrint(( "NWSPL [StartDocPrinter] " )); + if ( pDocInfo1 ) + { + if ( pDocInfo1->pDocName ) + KdPrint(("Document %ws", pDocInfo1->pDocName )); + if ( pDocInfo1->pOutputFile ) + KdPrint(("OutputFile %ws", pDocInfo1->pOutputFile )); + if ( pDocInfo1->pDatatype ) + KdPrint(("Datatype %ws", pDocInfo1->pDatatype )); + } + KdPrint(("\n")); + } +#endif + + if ( hPrinter == &handleDummy ) + { + SetLastError( ERROR_NO_NETWORK ); + return FALSE; + } + else if ( dwLevel != 1 ) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + // ignore the error, just use default value + NwpGetUserInfo( &pszUser, &fGateway ); + + RpcTryExcept + { + err = NwrStartDocPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter, + pDocInfo1? pDocInfo1->pDocName : NULL, + pszUser, + fGateway ); + + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + err = ERROR_INVALID_HANDLE; + else + err = NwpMapRpcError( code ); + } + RpcEndExcept + + LocalFree( pszUser ); + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; +} + + + +BOOL +WritePrinter( + HANDLE hPrinter, + LPVOID pBuf, + DWORD cbBuf, + 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: + + TRUE if it succeeds, FALSE otherwise. Use GetLastError() to get extended + error. + +--*/ +{ + DWORD err; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(( "NWSPL [WritePrinter]\n")); + + if ( hPrinter == &handleDummy ) + { + SetLastError( ERROR_NO_NETWORK ); + return FALSE; + } +#endif + + RpcTryExcept + { + err = NwrWritePrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter, + pBuf, + cbBuf, + pcbWritten ); + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + err = ERROR_INVALID_HANDLE; + else + err = NwpMapRpcError( code ); + } + RpcEndExcept + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; +} + + + +BOOL +AbortPrinter( + HANDLE 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: + + TRUE if the function succeeds, FALSE otherwise. + +--*/ +{ + DWORD err; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(( "NWSPL [AbortPrinter]\n")); + + if ( hPrinter == &handleDummy ) + { + SetLastError( ERROR_NO_NETWORK ); + return FALSE; + } +#endif + + RpcTryExcept + { + err = NwrAbortPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter ); + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + err = ERROR_INVALID_HANDLE; + else + err = NwpMapRpcError( code ); + } + RpcEndExcept + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; + +} + + + +BOOL +EndDocPrinter( + HANDLE hPrinter +) +/*++ + +Routine Description: + + This routine ends the print job for the given printer. + +Arguments: + + hPrinter - Handle of the printer object + +Return Value: + + TRUE if the function succeeds, FALSE otherwise. + +--*/ +{ + DWORD err; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(( "NWSPL [EndDocPrinter]\n")); +#endif + + if ( hPrinter == &handleDummy ) + { + SetLastError( ERROR_NO_NETWORK ); + return FALSE; + } + + RpcTryExcept + { + err = NwrEndDocPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter ); + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + err = ERROR_INVALID_HANDLE; + else + err = NwpMapRpcError( code ); + } + RpcEndExcept + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; +} + + + +BOOL +GetJob( + HANDLE hPrinter, + DWORD dwJobId, + DWORD dwLevel, + LPBYTE pbJob, + DWORD cbBuf, + LPDWORD pcbNeeded +) +/*++ + +Routine Description: + + This routine retrieves print-job data for the given printer. + +Arguments: + + hPrinter - Handle of the printer + dwJobId - Job identifition number + dwLevel - Data structure level of pbJob + pbJob - Address of data-structure array + cbBuf - Count of bytes in array + pcbNeeded - Count of bytes retrieved or required + +Return Value: + + TRUE if the function succeeds, FALSE otherwise. + +--*/ +{ + DWORD err; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [GetJob] JobId = %d Level = %d\n", dwJobId, dwLevel)); +#endif + + if ( hPrinter == &handleDummy ) + { + SetLastError( ERROR_NO_NETWORK ); + return FALSE; + } + else if (( dwLevel != 1 ) && ( dwLevel != 2 )) + { + SetLastError( ERROR_INVALID_LEVEL ); + return FALSE; + } + + RpcTryExcept + { + err = NwrGetJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter, + dwJobId, + dwLevel, + pbJob, + cbBuf, + pcbNeeded ); + + if ( !err ) + { + if ( dwLevel == 1 ) + MarshallUpStructure( pbJob, JobInfo1Offsets, pbJob ); + else + MarshallUpStructure( pbJob, JobInfo2Offsets, pbJob ); + } + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + err = ERROR_INVALID_HANDLE; + else + err = NwpMapRpcError( code ); + } + RpcEndExcept + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; + +} + + + +BOOL +EnumJobs( + HANDLE hPrinter, + DWORD dwFirstJob, + DWORD dwNoJobs, + DWORD dwLevel, + LPBYTE pbJob, + DWORD cbBuf, + LPDWORD pcbNeeded, + LPDWORD pcReturned +) +/*++ + +Routine Description: + + This routine initializes the array of JOB_INFO_1 or JOB_INFO_2 structures + with data describing the specified print jobs for the given printer. + +Arguments: + + hPrinter - Handle of the printer + dwFirstJob - Location of first job in the printer + dwNoJobs - Number of jobs to enumerate + dwLevel - Data structure level + pbJob - Address of structure array + cbBuf - Size of pbJob, in bytes + pcbNeeded - Receives the number of bytes copied or required + pcReturned - Receives the number of jobs copied + +Return Value: + + TRUE if the function succeeds, FALSE otherwise. + +--*/ +{ + DWORD err; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [EnumJobs] Level = %d FirstJob = %d NoJobs = %d\n", + dwLevel, dwFirstJob, dwNoJobs)); +#endif + + if ( hPrinter == &handleDummy ) + { + SetLastError( ERROR_NO_NETWORK ); + return FALSE; + } + else if ( ( dwLevel != 1 ) && ( dwLevel != 2 ) ) + { + SetLastError( ERROR_INVALID_LEVEL ); + return FALSE; + } + + RpcTryExcept + { + *pcReturned = 0; + *pcbNeeded = 0; + + err = NwrEnumJobs( (NWWKSTA_PRINTER_CONTEXT) hPrinter, + dwFirstJob, + dwNoJobs, + dwLevel, + pbJob, + cbBuf, + pcbNeeded, + pcReturned ); + + if ( !err ) + { + DWORD i; + DWORD cbStruct; + DWORD *pOffsets; + + if ( dwLevel == 1 ) + { + cbStruct = sizeof( JOB_INFO_1W ); + pOffsets = JobInfo1Offsets; + } + else // dwLevel == 2 + { + cbStruct = sizeof( JOB_INFO_2W ); + pOffsets = JobInfo2Offsets; + } + + for ( i = 0; i < *pcReturned; i++ ) + MarshallUpStructure( pbJob + i * cbStruct, pOffsets, pbJob ); + } + + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + err = ERROR_INVALID_HANDLE; + else + err = NwpMapRpcError( code ); + } + RpcEndExcept + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; + +} + + + +BOOL +SetJob( + HANDLE hPrinter, + DWORD dwJobId, + DWORD dwLevel, + LPBYTE pbJob, + DWORD dwCommand +) +/*++ + +Routine Description: + + This routine pauses, cancels, resumes, restarts the specified print job + in the given printer. The function can also be used to set print job + parameters such as job position, and so on. + +Arguments: + + hPrinter - Handle of the printer + dwJobId - Job indentification number + dwLevel - Data structure level + pbJob - Address of data structure + dwCommand - Specify the operation to be performed + +Return Value: + + TRUE if the function succeeds, FALSE otherwise. + +--*/ +{ + DWORD err; + +#if DBG + IF_DEBUG(PRINT) + { + KdPrint(("NWSPL [SetJob] Level = %d JobId = %d Command = %d\n", + dwLevel, dwJobId, dwCommand)); + } +#endif + + if ( hPrinter == &handleDummy ) + { + SetLastError( ERROR_NO_NETWORK ); + return FALSE; + } + else if ( ( dwLevel != 0 ) && ( dwLevel != 1 ) && ( dwLevel != 2 ) ) + { + SetLastError( ERROR_INVALID_LEVEL ); + return FALSE; + } + else if ( ( dwLevel == 0 ) && ( pbJob != NULL ) ) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + RpcTryExcept + { + NW_JOB_INFO NwJobInfo; + + if ( dwLevel == 1 ) + { + NwJobInfo.nPosition = ((LPJOB_INFO_1W) pbJob)->Position; + NwJobInfo.pUserName = ((LPJOB_INFO_1W) pbJob)->pUserName; + NwJobInfo.pDocument = ((LPJOB_INFO_1W) pbJob)->pDocument; + } + else if ( dwLevel == 2 ) + { + NwJobInfo.nPosition = ((LPJOB_INFO_2W) pbJob)->Position; + NwJobInfo.pUserName = ((LPJOB_INFO_2W) pbJob)->pUserName; + NwJobInfo.pDocument = ((LPJOB_INFO_2W) pbJob)->pDocument; + } + + err = NwrSetJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter, + dwJobId, + dwLevel, + dwLevel == 0 ? NULL : &NwJobInfo, + dwCommand ); + + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + err = ERROR_INVALID_HANDLE; + else + err = NwpMapRpcError( code ); + } + RpcEndExcept + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; + +} + + + +BOOL +AddJob( + HANDLE hPrinter, + DWORD dwLevel, + LPBYTE pbAddJob, + DWORD cbBuf, + LPDWORD pcbNeeded +) +/*++ + +Routine Description: + + This routine returns a full path and filename of a file that can be used + to store a print job. + +Arguments: + + hPrinter - Handle of the printer + dwLevel - Data structure level + pbAddJob - Points to a ADD_INFO_1 structure + cbBuf - Size of pbAddJob, in bytes + pcbNeeded - Receives the bytes copied or required + +Return Value: + + TRUE if the function succeeds, FALSE otherwise. + +--*/ +{ + DWORD err; + + ADDJOB_INFO_1W TempBuffer; + PADDJOB_INFO_1W OutputBuffer; + DWORD OutputBufferSize; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(( "NWSPL [AddJob]\n")); +#endif + + if ( hPrinter == &handleDummy ) + { + SetLastError( ERROR_NO_NETWORK ); + return FALSE; + } + else if ( dwLevel != 1 ) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + // + // The output buffer size must be at least the size of the fixed + // portion of the structure marshalled by RPC or RPC will not + // call the server-side to get the pcbNeeded. Use our own temporary + // buffer to force RPC to call the server-side if output buffer + // specified by the caller is too small. + // + if (cbBuf < sizeof(ADDJOB_INFO_1W)) { + OutputBuffer = &TempBuffer; + OutputBufferSize = sizeof(ADDJOB_INFO_1W); + } + else { + OutputBuffer = (LPADDJOB_INFO_1W) pbAddJob; + OutputBufferSize = cbBuf; + } + + RpcTryExcept + { + err = NwrAddJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter, + OutputBuffer, + OutputBufferSize, + pcbNeeded ); + + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + err = ERROR_INVALID_HANDLE; + else + err = NwpMapRpcError( code ); + } + RpcEndExcept + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; +} + + + +BOOL +ScheduleJob( + HANDLE hPrinter, + DWORD dwJobId +) +/*++ + +Routine Description: + + This routine informs the print spooler that the specified job can be + scheduled for spooling. + +Arguments: + + hPrinter - Handle of the printer + dwJobId - Job number that can be scheduled + +Return Value: + + TRUE if the function succeeds, FALSE otherwise. + +--*/ +{ + DWORD err; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(( "NWSPL [ScheduleJob] JobId = %d\n", dwJobId )); +#endif + + if ( hPrinter == &handleDummy ) + { + SetLastError( ERROR_NO_NETWORK ); + return FALSE; + } + + RpcTryExcept + { + err = NwrScheduleJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter, + dwJobId ); + + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + err = ERROR_INVALID_HANDLE; + else + err = NwpMapRpcError( code ); + } + RpcEndExcept + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; +} + + + +DWORD +WaitForPrinterChange( + HANDLE hPrinter, + DWORD dwFlags +) +/*++ + +Routine Description: + + This function returns when one or more requested changes occur on a + print server or if the function times out. + +Arguments: + + hPrinter - Handle of the printer to wait on + dwFlags - A bitmask that specifies the changes that the application + wishes to be notified of. + +Return Value: + + Return a bitmask that indicates the changes that occurred. + +--*/ +{ + DWORD err; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [WaitForPrinterChange] Flags = %d\n", dwFlags)); +#endif + + if ( hPrinter == &handleDummy ) + { + SetLastError( ERROR_NO_NETWORK ); + return 0; + } + + RpcTryExcept + { + err = NwrWaitForPrinterChange( (NWWKSTA_PRINTER_CONTEXT) hPrinter, + &dwFlags ); + + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + err = ERROR_INVALID_HANDLE; + else + err = NwpMapRpcError( code ); + } + RpcEndExcept + + if ( err ) + { + SetLastError( err ); + return 0; + } + + return dwFlags; +} + + + +BOOL +EnumPortsW( + LPWSTR pszName, + DWORD dwLevel, + LPBYTE pbPort, + DWORD cbBuf, + LPDWORD pcbNeeded, + LPDWORD pcReturned +) +/*++ + +Routine Description: + + This function enumerates the ports available for printing on a + specified server. + +Arguments: + + pszName - Name of the server to enumerate on + dwLevel - Structure level + pbPort - Address of array to receive the port information + cbBuf - Size, in bytes, of pbPort + pcbNeeded - Address to store the number of bytes needed or copied + pcReturned - Address to store the number of entries copied + +Return Value: + + TRUE if the function succeeds, FALSE otherwise. + +--*/ +{ + DWORD err = NO_ERROR; + DWORD cb = 0; + PNWPORT pNwPort; + LPPORT_INFO_1W pPortInfo1; + LPBYTE pEnd = pbPort + cbBuf; + LPBYTE pFixedDataEnd = pbPort; + BOOL FitInBuffer; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [EnumPorts]\n")); +#endif + + if ( dwLevel != 1 ) + { + SetLastError( ERROR_INVALID_NAME ); + return FALSE; + } + else if ( !IsLocalMachine( pszName ) ) + { + SetLastError( ERROR_INVALID_NAME ); + return FALSE; + } + + EnterCriticalSection( &NwSplSem ); + + pNwPort = pNwFirstPort; + while ( pNwPort ) + { + cb += sizeof(PORT_INFO_1W) + ( wcslen( pNwPort->pName)+1)*sizeof(WCHAR); + pNwPort = pNwPort->pNext; + } + + *pcbNeeded = cb; + *pcReturned = 0; + + if ( cb <= cbBuf ) + { + pEnd = pbPort + cbBuf; + + pNwPort = pNwFirstPort; + while ( pNwPort ) + { + pPortInfo1 = (LPPORT_INFO_1W) pFixedDataEnd; + pFixedDataEnd += sizeof( PORT_INFO_1W ); + + FitInBuffer = NwlibCopyStringToBuffer( pNwPort->pName, + wcslen( pNwPort->pName), + (LPCWSTR) pFixedDataEnd, + (LPWSTR *) &pEnd, + &pPortInfo1->pName ); + ASSERT( FitInBuffer ); + + pNwPort = pNwPort->pNext; + (*pcReturned)++; + } + } + else + { + err = ERROR_INSUFFICIENT_BUFFER; + } + + LeaveCriticalSection( &NwSplSem ); + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; +} + + + +BOOL +DeletePortW( + LPWSTR pszName, + HWND hWnd, + LPWSTR pszPortName +) +/*++ + +Routine Description: + + This routine deletes the port given on the server. A dialog can + be displayed if needed. + +Arguments: + + pszName - Name of the server for which the port should be deleted + hWnd - Parent window + pszPortName - The name of the port to delete + +Return Value: + + TRUE if the function succeeds, FALSE otherwise. + +--*/ +{ + DWORD err; + BOOL fPortDeleted; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [DeletePort]\n")); +#endif + + if ( !IsLocalMachine( pszName ) ) + { + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; + } + + fPortDeleted = DeletePortEntry( pszPortName ); + + if ( fPortDeleted ) + { + err = DeleteRegistryEntry( pszPortName ); + } + else + { + err = ERROR_UNKNOWN_PORT; + } + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; + +} + + + +BOOL +ConfigurePortW( + LPWSTR pszName, + HWND hWnd, + LPWSTR pszPortName +) +/*++ + +Routine Description: + + This routine displays the port configuration dialog box + for the given port on the given server. + +Arguments: + + pszName - Name of the server on which the given port exist + hWnd - Parent window + pszPortName - The name of the port to be configured + +Return Value: + + TRUE if the function succeeds, FALSE otherwise. + +--*/ +{ + DWORD nCurrentThreadId; + DWORD nWindowThreadId; + WCHAR szCaption[MAX_PATH]; + WCHAR szMessage[MAX_PATH]; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [ConfigurePort] PortName = %ws\n", pszPortName)); +#endif + + if ( !IsLocalMachine( pszName ) ) + { + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; + } + else if ( !PortKnown( pszPortName ) ) + { + SetLastError( ERROR_UNKNOWN_PORT ); + return FALSE; + } + + nCurrentThreadId = GetCurrentThreadId(); + nWindowThreadId = GetWindowThreadProcessId( hWnd, NULL ); + + if ( !AttachThreadInput( nCurrentThreadId, nWindowThreadId, TRUE )) + KdPrint(("[NWSPL] AttachThreadInput failed with %d.\n",GetLastError())); + + if ( LoadStringW( hmodNW, + IDS_NETWARE_PRINT_CAPTION, + szCaption, + sizeof( szCaption ) / sizeof( WCHAR ))) + { + if ( LoadStringW( hmodNW, + IDS_NOTHING_TO_CONFIGURE, + szMessage, + sizeof( szMessage ) / sizeof( WCHAR ))) + { + MessageBox( hWnd, szMessage, szCaption, + MB_OK | MB_ICONINFORMATION ); + } + else + { + KdPrint(("[NWSPL] LoadString failed with %d.\n",GetLastError())); + } + } + else + { + KdPrint(("[NWSPL] LoadString failed with %d.\n",GetLastError())); + } + + if ( !AttachThreadInput( nCurrentThreadId, nWindowThreadId, FALSE )) + KdPrint(("[NWSPL] DetachThreadInput failed with %d.\n",GetLastError())); + + return TRUE; +} + +//------------------------------------------------------------------ +// +// Print Provider Functions not supported by NetWare provider +// +//------------------------------------------------------------------ + +BOOL +AddPrinterConnectionW( + LPWSTR pszPrinterName +) +{ +#if DBG + IF_DEBUG(PRINT) + { + KdPrint(("NWSPL [AddPrinterConnection] PrinterName = %ws\n", + pszPrinterName)); + } +#endif + + SetLastError( ERROR_INVALID_NAME ); + return FALSE; +} + +BOOL +EnumMonitorsW( + LPWSTR pszName, + DWORD dwLevel, + LPBYTE pbMonitor, + DWORD cbBuf, + LPDWORD pcbNeeded, + LPDWORD pcReturned +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [EnumMonitors]\n")); +#endif + + SetLastError( ERROR_INVALID_NAME ); + return FALSE; +} + + +BOOL +AddPortW( + LPWSTR pszName, + HWND hWnd, + LPWSTR pszMonitorName +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [AddPort]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + + +HANDLE +AddPrinterW( + LPWSTR pszName, + DWORD dwLevel, + LPBYTE pbPrinter +) + +// Creates a print queue on the netware server and returns a handle to it +{ +#ifdef NOT_USED + +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [AddPrinterW]\n")); +#endif + + SetLastError(ERROR_NOT_SUPPORTED); + return FALSE; +#else + + LPTSTR pszPrinterName = NULL; + LPTSTR pszPServer = NULL; + LPTSTR pszQueue = NULL; + HANDLE hPrinter = NULL; + DWORD err; + PPRINTER_INFO_2 pPrinterInfo; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [AddPrinterW]\n")); +#endif + + pPrinterInfo = (PPRINTER_INFO_2)pbPrinter; + + + if (dwLevel != 2) + { + err = ERROR_INVALID_PARAMETER; + goto ErrorExit; + } + + + if (!(pszPrinterName = (LPTSTR)LocalAlloc(LPTR, (wcslen(((PRINTER_INFO_2 *)pbPrinter)->pPrinterName)+1)* sizeof(WCHAR)))) + { + err = ERROR_NOT_ENOUGH_MEMORY; + goto ErrorExit; + } + + wcscpy(pszPrinterName,pPrinterInfo->pPrinterName); + + // PrinterName is the name represented as \\server\share + //The pszPServer parameter could have multiple fields separated by semicolons + + + if ( ( !ValidateUNCName( pszPrinterName ) ) + || ( (pszQueue = wcschr( pszPrinterName + 2, L'\\')) == NULL ) + || ( pszQueue == (pszPrinterName + 2) ) + || ( *(pszQueue + 1) == L'\0' ) + ) + { + err = ERROR_INVALID_NAME; + goto ErrorExit; + } + + + +#if DBG + IF_DEBUG(PRINT) + KdPrint(( "NWSPL [AddPrinter] Name = %ws\n",pszPServer)); +#endif + + if ( pszPrinterName == NULL ) +//PrinterName is a mandatory field but not the list of PServers + { +#if DBG + IF_DEBUG(PRINT) + KdPrint(( "NWSPL [AddPrinter] Printername not supplied\n" )); +#endif + + SetLastError( ERROR_INVALID_NAME ); + goto ErrorExit; + } + + //Check to see if there is a port of the same name + // If so, abort the addprinter operation. + // This code was commented earlier + + if (PortExists(pszPrinterName, &err ) && !err ) + { +#if DBG + IF_DEBUG(PRINT) + KdPrint(( "NWSPL [AddPrinter], = %ws; Port exists with same name\n", pszPrinterName )); +#endif + SetLastError(ERROR_ALREADY_ASSIGNED); + goto ErrorExit; + } + + + // Put all the relevant information into the PRINTER_INFO_2 structure + + RpcTryExcept + { + err = NwrAddPrinter ( NULL, + (LPPRINTER_INFO_2W) pPrinterInfo, + (LPNWWKSTA_PRINTER_CONTEXT) &hPrinter + ); + if (!err) + { +#if DBG + IF_DEBUG(PRINT) + KdPrint(( "NWSPL [AddPrinter] Name = %ws\n", pszPrinterName )); +#endif + goto ErrorExit; + } + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + err = NwpMapRpcError( code ); + goto ErrorExit; + } + RpcEndExcept + if ( !pszPrinterName) + (void) LocalFree((HLOCAL)pszPrinterName); + + return hPrinter; + +ErrorExit: + if ( !pszPrinterName) + (void) LocalFree((HLOCAL)pszPrinterName); + + SetLastError( err); + return (HANDLE)0x0; + +#endif // #ifdef NOT_USED +} + +BOOL +DeletePrinter( + HANDLE hPrinter +) +{ +#ifdef NOT_USED + +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [DeletePrinter]\n")); +#endif + + SetLastError(ERROR_NOT_SUPPORTED); + return FALSE; +#else + LPWSTR pszPrinterName = NULL ; // Used to delete entry from registry + DWORD err = NO_ERROR; + DWORD DoesPortExist; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [DeletePrinter]\n")); +#endif + + pszPrinterName = (LPWSTR)LocalAlloc(LPTR,sizeof(WCHAR)*MAX_PATH); + + if(pszPrinterName == NULL) + { + err = ERROR_NOT_ENOUGH_MEMORY; + return FALSE; + } + //FIXFIX Should you delete the registry and port entries + // + // Just return success if the handle is a dummy one + // + if ( hPrinter == &handleDummy ) + { +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [DeletePrinter] Dummy handle \n")); +#endif + SetLastError(ERROR_NO_NETWORK); + return FALSE; + } + RpcTryExcept + { + + + err = NwrDeletePrinter( NULL, + // pszPrinterName, + (LPNWWKSTA_PRINTER_CONTEXT) &hPrinter ); + + } + RpcExcept(1) + { + DWORD code = RpcExceptionCode(); + + if ( code == RPC_S_SERVER_UNAVAILABLE ) + err = ERROR_INVALID_HANDLE; + else + err = NwpMapRpcError( code ); + } + RpcEndExcept + + if (!err && PortExists(pszPrinterName, &DoesPortExist) && DoesPortExist) + { + + if ( DeleteRegistryEntry (pszPrinterName)) + (void) DeletePortEntry(pszPrinterName); + + } + + + if ( err ) + SetLastError( err ); + + return err == NO_ERROR; + +#endif // #ifdef NOT_USED +} + + +BOOL +DeletePrinterConnectionW( + LPWSTR pszName +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [DeletePrinterConnection]\n")); +#endif + + SetLastError( ERROR_INVALID_NAME ); + return FALSE; +} + + +BOOL +AddPrinterDriverW( + LPWSTR pszName, + DWORD dwLevel, + LPBYTE pbPrinter +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [AddPrinterDriver]\n")); +#endif + + SetLastError( ERROR_INVALID_NAME ); + return FALSE; +} + +BOOL +EnumPrinterDriversW( + LPWSTR pszName, + LPWSTR pszEnvironment, + DWORD dwLevel, + LPBYTE pbDriverInfo, + DWORD cbBuf, + LPDWORD pcbNeeded, + LPDWORD pcReturned +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [EnumPrinterDrivers]\n")); +#endif + + SetLastError( ERROR_INVALID_NAME ); + return FALSE; +} + +BOOL +GetPrinterDriverW( + HANDLE hPrinter, + LPWSTR pszEnvironment, + DWORD dwLevel, + LPBYTE pbDriverInfo, + DWORD cbBuf, + LPDWORD pcbNeeded +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [GetPrinterDriver]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + +BOOL +GetPrinterDriverDirectoryW( + LPWSTR pszName, + LPWSTR pszEnvironment, + DWORD dwLevel, + LPBYTE pbDriverDirectory, + DWORD cbBuf, + LPDWORD pcbNeeded +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [GetPrinterDriverDirectory]\n")); +#endif + + SetLastError( ERROR_INVALID_NAME ); + return FALSE; +} + +BOOL +DeletePrinterDriverW( + LPWSTR pszName, + LPWSTR pszEnvironment, + LPWSTR pszDriverName +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [DeletePrinterDriver]\n")); +#endif + + SetLastError( ERROR_INVALID_NAME ); + return FALSE; +} + +BOOL +AddPrintProcessorW( + LPWSTR pszName, + LPWSTR pszEnvironment, + LPWSTR pszPathName, + LPWSTR pszPrintProcessorName +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [AddPrintProcessor]\n")); +#endif + + SetLastError( ERROR_INVALID_NAME ); + return FALSE; +} + +BOOL +EnumPrintProcessorsW( + LPWSTR pszName, + LPWSTR pszEnvironment, + DWORD dwLevel, + LPBYTE pbPrintProcessorInfo, + DWORD cbBuf, + LPDWORD pcbNeeded, + LPDWORD pcReturned +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [EnumPrintProcessors]\n")); +#endif + + SetLastError( ERROR_INVALID_NAME ); + return FALSE; +} + +BOOL +EnumPrintProcessorDatatypesW( + LPWSTR pszName, + LPWSTR pszPrintProcessorName, + DWORD dwLevel, + LPBYTE pbDatatypes, + DWORD cbBuf, + LPDWORD pcbNeeded, + LPDWORD pcReturned +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [EnumPrintProcessorDatatypes]\n")); +#endif + + SetLastError( ERROR_INVALID_NAME ); + return FALSE; +} + +BOOL +GetPrintProcessorDirectoryW( + LPWSTR pszName, + LPWSTR pszEnvironment, + DWORD dwLevel, + LPBYTE pbPrintProcessorDirectory, + DWORD cbBuf, + LPDWORD pcbNeeded +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [GetPrintProcessorDirectory]\n")); +#endif + + SetLastError( ERROR_INVALID_NAME ); + return FALSE; +} + +BOOL +StartPagePrinter( + HANDLE hPrinter +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [StartPagePrinter]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + +BOOL +EndPagePrinter( + HANDLE hPrinter +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [EndPagePrinter]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + +BOOL +ReadPrinter( + HANDLE hPrinter, + LPVOID pBuf, + DWORD cbBuf, + LPDWORD pcbRead +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [ReadPrinter]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + +DWORD +GetPrinterDataW( + HANDLE hPrinter, + LPWSTR pszValueName, + LPDWORD pdwType, + LPBYTE pbData, + DWORD cbBuf, + LPDWORD pcbNeeded +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [GetPrinterData]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + +DWORD +SetPrinterDataW( + HANDLE hPrinter, + LPWSTR pszValueName, + DWORD dwType, + LPBYTE pbData, + DWORD cbData +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [SetPrinterData]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + +BOOL +AddForm( + HANDLE hPrinter, + DWORD dwLevel, + LPBYTE pbForm +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [AddForm]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + +BOOL +DeleteFormW( + HANDLE hPrinter, + LPWSTR pszFormName +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [DeleteForm]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + +BOOL +GetFormW( + HANDLE hPrinter, + LPWSTR pszFormName, + DWORD dwLevel, + LPBYTE pbForm, + DWORD cbBuf, + LPDWORD pcbNeeded +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [GetForm]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + +BOOL +SetFormW( + HANDLE hPrinter, + LPWSTR pszFormName, + DWORD dwLevel, + LPBYTE pbForm +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [SetForm]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + +BOOL +EnumForms( + HANDLE hPrinter, + DWORD dwLevel, + LPBYTE pbForm, + DWORD cbBuf, + LPDWORD pcbNeeded, + LPDWORD pcReturned +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [EnumForms]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + + +HANDLE +CreatePrinterIC( + HANDLE hPrinter, + LPDEVMODE pDevMode +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [CreatePrinterIC]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + +BOOL +PlayGdiScriptOnPrinterIC( + HANDLE hPrinterIC, + LPBYTE pbIn, + DWORD cbIn, + LPBYTE pbOut, + DWORD cbOut, + DWORD ul +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [PlayGdiScriptOnPrinterIC]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + +BOOL +DeletePrinterIC( + HANDLE hPrinterIC +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [DeletePrinterIC]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + +DWORD +PrinterMessageBoxW( + HANDLE hPrinter, + DWORD dwError, + HWND hWnd, + LPWSTR pszText, + LPWSTR pszCaption, + DWORD dwType +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [PrinterMessageBox]\n")); +#endif + + SetLastError( ERROR_NOT_SUPPORTED ); + return FALSE; +} + +BOOL +AddMonitorW( + LPWSTR pszName, + DWORD dwLevel, + LPBYTE pbMonitorInfo +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [AddMonitor]\n")); +#endif + + SetLastError( ERROR_INVALID_NAME ); + return FALSE; +} + +BOOL +DeleteMonitorW( + LPWSTR pszName, + LPWSTR pszEnvironment, + LPWSTR pszMonitorName +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [DeleteMonitor]\n")); +#endif + + SetLastError( ERROR_INVALID_NAME ); + return FALSE; +} + +BOOL +DeletePrintProcessorW( + LPWSTR pszName, + LPWSTR pszEnvironment, + LPWSTR pszPrintProcessorName +) +{ +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NWSPL [DeletePrintProcessor]\n")); +#endif + + SetLastError( ERROR_INVALID_NAME ); + return FALSE; +} + +//------------------------------------------------------------------ +// +// Print Provider Miscellaneous Functions +// +//------------------------------------------------------------------ + +VOID +NwpGetUserInfo( + LPWSTR *ppszUser, + BOOL *pfGateway +) +/*++ + +Routine Description: + + Get the user information of the impersonating client. + +Arguments: + + ppszUser - A pointer to buffer to store the Unicode string if + the impersonated client's user name can be looked up + successfully. If the conversion was unsuccessful, it points + to NULL. + + pfGateway - A pointer to a boolean to store whether the user is + printing through a gateway or not. We assume that + if the user sid and the current logon user sid is not + the same, then the user is printing through gateway. + Else the user is printing locally. + +Return Value: + + None. + +--*/ +{ + DWORD err; + LPWSTR pszUserSid = NULL; + LPWSTR pszLogonUserSid = NULL; + + // + // If any error occurs while trying to get the username, just + // assume no user name and not gateway printing. + // + *pfGateway = TRUE; + *ppszUser = NULL; + + if ( ((err = NwpGetThreadUserInfo( ppszUser, &pszUserSid )) == NO_ERROR) + && ((err = NwpGetLogonUserInfo( &pszLogonUserSid )) == NO_ERROR) + ) + { + if ( _wcsicmp( pszUserSid, pszLogonUserSid ) == 0 ) + *pfGateway = FALSE; + +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NwpGetUserInfo: Thread User= %ws, Thread SID = %ws,\nCurrent SID = %ws fGateway = %d\n", + *ppszUser, pszUserSid, pszLogonUserSid, *pfGateway )); +#endif + + LocalFree( pszUserSid ); + LocalFree( pszLogonUserSid ); + } + +} + +#define SIZE_OF_TOKEN_INFORMATION \ + sizeof( TOKEN_USER ) \ + + sizeof( SID ) \ + + sizeof( ULONG ) * SID_MAX_SUB_AUTHORITIES + +DWORD +NwpGetThreadUserInfo( + LPWSTR *ppszUser, + LPWSTR *ppszUserSid +) +/*++ + +Routine Description: + + Get the user name and user sid string of the impersonating client. + +Arguments: + + ppszUser - A pointer to buffer to store the Unicode string + if the impersonated client's can be looked up. If the + lookup was unsuccessful, it points to NULL. + + ppszUserSid - A pointer to buffer to store the string if the impersonated + client's SID can be expanded successfully into unicode string. + If the conversion was unsuccessful, it points to NULL. + +Return Value: + + The error code. + +--*/ +{ + DWORD err; + HANDLE TokenHandle; + UCHAR TokenInformation[ SIZE_OF_TOKEN_INFORMATION ]; + ULONG ReturnLength; + + *ppszUser = NULL; + *ppszUserSid = NULL; + + // We can use OpenThreadToken because this server thread + // is impersonating a client + + if ( !OpenThreadToken( GetCurrentThread(), + TOKEN_READ, + TRUE, /* Open as self */ + &TokenHandle )) + { +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NwpGetThreadUserInfo: OpenThreadToken failed: Error %d\n", + GetLastError())); +#endif + return(GetLastError()); + } + + // notice that we've allocated enough space for the + // TokenInformation structure. so if we fail, we + // return a NULL pointer indicating failure + + + if ( !GetTokenInformation( TokenHandle, + TokenUser, + TokenInformation, + sizeof( TokenInformation ), + &ReturnLength )) + { +#if DBG + IF_DEBUG(PRINT) + KdPrint(("NwpGetThreadUserInfo: GetTokenInformation failed: Error %d\n", + GetLastError())); +#endif + return(GetLastError()); + } + + CloseHandle( TokenHandle ); + + // convert the Sid (pointed to by pSid) to its + // equivalent Unicode string representation. + + err = NwpGetUserNameFromSid( ((PTOKEN_USER)TokenInformation)->User.Sid, + ppszUser ); + err = err? err : NwpConvertSid( ((PTOKEN_USER)TokenInformation)->User.Sid, + ppszUserSid ); + + if ( err ) + { + if ( *ppszUser ) + LocalFree( *ppszUser ); + + if ( *ppszUserSid ) + LocalFree( *ppszUserSid ); + } + + return err; +} + +DWORD +NwpGetUserNameFromSid( + PSID pUserSid, + LPWSTR *ppszUserName +) +/*++ + +Routine Description: + + Lookup the user name given the user SID. + +Arguments: + + pUserSid - Points to the user sid to be looked up + + ppszUserName - A pointer to buffer to store the string if the impersonated + client's SID can be expanded successfully into unicode string. + If the conversion was unsuccessful, it points to NULL. + +Return Value: + + The error code. + +--*/ +{ + NTSTATUS ntstatus; + + LSA_HANDLE hlsa; + OBJECT_ATTRIBUTES oa; + SECURITY_QUALITY_OF_SERVICE sqos; + PLSA_REFERENCED_DOMAIN_LIST plsardl = NULL; + PLSA_TRANSLATED_NAME plsatn = NULL; + + sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); + sqos.ImpersonationLevel = SecurityImpersonation; + sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; + sqos.EffectiveOnly = FALSE; + InitializeObjectAttributes( &oa, NULL, 0L, NULL, NULL ); + oa.SecurityQualityOfService = &sqos; + + ntstatus = LsaOpenPolicy( NULL, + &oa, + POLICY_LOOKUP_NAMES, + &hlsa ); + + if ( NT_SUCCESS( ntstatus )) + { + ntstatus = LsaLookupSids( hlsa, + 1, + &pUserSid, + &plsardl, + &plsatn ); + + if ( NT_SUCCESS( ntstatus )) + { + UNICODE_STRING *pUnicodeStr = &((*plsatn).Name); + + *ppszUserName = LocalAlloc( LMEM_ZEROINIT, + pUnicodeStr->Length+sizeof(WCHAR)); + + if ( *ppszUserName != NULL ) + { + memcpy( *ppszUserName, pUnicodeStr->Buffer, pUnicodeStr->Length ); + } + else + { + ntstatus = STATUS_NO_MEMORY; + } + + LsaFreeMemory( plsardl ); + LsaFreeMemory( plsatn ); + } +#if DBG + else + { + KdPrint(("NwpGetUserNameFromSid: LsaLookupSids failed: Error = %d\n", + GetLastError())); + } +#endif + + LsaClose( hlsa ); + } +#if DBG + else + { + KdPrint(("NwpGetUserNameFromSid: LsaOpenPolicy failed: Error = %d\n", + GetLastError())); + } +#endif + + return RtlNtStatusToDosError( ntstatus ); + +} + +DWORD +NwpGetLogonUserInfo( + LPWSTR *ppszUserSid +) +/*++ + +Routine Description: + + Get the logon user sid string from the registry. + +Arguments: + + ppszUserSid - On return, this points to the current logon user + sid string. + +Return Value: + + The error code. + +--*/ +{ + DWORD err; + HKEY WkstaKey; + + LPWSTR CurrentUser = NULL; + + // + // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services + // \NWCWorkstation\Parameters to get the sid of the CurrentUser + // + err = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + NW_WORKSTATION_REGKEY, + REG_OPTION_NON_VOLATILE, + KEY_READ, + &WkstaKey + ); + + if ( err == NO_ERROR) { + + // + // Read the current user SID string so that we + // know which key is the current user key to open. + // + err = NwReadRegValue( + WkstaKey, + NW_CURRENTUSER_VALUENAME, + &CurrentUser + ); + + RegCloseKey( WkstaKey ); + + if ( err == NO_ERROR) { + *ppszUserSid = CurrentUser; + } + } + + return(err); +} |