Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

740 lines
23 KiB

  1. /*++
  2. Copyright (c) 1991-1993 Microsoft Corporation
  3. Module Name:
  4. PrtQ.c
  5. Abstract:
  6. This module implements the print queue APIs to remote machines using
  7. the Remote Admin Protocol. In addition to the usual downlevel usage, this
  8. protocol is also used for the NT-to-NT print APIs.
  9. Author:
  10. John Rogers (JohnRo) 16-May-1991
  11. Environment:
  12. Portable to any flat, 32-bit environment. (Uses Win32 typedefs.)
  13. Requires ANSI C extensions: slash-slash comments, long external names.
  14. Notes:
  15. All of the RxPrint APIs are wide-character APIs, regardless of
  16. whether or not UNICODE is defined. This allows the net/dosprint/dosprint.c
  17. code to use the winspool APIs (which are currently ANSI APIs, despite their
  18. prototypes using LPTSTR in some places).
  19. Revision History:
  20. 16-May-1991 JohnRo
  21. Initial version.
  22. 17-Jun-1991 JohnRo
  23. Added RxPrintQ{Continue,Pause,Purge}. Added module header.
  24. 15-Jul-1991 JohnRo
  25. Added RxPrintQ{Add,Del,Enum,SetInfo}.
  26. 16-Jul-1991 JohnRo
  27. Estimate bytes needed for print APIs.
  28. 17-Jul-1991 JohnRo
  29. Extracted RxpDebug.h from Rxp.h.
  30. 21-Nov-1991 JohnRo
  31. Removed NT dependencies to reduce recompiles.
  32. 07-Jun-1992 JohnRo
  33. RAID 10324: net print vs. UNICODE.
  34. RAID 7243: Avoid 64KB requests (Winball servers only HAVE 64KB!)
  35. Use PREFIX_ equates.
  36. 11-May-1993 JohnRo
  37. RAID 9942: workaround Windows For Workgroups (WFW) bug in DosPrintQEnum,
  38. when level=0 and multiple queues exist.
  39. 18-May-1993 JohnRo
  40. RAID 10222: DosPrintQGetInfoW underestimates number of bytes needed.
  41. --*/
  42. #ifndef UNICODE
  43. #error "RxPrint APIs assume RxRemoteApi uses wide characters."
  44. #endif
  45. // These must be included first:
  46. #include <windows.h> // IN, LPWSTR, etc.
  47. #include <lmcons.h> // NET_API_STATUS, etc.
  48. // These may be included in any order:
  49. #include <apinums.h> // API_ equates.
  50. #include <lmerr.h> // NERR_ and ERROR_ equates.
  51. #include <names.h> // NetpIsUncComputerNameValid(), etc.
  52. #include <netdebug.h> // NetpAssert().
  53. #include <netlib.h> // NetpSetOptionalArg().
  54. #include <prefix.h> // PREFIX_ equates.
  55. #include <remdef.h> // REM16_, REM32_, REMSmb_, field index equates.
  56. #include <rx.h> // RxRemoteApi().
  57. #include <rxp.h> // RxpEstimatedBytesNeeded(). MAX_TRANSACT_ equates.
  58. #include <rxpdebug.h> // IF_DEBUG().
  59. #include <rxprint.h> // My prototypes, some PRQ_ equates.
  60. #include <strucinf.h> // NetpPrintQStructureInfo().
  61. DBGSTATIC NET_API_STATUS
  62. RxpGetPrintQInfoDescs(
  63. IN DWORD InfoLevel,
  64. IN BOOL AddOrSet,
  65. OUT LPDESC * DataDesc16 OPTIONAL,
  66. OUT LPDESC * DataDesc32 OPTIONAL,
  67. OUT LPDESC * DataDescSmb OPTIONAL,
  68. OUT LPDESC * AuxDesc16 OPTIONAL,
  69. OUT LPDESC * AuxDesc32 OPTIONAL,
  70. OUT LPDESC * AuxDescSmb OPTIONAL
  71. )
  72. {
  73. switch (InfoLevel) {
  74. case 0 :
  75. if (AddOrSet) {
  76. return (ERROR_INVALID_LEVEL);
  77. }
  78. NetpSetOptionalArg(AuxDesc16, NULL);
  79. NetpSetOptionalArg(AuxDesc32, NULL);
  80. NetpSetOptionalArg(AuxDescSmb, NULL);
  81. NetpSetOptionalArg(DataDesc16, REM16_printQ_0);
  82. NetpSetOptionalArg(DataDesc32, REM32_printQ_0);
  83. NetpSetOptionalArg(DataDescSmb, REMSmb_printQ_0);
  84. return (NERR_Success);
  85. case 1 :
  86. NetpSetOptionalArg(AuxDesc16, NULL);
  87. NetpSetOptionalArg(AuxDesc32, NULL);
  88. NetpSetOptionalArg(AuxDescSmb, NULL);
  89. NetpSetOptionalArg(DataDesc16, REM16_printQ_1);
  90. NetpSetOptionalArg(DataDesc32, REM32_printQ_1);
  91. NetpSetOptionalArg(DataDescSmb, REMSmb_printQ_1);
  92. return (NERR_Success);
  93. case 2 :
  94. if (AddOrSet) {
  95. return (ERROR_INVALID_LEVEL);
  96. }
  97. NetpSetOptionalArg(AuxDesc16, REM16_print_job_1);
  98. NetpSetOptionalArg(AuxDesc32, REM32_print_job_1);
  99. NetpSetOptionalArg(AuxDescSmb, REMSmb_print_job_1);
  100. NetpSetOptionalArg(DataDesc16, REM16_printQ_2);
  101. NetpSetOptionalArg(DataDesc32, REM32_printQ_2);
  102. NetpSetOptionalArg(DataDescSmb, REMSmb_printQ_2);
  103. return (NERR_Success);
  104. case 3 :
  105. NetpSetOptionalArg(AuxDesc16, NULL);
  106. NetpSetOptionalArg(AuxDesc32, NULL);
  107. NetpSetOptionalArg(AuxDescSmb, NULL);
  108. NetpSetOptionalArg(DataDesc16, REM16_printQ_3);
  109. NetpSetOptionalArg(DataDesc32, REM32_printQ_3);
  110. NetpSetOptionalArg(DataDescSmb, REMSmb_printQ_3);
  111. return (NERR_Success);
  112. case 4 :
  113. if (AddOrSet) {
  114. return (ERROR_INVALID_LEVEL);
  115. }
  116. NetpSetOptionalArg(AuxDesc16, REM16_print_job_2);
  117. NetpSetOptionalArg(AuxDesc32, REM32_print_job_2);
  118. NetpSetOptionalArg(AuxDescSmb, REMSmb_print_job_2);
  119. NetpSetOptionalArg(DataDesc16, REM16_printQ_4);
  120. NetpSetOptionalArg(DataDesc32, REM32_printQ_4);
  121. NetpSetOptionalArg(DataDescSmb, REMSmb_printQ_4);
  122. return (NERR_Success);
  123. case 5 :
  124. if (AddOrSet) {
  125. return (ERROR_INVALID_LEVEL);
  126. }
  127. NetpSetOptionalArg(AuxDesc16, NULL);
  128. NetpSetOptionalArg(AuxDesc32, NULL);
  129. NetpSetOptionalArg(AuxDescSmb, NULL);
  130. NetpSetOptionalArg(DataDesc16, REM16_printQ_5);
  131. NetpSetOptionalArg(DataDesc32, REM32_printQ_5);
  132. NetpSetOptionalArg(DataDescSmb, REMSmb_printQ_5);
  133. return (NERR_Success);
  134. default :
  135. return (ERROR_INVALID_LEVEL);
  136. }
  137. /* NOTREACHED */
  138. } // RxpGetPrintQInfoDescs
  139. SPLERR SPLENTRY
  140. RxPrintQAdd(
  141. IN LPWSTR UncServerName,
  142. IN DWORD Level,
  143. IN LPBYTE Buffer,
  144. IN DWORD BufferSize
  145. )
  146. {
  147. LPDESC AuxDesc16, AuxDesc32, AuxDescSmb;
  148. LPDESC DataDesc16, DataDesc32, DataDescSmb;
  149. NET_API_STATUS Status;
  150. Status = RxpGetPrintQInfoDescs(
  151. Level,
  152. TRUE, // this is an add or set API.
  153. & DataDesc16,
  154. & DataDesc32,
  155. & DataDescSmb,
  156. & AuxDesc16,
  157. & AuxDesc32,
  158. & AuxDescSmb);
  159. if (Status != NERR_Success) {
  160. return (Status);
  161. }
  162. return (RxRemoteApi(
  163. API_WPrintQAdd, // API number
  164. (LPTSTR) UncServerName,
  165. REMSmb_DosPrintQAdd_P, // parm desc
  166. DataDesc16,
  167. DataDesc32,
  168. DataDescSmb,
  169. AuxDesc16,
  170. AuxDesc32,
  171. AuxDescSmb,
  172. FALSE, // not a null session API
  173. // rest of API's arguments, in 32-bit LM2.x format:
  174. Level,
  175. Buffer,
  176. BufferSize));
  177. } // RxPrintQAdd
  178. SPLERR SPLENTRY
  179. RxPrintQContinue(
  180. IN LPWSTR UncServerName,
  181. IN LPWSTR QueueName
  182. )
  183. {
  184. return (RxRemoteApi(
  185. API_WPrintQContinue, // API number
  186. (LPTSTR) UncServerName,
  187. REMSmb_DosPrintQContinue_P, // parm desc
  188. NULL, // no data desc 16
  189. NULL, // no data desc 32
  190. NULL, // no data desc SMB
  191. NULL, // no aux desc 16
  192. NULL, // no aux desc 32
  193. NULL, // no aux desc SMB
  194. FALSE, // not a null session API
  195. // rest of API's arguments, in 32-bit LM2.x format:
  196. QueueName));
  197. } // RxPrintQContinue
  198. SPLERR SPLENTRY
  199. RxPrintQDel(
  200. IN LPWSTR UncServerName,
  201. IN LPWSTR QueueName
  202. )
  203. {
  204. return (RxRemoteApi(
  205. API_WPrintQDel, // API number
  206. (LPTSTR) UncServerName,
  207. REMSmb_DosPrintQDel_P, // parm desc
  208. NULL, // no data desc 16
  209. NULL, // no data desc 32
  210. NULL, // no data desc SMB
  211. NULL, // no aux desc 16
  212. NULL, // no aux desc 32
  213. NULL, // no aux desc SMB
  214. FALSE, // not a null session API
  215. // rest of API's arguments, in 32-bit LM2.x format:
  216. QueueName));
  217. } // RxPrintQDel
  218. SPLERR SPLENTRY
  219. RxPrintQEnum(
  220. IN LPWSTR UncServerName,
  221. IN DWORD Level,
  222. OUT LPBYTE Buffer,
  223. IN DWORD BufferSize,
  224. OUT LPDWORD EntriesRead,
  225. OUT LPDWORD EntriesAvail
  226. )
  227. {
  228. DWORD ActualEntries = 0;
  229. LPDESC AuxDesc16, AuxDesc32, AuxDescSmb;
  230. LPDESC DataDesc16, DataDesc32, DataDescSmb;
  231. DWORD SafeEntries;
  232. LPVOID SafeLevelBuffer = NULL;
  233. NET_API_STATUS Status;
  234. Status = RxpGetPrintQInfoDescs(
  235. Level,
  236. FALSE, // this is not an add or set API.
  237. & DataDesc16,
  238. & DataDesc32,
  239. & DataDescSmb,
  240. & AuxDesc16,
  241. & AuxDesc32,
  242. & AuxDescSmb);
  243. if (Status != NERR_Success) {
  244. return (Status);
  245. }
  246. //
  247. // Assume normal call, on assumption that we won't run into WFW 3.1
  248. //
  249. Status = RxRemoteApi(
  250. API_WPrintQEnum, // API number
  251. (LPTSTR) UncServerName,
  252. REMSmb_DosPrintQEnum_P, // parm desc
  253. DataDesc16,
  254. DataDesc32,
  255. DataDescSmb,
  256. AuxDesc16,
  257. AuxDesc32,
  258. AuxDescSmb,
  259. 0, // flags: not a null session API
  260. // rest of API's arguments, in 32-bit LM2.x format:
  261. Level,
  262. Buffer,
  263. BufferSize,
  264. &ActualEntries,
  265. EntriesAvail);
  266. //
  267. // Check for a nasty WFW 3.1 bug: for level 0, with multiple queues,
  268. // one or more queue names are garbage. (I've seen garbage "zzzzWWzzl"
  269. // come back, in particular.) If we might have gotten this,
  270. // then retry with a safe info level. Since level 0 is just short queue
  271. // names, and level 1 is a superset of that, we can make one from the other.
  272. //
  273. if ( (!RxpFatalErrorCode(Status))
  274. && (Level == 0)
  275. && (ActualEntries > 1 ) ) {
  276. LPCTSTR OutEntry = (LPVOID) Buffer;
  277. DWORD SafeAvail;
  278. PPRQINFO SafeEntry;
  279. const DWORD SafeLevel = 1;
  280. DWORD SafeLevelEntrySize;
  281. DWORD SafeLevelBufferSize;
  282. RetryTheApi:
  283. //
  284. // Avoid pointer faults below if caller's buffer isn't large enough.
  285. //
  286. if ( (ActualEntries * (LM20_QNLEN+1) * sizeof(TCHAR)) > BufferSize ) {
  287. Status = NERR_BufTooSmall;
  288. goto Cleanup;
  289. }
  290. //
  291. // Compute area needed for safe array, and allocate it.
  292. //
  293. (VOID) NetpPrintQStructureInfo(
  294. SafeLevel,
  295. PARMNUM_ALL,
  296. TRUE, // Yes, we need native size
  297. FALSE, // not add or setinfo API
  298. sizeof(TCHAR), // size of chars wanted
  299. NULL, // don't need DataDesc16 OPTIONAL,
  300. NULL, // don't need DataDesc32 OPTIONAL,
  301. NULL, // don't need DataDescSmb OPTIONAL,
  302. NULL, // don't need AuxDesc16 OPTIONAL,
  303. NULL, // don't need AuxDesc32 OPTIONAL,
  304. NULL, // don't need AuxDescSmb OPTIONAL,
  305. &SafeLevelEntrySize, // need max size
  306. NULL, // don't need size of fixed part
  307. NULL ); // don't need size of string area
  308. NetpAssert( SafeLevelEntrySize > 0 );
  309. SafeLevelBufferSize = ActualEntries * SafeLevelEntrySize;
  310. NetpAssert( SafeLevelBufferSize > 0 );
  311. SafeLevelBuffer = NetpMemoryAllocate( SafeLevelBufferSize );
  312. if (SafeLevelBuffer == NULL) {
  313. Status = ERROR_NOT_ENOUGH_MEMORY;
  314. goto Cleanup;
  315. }
  316. //
  317. // Do recursive call, to get queues at safe info level.
  318. //
  319. Status = RxPrintQEnum(
  320. UncServerName,
  321. SafeLevel, // level we want
  322. SafeLevelBuffer, // buffer to fill in
  323. SafeLevelBufferSize,
  324. &SafeEntries,
  325. &SafeAvail );
  326. if ( Status == ERROR_MORE_DATA) {
  327. if (SafeLevelBuffer != NULL) {
  328. NetpMemoryFree( SafeLevelBuffer );
  329. }
  330. SafeLevelBuffer = NULL;
  331. if (SafeAvail > ActualEntries) {
  332. // Retry if queue was added.
  333. ActualEntries = SafeAvail;
  334. goto RetryTheApi;
  335. } else {
  336. // Not enough information to know what to do differently.
  337. NetpKdPrint(( PREFIX_NETAPI
  338. "RxPrintQEnum: WFW workaround failed, error more data "
  339. "but should have been enough!\n" ));
  340. Status = NERR_InternalError;
  341. goto Cleanup;
  342. }
  343. }
  344. if ( RxpFatalErrorCode( Status ) ) {
  345. NetpKdPrint(( PREFIX_NETAPI
  346. "RxPrintQEnum: WFW workaround failed, API status="
  347. FORMAT_API_STATUS ".\n", Status ));
  348. goto Cleanup;
  349. }
  350. if (SafeEntries==0) {
  351. // Deleted them all of a sudden? OK, I guess.
  352. ActualEntries = 0;
  353. goto Cleanup;
  354. }
  355. //
  356. // Convert safe info level to desired info level.
  357. //
  358. ActualEntries = 0;
  359. SafeEntry = (LPVOID) SafeLevelBuffer;
  360. do {
  361. LPCTSTR SafeQueueName;
  362. SafeQueueName = SafeEntry->szName;
  363. NetpAssert( SafeQueueName != NULL );
  364. if ( (*SafeQueueName) == TCHAR_EOS) {
  365. NetpKdPrint(( PREFIX_NETAPI
  366. "RxPrintQEnum: WFW workaround failed, got empty "
  367. "queue name anyway.\n" ));
  368. Status = NERR_InternalError;
  369. goto Cleanup;
  370. }
  371. if ( STRLEN( SafeQueueName ) < LM20_QNLEN ) {
  372. if (NetpIsPrintQueueNameValid( SafeQueueName ) ) {
  373. // Hey, it's short and valid. Copy it over.
  374. (VOID) STRCPY(
  375. (LPTSTR) OutEntry, // dest
  376. (LPTSTR) SafeQueueName ); // src
  377. OutEntry += (LM20_QNLEN+1);
  378. ++ActualEntries;
  379. } else {
  380. NetpKdPrint(( PREFIX_NETAPI
  381. "RxPrintQEnum: WFW workaround failed, got bad "
  382. "queue name anyway.\n" ));
  383. Status = NERR_InternalError;
  384. goto Cleanup;
  385. }
  386. }
  387. --SafeEntries;
  388. ++SafeEntry;
  389. } while (SafeEntries > 0);
  390. }
  391. Cleanup:
  392. NetpSetOptionalArg( EntriesRead, ActualEntries );
  393. if (SafeLevelBuffer != NULL) {
  394. NetpMemoryFree( SafeLevelBuffer );
  395. }
  396. return (Status);
  397. } // RxPrintQEnum
  398. SPLERR SPLENTRY
  399. RxPrintQGetInfo(
  400. IN LPWSTR UncServerName,
  401. IN LPWSTR QueueName,
  402. IN DWORD Level,
  403. OUT LPBYTE Buffer,
  404. IN DWORD BufferSize,
  405. OUT LPDWORD BytesNeeded // estimated (probably too large).
  406. )
  407. {
  408. LPDESC AuxDesc16, AuxDesc32, AuxDescSmb;
  409. LPDESC DataDesc16, DataDesc32, DataDescSmb;
  410. DWORD BytesNeeded16;
  411. DWORD EdittedBufferSize;
  412. NET_API_STATUS Status;
  413. NetpAssert(UncServerName != NULL);
  414. NetpAssert(*UncServerName != '\0');
  415. Status = RxpGetPrintQInfoDescs(
  416. Level,
  417. FALSE, // not an add or set API.
  418. & DataDesc16,
  419. & DataDesc32,
  420. & DataDescSmb,
  421. & AuxDesc16,
  422. & AuxDesc32,
  423. & AuxDescSmb);
  424. if (Status != NERR_Success) {
  425. return (Status);
  426. }
  427. NetpAssert( DataDesc16 != NULL );
  428. NetpAssert( DataDesc32 != NULL );
  429. NetpAssert( DataDescSmb != NULL );
  430. if (BufferSize <= MAX_TRANSACT_RET_DATA_SIZE) {
  431. EdittedBufferSize = BufferSize;
  432. } else {
  433. EdittedBufferSize = MAX_TRANSACT_RET_DATA_SIZE;
  434. }
  435. Status = RxRemoteApi(
  436. API_WPrintQGetInfo,
  437. (LPTSTR) UncServerName,
  438. REMSmb_DosPrintQGetInfo_P,
  439. DataDesc16,
  440. DataDesc32,
  441. DataDescSmb,
  442. AuxDesc16,
  443. AuxDesc32,
  444. AuxDescSmb,
  445. FALSE, // not a null session API.
  446. // rest of API's arguments in LM 2.x format:
  447. QueueName,
  448. Level,
  449. Buffer,
  450. EdittedBufferSize,
  451. & BytesNeeded16); // downlevel buffer size needed.
  452. // If ERROR_MORE_DATA, convert BytesNeeded to native num.
  453. if ( (Status == ERROR_MORE_DATA) || (Status == NERR_BufTooSmall) ) {
  454. *BytesNeeded = RxpEstimateBytesNeeded(BytesNeeded16);
  455. } else {
  456. *BytesNeeded = BufferSize;
  457. }
  458. IF_DEBUG(PRTQ) {
  459. NetpKdPrint(( PREFIX_NETAPI "RxPrintQGetInfo: returned, status is "
  460. FORMAT_API_STATUS "\n", Status));
  461. }
  462. // Return results of RxRemoteApi call.
  463. return (Status);
  464. } // RxPrintQGetInfo
  465. SPLERR SPLENTRY
  466. RxPrintQPause(
  467. IN LPWSTR UncServerName,
  468. IN LPWSTR QueueName
  469. )
  470. {
  471. return (RxRemoteApi(
  472. API_WPrintQPause, // API number
  473. (LPTSTR) UncServerName,
  474. REMSmb_DosPrintQPause_P, // parm desc
  475. NULL, // no data desc 16
  476. NULL, // no data desc 32
  477. NULL, // no data desc SMB
  478. NULL, // no aux desc 16
  479. NULL, // no aux desc 32
  480. NULL, // no aux desc SMB
  481. FALSE, // not a null session API
  482. // rest of API's arguments, in 32-bit LM2.x format:
  483. QueueName));
  484. } // RxPrintQPause
  485. SPLERR SPLENTRY
  486. RxPrintQPurge(
  487. IN LPWSTR UncServerName,
  488. IN LPWSTR QueueName
  489. )
  490. {
  491. return (RxRemoteApi(
  492. API_WPrintQPurge, // API number
  493. (LPTSTR) UncServerName,
  494. REMSmb_DosPrintQPurge_P, // parm desc
  495. NULL, // no data desc 16
  496. NULL, // no data desc 32
  497. NULL, // no data desc SMB
  498. NULL, // no aux desc 16
  499. NULL, // no aux desc 32
  500. NULL, // no aux desc SMB
  501. FALSE, // not a null session API
  502. // rest of API's arguments, in 32-bit LM2.x format:
  503. QueueName));
  504. } // RxPrintQPurge
  505. SPLERR SPLENTRY
  506. RxPrintQSetInfo(
  507. IN LPWSTR UncServerName,
  508. IN LPWSTR QueueName,
  509. IN DWORD Level,
  510. IN LPBYTE Buffer,
  511. IN DWORD BufferSize,
  512. IN DWORD ParmNum
  513. )
  514. {
  515. LPDESC AuxDesc16, AuxDesc32, AuxDescSmb;
  516. LPDESC DataDesc16, DataDesc32, DataDescSmb;
  517. NET_API_STATUS Status;
  518. NetpAssert(UncServerName != NULL);
  519. NetpAssert(*UncServerName != '\0');
  520. Status = RxpGetPrintQInfoDescs(
  521. Level,
  522. TRUE, // This is a setinfo API.
  523. & DataDesc16,
  524. & DataDesc32,
  525. & DataDescSmb,
  526. & AuxDesc16,
  527. & AuxDesc32,
  528. & AuxDescSmb);
  529. if (Status != NERR_Success) {
  530. return (Status);
  531. }
  532. if (ParmNum == PARMNUM_ALL) {
  533. Status = RxRemoteApi(
  534. API_WPrintQSetInfo, // API number
  535. (LPTSTR) UncServerName,
  536. REMSmb_DosPrintQSetInfo_P, // parm desc
  537. DataDesc16,
  538. DataDesc32,
  539. DataDescSmb,
  540. AuxDesc16,
  541. AuxDesc32,
  542. AuxDescSmb,
  543. FALSE, // not a null session API
  544. // rest of API's arguments, in 32-bit LM 2.x format:
  545. QueueName,
  546. Level,
  547. Buffer,
  548. BufferSize,
  549. ParmNum);
  550. } else {
  551. DWORD FieldIndex;
  552. // Compute field index from parmnum and level.
  553. NetpAssert( (Level==1) || (Level==3) ); // Already verified.
  554. switch (ParmNum) {
  555. case PRQ_PRIORITY_PARMNUM :
  556. if (Level==1) {
  557. FieldIndex = PRQ_PRIORITY_LVL1_FIELDINDEX;
  558. } else {
  559. FieldIndex = PRQ_PRIORITY_LVL3_FIELDINDEX;
  560. }
  561. break;
  562. case PRQ_STARTTIME_PARMNUM :
  563. if (Level==1) {
  564. FieldIndex = PRQ_STARTTIME_LVL1_FIELDINDEX;
  565. } else {
  566. FieldIndex = PRQ_STARTTIME_LVL3_FIELDINDEX;
  567. }
  568. break;
  569. case PRQ_UNTILTIME_PARMNUM :
  570. if (Level==1) {
  571. FieldIndex = PRQ_UNTILTIME_LVL1_FIELDINDEX;
  572. } else {
  573. FieldIndex = PRQ_UNTILTIME_LVL3_FIELDINDEX;
  574. }
  575. break;
  576. case PRQ_SEPARATOR_PARMNUM :
  577. if (Level==1) {
  578. FieldIndex = PRQ_SEPARATOR_LVL1_FIELDINDEX;
  579. } else {
  580. FieldIndex = PRQ_SEPARATOR_LVL3_FIELDINDEX;
  581. }
  582. break;
  583. case PRQ_PROCESSOR_PARMNUM :
  584. if (Level==1) {
  585. FieldIndex = PRQ_PROCESSOR_LVL1_FIELDINDEX;
  586. } else {
  587. FieldIndex = PRQ_PROCESSOR_LVL3_FIELDINDEX;
  588. }
  589. break;
  590. case PRQ_DESTINATIONS_PARMNUM :
  591. if (Level==1) {
  592. FieldIndex = PRQ_DESTINATIONS_LVL1_FIELDINDEX;
  593. } else {
  594. return (ERROR_INVALID_LEVEL);
  595. }
  596. break;
  597. case PRQ_PARMS_PARMNUM :
  598. if (Level==1) {
  599. FieldIndex = PRQ_PARMS_LVL1_FIELDINDEX;
  600. } else {
  601. FieldIndex = PRQ_PARMS_LVL3_FIELDINDEX;
  602. }
  603. break;
  604. case PRQ_COMMENT_PARMNUM :
  605. if (Level==1) {
  606. FieldIndex = PRQ_COMMENT_LVL1_FIELDINDEX;
  607. } else {
  608. FieldIndex = PRQ_COMMENT_LVL3_FIELDINDEX;
  609. }
  610. break;
  611. case PRQ_PRINTERS_PARMNUM :
  612. if (Level==1) {
  613. return (ERROR_INVALID_LEVEL);
  614. } else {
  615. FieldIndex = PRQ_PRINTERS_LVL3_FIELDINDEX;
  616. }
  617. break;
  618. case PRQ_DRIVERDATA_PARMNUM :
  619. // Can't set driver data from NT
  620. /* FALLTHROUGH */
  621. default :
  622. IF_DEBUG(PRTQ) {
  623. NetpKdPrint(( PREFIX_NETAPI
  624. "RxPrintQSetInfo: invalid (bad parmnum).\n" ));
  625. }
  626. return (ERROR_INVALID_PARAMETER);
  627. }
  628. Status = RxpSetField (
  629. API_WPrintQSetInfo, // API number
  630. UncServerName,
  631. "z", // object's desc
  632. QueueName, // object to set
  633. REMSmb_DosPrintQSetInfo_P, // parm desc
  634. DataDesc16,
  635. DataDesc32,
  636. DataDescSmb,
  637. (LPVOID) Buffer, // native info buffer
  638. ParmNum, // parm num to send
  639. FieldIndex, // field index
  640. Level);
  641. }
  642. return (Status);
  643. } // RxPrintQSetInfo