windows-nt/Source/XPSP1/NT/ds/netapi/rpcxlate/rxapi/prtq.c
2020-09-26 16:20:57 +08:00

741 lines
22 KiB
C

/*++
Copyright (c) 1991-1993 Microsoft Corporation
Module Name:
PrtQ.c
Abstract:
This module implements the print queue APIs to remote machines using
the Remote Admin Protocol. In addition to the usual downlevel usage, this
protocol is also used for the NT-to-NT print APIs.
Author:
John Rogers (JohnRo) 16-May-1991
Environment:
Portable to any flat, 32-bit environment. (Uses Win32 typedefs.)
Requires ANSI C extensions: slash-slash comments, long external names.
Notes:
All of the RxPrint APIs are wide-character APIs, regardless of
whether or not UNICODE is defined. This allows the net/dosprint/dosprint.c
code to use the winspool APIs (which are currently ANSI APIs, despite their
prototypes using LPTSTR in some places).
Revision History:
16-May-1991 JohnRo
Initial version.
17-Jun-1991 JohnRo
Added RxPrintQ{Continue,Pause,Purge}. Added module header.
15-Jul-1991 JohnRo
Added RxPrintQ{Add,Del,Enum,SetInfo}.
16-Jul-1991 JohnRo
Estimate bytes needed for print APIs.
17-Jul-1991 JohnRo
Extracted RxpDebug.h from Rxp.h.
21-Nov-1991 JohnRo
Removed NT dependencies to reduce recompiles.
07-Jun-1992 JohnRo
RAID 10324: net print vs. UNICODE.
RAID 7243: Avoid 64KB requests (Winball servers only HAVE 64KB!)
Use PREFIX_ equates.
11-May-1993 JohnRo
RAID 9942: workaround Windows For Workgroups (WFW) bug in DosPrintQEnum,
when level=0 and multiple queues exist.
18-May-1993 JohnRo
RAID 10222: DosPrintQGetInfoW underestimates number of bytes needed.
--*/
#ifndef UNICODE
#error "RxPrint APIs assume RxRemoteApi uses wide characters."
#endif
// These must be included first:
#include <windows.h> // IN, LPWSTR, etc.
#include <lmcons.h> // NET_API_STATUS, etc.
// These may be included in any order:
#include <apinums.h> // API_ equates.
#include <lmerr.h> // NERR_ and ERROR_ equates.
#include <names.h> // NetpIsUncComputerNameValid(), etc.
#include <netdebug.h> // NetpAssert().
#include <netlib.h> // NetpSetOptionalArg().
#include <prefix.h> // PREFIX_ equates.
#include <remdef.h> // REM16_, REM32_, REMSmb_, field index equates.
#include <rx.h> // RxRemoteApi().
#include <rxp.h> // RxpEstimatedBytesNeeded(). MAX_TRANSACT_ equates.
#include <rxpdebug.h> // IF_DEBUG().
#include <rxprint.h> // My prototypes, some PRQ_ equates.
#include <strucinf.h> // NetpPrintQStructureInfo().
DBGSTATIC NET_API_STATUS
RxpGetPrintQInfoDescs(
IN DWORD InfoLevel,
IN BOOL AddOrSet,
OUT LPDESC * DataDesc16 OPTIONAL,
OUT LPDESC * DataDesc32 OPTIONAL,
OUT LPDESC * DataDescSmb OPTIONAL,
OUT LPDESC * AuxDesc16 OPTIONAL,
OUT LPDESC * AuxDesc32 OPTIONAL,
OUT LPDESC * AuxDescSmb OPTIONAL
)
{
switch (InfoLevel) {
case 0 :
if (AddOrSet) {
return (ERROR_INVALID_LEVEL);
}
NetpSetOptionalArg(AuxDesc16, NULL);
NetpSetOptionalArg(AuxDesc32, NULL);
NetpSetOptionalArg(AuxDescSmb, NULL);
NetpSetOptionalArg(DataDesc16, REM16_printQ_0);
NetpSetOptionalArg(DataDesc32, REM32_printQ_0);
NetpSetOptionalArg(DataDescSmb, REMSmb_printQ_0);
return (NERR_Success);
case 1 :
NetpSetOptionalArg(AuxDesc16, NULL);
NetpSetOptionalArg(AuxDesc32, NULL);
NetpSetOptionalArg(AuxDescSmb, NULL);
NetpSetOptionalArg(DataDesc16, REM16_printQ_1);
NetpSetOptionalArg(DataDesc32, REM32_printQ_1);
NetpSetOptionalArg(DataDescSmb, REMSmb_printQ_1);
return (NERR_Success);
case 2 :
if (AddOrSet) {
return (ERROR_INVALID_LEVEL);
}
NetpSetOptionalArg(AuxDesc16, REM16_print_job_1);
NetpSetOptionalArg(AuxDesc32, REM32_print_job_1);
NetpSetOptionalArg(AuxDescSmb, REMSmb_print_job_1);
NetpSetOptionalArg(DataDesc16, REM16_printQ_2);
NetpSetOptionalArg(DataDesc32, REM32_printQ_2);
NetpSetOptionalArg(DataDescSmb, REMSmb_printQ_2);
return (NERR_Success);
case 3 :
NetpSetOptionalArg(AuxDesc16, NULL);
NetpSetOptionalArg(AuxDesc32, NULL);
NetpSetOptionalArg(AuxDescSmb, NULL);
NetpSetOptionalArg(DataDesc16, REM16_printQ_3);
NetpSetOptionalArg(DataDesc32, REM32_printQ_3);
NetpSetOptionalArg(DataDescSmb, REMSmb_printQ_3);
return (NERR_Success);
case 4 :
if (AddOrSet) {
return (ERROR_INVALID_LEVEL);
}
NetpSetOptionalArg(AuxDesc16, REM16_print_job_2);
NetpSetOptionalArg(AuxDesc32, REM32_print_job_2);
NetpSetOptionalArg(AuxDescSmb, REMSmb_print_job_2);
NetpSetOptionalArg(DataDesc16, REM16_printQ_4);
NetpSetOptionalArg(DataDesc32, REM32_printQ_4);
NetpSetOptionalArg(DataDescSmb, REMSmb_printQ_4);
return (NERR_Success);
case 5 :
if (AddOrSet) {
return (ERROR_INVALID_LEVEL);
}
NetpSetOptionalArg(AuxDesc16, NULL);
NetpSetOptionalArg(AuxDesc32, NULL);
NetpSetOptionalArg(AuxDescSmb, NULL);
NetpSetOptionalArg(DataDesc16, REM16_printQ_5);
NetpSetOptionalArg(DataDesc32, REM32_printQ_5);
NetpSetOptionalArg(DataDescSmb, REMSmb_printQ_5);
return (NERR_Success);
default :
return (ERROR_INVALID_LEVEL);
}
/* NOTREACHED */
} // RxpGetPrintQInfoDescs
SPLERR SPLENTRY
RxPrintQAdd(
IN LPWSTR UncServerName,
IN DWORD Level,
IN LPBYTE Buffer,
IN DWORD BufferSize
)
{
LPDESC AuxDesc16, AuxDesc32, AuxDescSmb;
LPDESC DataDesc16, DataDesc32, DataDescSmb;
NET_API_STATUS Status;
Status = RxpGetPrintQInfoDescs(
Level,
TRUE, // this is an add or set API.
& DataDesc16,
& DataDesc32,
& DataDescSmb,
& AuxDesc16,
& AuxDesc32,
& AuxDescSmb);
if (Status != NERR_Success) {
return (Status);
}
return (RxRemoteApi(
API_WPrintQAdd, // API number
(LPTSTR) UncServerName,
REMSmb_DosPrintQAdd_P, // parm desc
DataDesc16,
DataDesc32,
DataDescSmb,
AuxDesc16,
AuxDesc32,
AuxDescSmb,
FALSE, // not a null session API
// rest of API's arguments, in 32-bit LM2.x format:
Level,
Buffer,
BufferSize));
} // RxPrintQAdd
SPLERR SPLENTRY
RxPrintQContinue(
IN LPWSTR UncServerName,
IN LPWSTR QueueName
)
{
return (RxRemoteApi(
API_WPrintQContinue, // API number
(LPTSTR) UncServerName,
REMSmb_DosPrintQContinue_P, // parm desc
NULL, // no data desc 16
NULL, // no data desc 32
NULL, // no data desc SMB
NULL, // no aux desc 16
NULL, // no aux desc 32
NULL, // no aux desc SMB
FALSE, // not a null session API
// rest of API's arguments, in 32-bit LM2.x format:
QueueName));
} // RxPrintQContinue
SPLERR SPLENTRY
RxPrintQDel(
IN LPWSTR UncServerName,
IN LPWSTR QueueName
)
{
return (RxRemoteApi(
API_WPrintQDel, // API number
(LPTSTR) UncServerName,
REMSmb_DosPrintQDel_P, // parm desc
NULL, // no data desc 16
NULL, // no data desc 32
NULL, // no data desc SMB
NULL, // no aux desc 16
NULL, // no aux desc 32
NULL, // no aux desc SMB
FALSE, // not a null session API
// rest of API's arguments, in 32-bit LM2.x format:
QueueName));
} // RxPrintQDel
SPLERR SPLENTRY
RxPrintQEnum(
IN LPWSTR UncServerName,
IN DWORD Level,
OUT LPBYTE Buffer,
IN DWORD BufferSize,
OUT LPDWORD EntriesRead,
OUT LPDWORD EntriesAvail
)
{
DWORD ActualEntries = 0;
LPDESC AuxDesc16, AuxDesc32, AuxDescSmb;
LPDESC DataDesc16, DataDesc32, DataDescSmb;
DWORD SafeEntries;
LPVOID SafeLevelBuffer = NULL;
NET_API_STATUS Status;
Status = RxpGetPrintQInfoDescs(
Level,
FALSE, // this is not an add or set API.
& DataDesc16,
& DataDesc32,
& DataDescSmb,
& AuxDesc16,
& AuxDesc32,
& AuxDescSmb);
if (Status != NERR_Success) {
return (Status);
}
//
// Assume normal call, on assumption that we won't run into WFW 3.1
//
Status = RxRemoteApi(
API_WPrintQEnum, // API number
(LPTSTR) UncServerName,
REMSmb_DosPrintQEnum_P, // parm desc
DataDesc16,
DataDesc32,
DataDescSmb,
AuxDesc16,
AuxDesc32,
AuxDescSmb,
0, // flags: not a null session API
// rest of API's arguments, in 32-bit LM2.x format:
Level,
Buffer,
BufferSize,
&ActualEntries,
EntriesAvail);
//
// Check for a nasty WFW 3.1 bug: for level 0, with multiple queues,
// one or more queue names are garbage. (I've seen garbage "zzzzWWzzl"
// come back, in particular.) If we might have gotten this,
// then retry with a safe info level. Since level 0 is just short queue
// names, and level 1 is a superset of that, we can make one from the other.
//
if ( (!RxpFatalErrorCode(Status))
&& (Level == 0)
&& (ActualEntries > 1 ) ) {
LPCTSTR OutEntry = (LPVOID) Buffer;
DWORD SafeAvail;
PPRQINFO SafeEntry;
const DWORD SafeLevel = 1;
DWORD SafeLevelEntrySize;
DWORD SafeLevelBufferSize;
RetryTheApi:
//
// Avoid pointer faults below if caller's buffer isn't large enough.
//
if ( (ActualEntries * (LM20_QNLEN+1) * sizeof(TCHAR)) > BufferSize ) {
Status = NERR_BufTooSmall;
goto Cleanup;
}
//
// Compute area needed for safe array, and allocate it.
//
(VOID) NetpPrintQStructureInfo(
SafeLevel,
PARMNUM_ALL,
TRUE, // Yes, we need native size
FALSE, // not add or setinfo API
sizeof(TCHAR), // size of chars wanted
NULL, // don't need DataDesc16 OPTIONAL,
NULL, // don't need DataDesc32 OPTIONAL,
NULL, // don't need DataDescSmb OPTIONAL,
NULL, // don't need AuxDesc16 OPTIONAL,
NULL, // don't need AuxDesc32 OPTIONAL,
NULL, // don't need AuxDescSmb OPTIONAL,
&SafeLevelEntrySize, // need max size
NULL, // don't need size of fixed part
NULL ); // don't need size of string area
NetpAssert( SafeLevelEntrySize > 0 );
SafeLevelBufferSize = ActualEntries * SafeLevelEntrySize;
NetpAssert( SafeLevelBufferSize > 0 );
SafeLevelBuffer = NetpMemoryAllocate( SafeLevelBufferSize );
if (SafeLevelBuffer == NULL) {
Status = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
//
// Do recursive call, to get queues at safe info level.
//
Status = RxPrintQEnum(
UncServerName,
SafeLevel, // level we want
SafeLevelBuffer, // buffer to fill in
SafeLevelBufferSize,
&SafeEntries,
&SafeAvail );
if ( Status == ERROR_MORE_DATA) {
if (SafeLevelBuffer != NULL) {
NetpMemoryFree( SafeLevelBuffer );
}
SafeLevelBuffer = NULL;
if (SafeAvail > ActualEntries) {
// Retry if queue was added.
ActualEntries = SafeAvail;
goto RetryTheApi;
} else {
// Not enough information to know what to do differently.
NetpKdPrint(( PREFIX_NETAPI
"RxPrintQEnum: WFW workaround failed, error more data "
"but should have been enough!\n" ));
Status = NERR_InternalError;
goto Cleanup;
}
}
if ( RxpFatalErrorCode( Status ) ) {
NetpKdPrint(( PREFIX_NETAPI
"RxPrintQEnum: WFW workaround failed, API status="
FORMAT_API_STATUS ".\n", Status ));
goto Cleanup;
}
if (SafeEntries==0) {
// Deleted them all of a sudden? OK, I guess.
ActualEntries = 0;
goto Cleanup;
}
//
// Convert safe info level to desired info level.
//
ActualEntries = 0;
SafeEntry = (LPVOID) SafeLevelBuffer;
do {
LPCTSTR SafeQueueName;
SafeQueueName = SafeEntry->szName;
NetpAssert( SafeQueueName != NULL );
if ( (*SafeQueueName) == TCHAR_EOS) {
NetpKdPrint(( PREFIX_NETAPI
"RxPrintQEnum: WFW workaround failed, got empty "
"queue name anyway.\n" ));
Status = NERR_InternalError;
goto Cleanup;
}
if ( STRLEN( SafeQueueName ) < LM20_QNLEN ) {
if (NetpIsPrintQueueNameValid( SafeQueueName ) ) {
// Hey, it's short and valid. Copy it over.
(VOID) STRCPY(
(LPTSTR) OutEntry, // dest
(LPTSTR) SafeQueueName ); // src
OutEntry += (LM20_QNLEN+1);
++ActualEntries;
} else {
NetpKdPrint(( PREFIX_NETAPI
"RxPrintQEnum: WFW workaround failed, got bad "
"queue name anyway.\n" ));
Status = NERR_InternalError;
goto Cleanup;
}
}
--SafeEntries;
++SafeEntry;
} while (SafeEntries > 0);
}
Cleanup:
NetpSetOptionalArg( EntriesRead, ActualEntries );
if (SafeLevelBuffer != NULL) {
NetpMemoryFree( SafeLevelBuffer );
}
return (Status);
} // RxPrintQEnum
SPLERR SPLENTRY
RxPrintQGetInfo(
IN LPWSTR UncServerName,
IN LPWSTR QueueName,
IN DWORD Level,
OUT LPBYTE Buffer,
IN DWORD BufferSize,
OUT LPDWORD BytesNeeded // estimated (probably too large).
)
{
LPDESC AuxDesc16, AuxDesc32, AuxDescSmb;
LPDESC DataDesc16, DataDesc32, DataDescSmb;
DWORD BytesNeeded16;
DWORD EdittedBufferSize;
NET_API_STATUS Status;
NetpAssert(UncServerName != NULL);
NetpAssert(*UncServerName != '\0');
Status = RxpGetPrintQInfoDescs(
Level,
FALSE, // not an add or set API.
& DataDesc16,
& DataDesc32,
& DataDescSmb,
& AuxDesc16,
& AuxDesc32,
& AuxDescSmb);
if (Status != NERR_Success) {
return (Status);
}
NetpAssert( DataDesc16 != NULL );
NetpAssert( DataDesc32 != NULL );
NetpAssert( DataDescSmb != NULL );
if (BufferSize <= MAX_TRANSACT_RET_DATA_SIZE) {
EdittedBufferSize = BufferSize;
} else {
EdittedBufferSize = MAX_TRANSACT_RET_DATA_SIZE;
}
Status = RxRemoteApi(
API_WPrintQGetInfo,
(LPTSTR) UncServerName,
REMSmb_DosPrintQGetInfo_P,
DataDesc16,
DataDesc32,
DataDescSmb,
AuxDesc16,
AuxDesc32,
AuxDescSmb,
FALSE, // not a null session API.
// rest of API's arguments in LM 2.x format:
QueueName,
Level,
Buffer,
EdittedBufferSize,
& BytesNeeded16); // downlevel buffer size needed.
// If ERROR_MORE_DATA, convert BytesNeeded to native num.
if ( (Status == ERROR_MORE_DATA) || (Status == NERR_BufTooSmall) ) {
*BytesNeeded = RxpEstimateBytesNeeded(BytesNeeded16);
} else {
*BytesNeeded = BufferSize;
}
IF_DEBUG(PRTQ) {
NetpKdPrint(( PREFIX_NETAPI "RxPrintQGetInfo: returned, status is "
FORMAT_API_STATUS "\n", Status));
}
// Return results of RxRemoteApi call.
return (Status);
} // RxPrintQGetInfo
SPLERR SPLENTRY
RxPrintQPause(
IN LPWSTR UncServerName,
IN LPWSTR QueueName
)
{
return (RxRemoteApi(
API_WPrintQPause, // API number
(LPTSTR) UncServerName,
REMSmb_DosPrintQPause_P, // parm desc
NULL, // no data desc 16
NULL, // no data desc 32
NULL, // no data desc SMB
NULL, // no aux desc 16
NULL, // no aux desc 32
NULL, // no aux desc SMB
FALSE, // not a null session API
// rest of API's arguments, in 32-bit LM2.x format:
QueueName));
} // RxPrintQPause
SPLERR SPLENTRY
RxPrintQPurge(
IN LPWSTR UncServerName,
IN LPWSTR QueueName
)
{
return (RxRemoteApi(
API_WPrintQPurge, // API number
(LPTSTR) UncServerName,
REMSmb_DosPrintQPurge_P, // parm desc
NULL, // no data desc 16
NULL, // no data desc 32
NULL, // no data desc SMB
NULL, // no aux desc 16
NULL, // no aux desc 32
NULL, // no aux desc SMB
FALSE, // not a null session API
// rest of API's arguments, in 32-bit LM2.x format:
QueueName));
} // RxPrintQPurge
SPLERR SPLENTRY
RxPrintQSetInfo(
IN LPWSTR UncServerName,
IN LPWSTR QueueName,
IN DWORD Level,
IN LPBYTE Buffer,
IN DWORD BufferSize,
IN DWORD ParmNum
)
{
LPDESC AuxDesc16, AuxDesc32, AuxDescSmb;
LPDESC DataDesc16, DataDesc32, DataDescSmb;
NET_API_STATUS Status;
NetpAssert(UncServerName != NULL);
NetpAssert(*UncServerName != '\0');
Status = RxpGetPrintQInfoDescs(
Level,
TRUE, // This is a setinfo API.
& DataDesc16,
& DataDesc32,
& DataDescSmb,
& AuxDesc16,
& AuxDesc32,
& AuxDescSmb);
if (Status != NERR_Success) {
return (Status);
}
if (ParmNum == PARMNUM_ALL) {
Status = RxRemoteApi(
API_WPrintQSetInfo, // API number
(LPTSTR) UncServerName,
REMSmb_DosPrintQSetInfo_P, // parm desc
DataDesc16,
DataDesc32,
DataDescSmb,
AuxDesc16,
AuxDesc32,
AuxDescSmb,
FALSE, // not a null session API
// rest of API's arguments, in 32-bit LM 2.x format:
QueueName,
Level,
Buffer,
BufferSize,
ParmNum);
} else {
DWORD FieldIndex;
// Compute field index from parmnum and level.
NetpAssert( (Level==1) || (Level==3) ); // Already verified.
switch (ParmNum) {
case PRQ_PRIORITY_PARMNUM :
if (Level==1) {
FieldIndex = PRQ_PRIORITY_LVL1_FIELDINDEX;
} else {
FieldIndex = PRQ_PRIORITY_LVL3_FIELDINDEX;
}
break;
case PRQ_STARTTIME_PARMNUM :
if (Level==1) {
FieldIndex = PRQ_STARTTIME_LVL1_FIELDINDEX;
} else {
FieldIndex = PRQ_STARTTIME_LVL3_FIELDINDEX;
}
break;
case PRQ_UNTILTIME_PARMNUM :
if (Level==1) {
FieldIndex = PRQ_UNTILTIME_LVL1_FIELDINDEX;
} else {
FieldIndex = PRQ_UNTILTIME_LVL3_FIELDINDEX;
}
break;
case PRQ_SEPARATOR_PARMNUM :
if (Level==1) {
FieldIndex = PRQ_SEPARATOR_LVL1_FIELDINDEX;
} else {
FieldIndex = PRQ_SEPARATOR_LVL3_FIELDINDEX;
}
break;
case PRQ_PROCESSOR_PARMNUM :
if (Level==1) {
FieldIndex = PRQ_PROCESSOR_LVL1_FIELDINDEX;
} else {
FieldIndex = PRQ_PROCESSOR_LVL3_FIELDINDEX;
}
break;
case PRQ_DESTINATIONS_PARMNUM :
if (Level==1) {
FieldIndex = PRQ_DESTINATIONS_LVL1_FIELDINDEX;
} else {
return (ERROR_INVALID_LEVEL);
}
break;
case PRQ_PARMS_PARMNUM :
if (Level==1) {
FieldIndex = PRQ_PARMS_LVL1_FIELDINDEX;
} else {
FieldIndex = PRQ_PARMS_LVL3_FIELDINDEX;
}
break;
case PRQ_COMMENT_PARMNUM :
if (Level==1) {
FieldIndex = PRQ_COMMENT_LVL1_FIELDINDEX;
} else {
FieldIndex = PRQ_COMMENT_LVL3_FIELDINDEX;
}
break;
case PRQ_PRINTERS_PARMNUM :
if (Level==1) {
return (ERROR_INVALID_LEVEL);
} else {
FieldIndex = PRQ_PRINTERS_LVL3_FIELDINDEX;
}
break;
case PRQ_DRIVERDATA_PARMNUM :
// Can't set driver data from NT
/* FALLTHROUGH */
default :
IF_DEBUG(PRTQ) {
NetpKdPrint(( PREFIX_NETAPI
"RxPrintQSetInfo: invalid (bad parmnum).\n" ));
}
return (ERROR_INVALID_PARAMETER);
}
Status = RxpSetField (
API_WPrintQSetInfo, // API number
UncServerName,
"z", // object's desc
QueueName, // object to set
REMSmb_DosPrintQSetInfo_P, // parm desc
DataDesc16,
DataDesc32,
DataDescSmb,
(LPVOID) Buffer, // native info buffer
ParmNum, // parm num to send
FieldIndex, // field index
Level);
}
return (Status);
} // RxPrintQSetInfo