Source code of Windows XP (NT5)
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.

1939 lines
53 KiB

  1. /*++
  2. Copyright (c) 1991-1993 Microsoft Corporation
  3. Module Name:
  4. queue.c
  5. Abstract:
  6. This module contains the support routines for the queue APIs that call
  7. into the NetWare redirector
  8. Author:
  9. Yi-Hsin Sung (yihsins) 24-Apr-1993
  10. Revision History:
  11. --*/
  12. #include <nw.h>
  13. #include <nwxchg.h>
  14. #include <nwapi.h>
  15. #include <nwreg.h>
  16. #include <queue.h>
  17. #include <splutil.h>
  18. //-------------------------------------------------------------------//
  19. // //
  20. // Local Function Prototypes //
  21. // //
  22. //-------------------------------------------------------------------//
  23. DWORD
  24. NwWriteJobInfoEntry(
  25. IN OUT LPBYTE *FixedPortion,
  26. IN OUT LPWSTR *EndOfVariableData,
  27. IN DWORD Level,
  28. IN WORD JobId,
  29. IN LPWSTR PrinterName,
  30. IN LPWSTR JobDescription,
  31. IN LPWSTR UserName,
  32. IN BYTE JobControlFlags,
  33. IN BYTE JobPosition,
  34. IN LPBYTE JobEntryTime,
  35. IN JOBTIME TargetExecutionTime,
  36. IN DWORD FileSize
  37. );
  38. DWORD
  39. ConvertToSystemTime(
  40. IN JOBTIME JobTime,
  41. OUT LPSYSTEMTIME pSystemTime
  42. );
  43. //-------------------------------------------------------------------//
  44. // //
  45. // Global variables //
  46. // //
  47. //-------------------------------------------------------------------//
  48. #define NW_RDR_SERVER_PREFIX L"\\Device\\Nwrdr\\"
  49. #define QF_USER_HOLD 0x40
  50. #define QF_OPERATOR_HOLD 0x80
  51. //
  52. // Stores the current user's print control options
  53. //
  54. //DWORD NwPrintOption = NW_PRINT_OPTION_DEFAULT; - Commented out for multi-user code merge. We don't use global flag anymore
  55. // The print option is passed from the client for each user
  56. // Default Print Control Flags: Suppress form
  57. // feed, banner on, notify on
  58. DWORD NwGatewayPrintOption = NW_GATEWAY_PRINT_OPTION_DEFAULT;
  59. // Gateway default print control flags:
  60. // Suppress form feed, banner on, notify off
  61. DWORD
  62. NwAttachToNetwareServer(
  63. IN LPWSTR ServerName,
  64. OUT LPHANDLE phandleServer
  65. )
  66. /*++
  67. Routine Description:
  68. This routine opens a handle to the given server.
  69. Arguments:
  70. ServerName - The server name to attach to.
  71. phandleServer - Receives an opened handle to the preferred or
  72. nearest server.
  73. Return Value:
  74. NO_ERROR or reason for failure.
  75. --*/
  76. {
  77. NTSTATUS ntstatus;
  78. IO_STATUS_BLOCK IoStatusBlock;
  79. OBJECT_ATTRIBUTES ObjectAttributes;
  80. LPWSTR FullName;
  81. UNICODE_STRING UServerName;
  82. FullName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
  83. (UINT) ( wcslen( NW_RDR_SERVER_PREFIX) +
  84. wcslen( ServerName ) - 1) *
  85. sizeof(WCHAR)
  86. );
  87. if ( FullName == NULL ) {
  88. return ERROR_NOT_ENOUGH_MEMORY;
  89. }
  90. wcscpy( FullName, NW_RDR_SERVER_PREFIX );
  91. wcscat( FullName, ServerName + 2 ); // Skip past the prefix "\\"
  92. RtlInitUnicodeString( &UServerName, FullName );
  93. InitializeObjectAttributes(
  94. &ObjectAttributes,
  95. &UServerName,
  96. OBJ_CASE_INSENSITIVE,
  97. NULL,
  98. NULL
  99. );
  100. //
  101. // Open a handle to the preferred server.
  102. //
  103. ntstatus = NtOpenFile(
  104. phandleServer,
  105. SYNCHRONIZE | GENERIC_WRITE,
  106. &ObjectAttributes,
  107. &IoStatusBlock,
  108. FILE_SHARE_VALID_FLAGS,
  109. FILE_SYNCHRONOUS_IO_NONALERT
  110. );
  111. if ( NT_SUCCESS(ntstatus)) {
  112. ntstatus = IoStatusBlock.Status;
  113. }
  114. if (! NT_SUCCESS(ntstatus)) {
  115. *phandleServer = NULL;
  116. }
  117. LocalFree( FullName );
  118. return RtlNtStatusToDosError(ntstatus);
  119. }
  120. DWORD
  121. NwGetNextQueueEntry(
  122. IN HANDLE PreferredServer,
  123. IN OUT LPDWORD LastObjectId,
  124. OUT LPSTR QueueName
  125. )
  126. /*++
  127. Routine Description:
  128. This function uses an opened handle to the preferred server to
  129. scan it bindery for all print queue objects.
  130. Arguments:
  131. PreferredServer - Supplies the handle to the preferred server on
  132. which to scan the bindery.
  133. LastObjectId - On input, supplies the object ID to the last print
  134. queue object returned, which is the resume handle to get the
  135. next print queue object. On output, receives the object ID
  136. of the print queue object returned.
  137. QueueName - Receives the name of the returned print queue object.
  138. Return Value:
  139. NO_ERROR - Successfully gotten a print name.
  140. WN_NO_MORE_ENTRIES - No other print queue object past the one
  141. specified by LastObjectId.
  142. --*/
  143. {
  144. NTSTATUS ntstatus;
  145. WORD ObjectType;
  146. #if DBG
  147. IF_DEBUG(ENUM) {
  148. KdPrint(("NWWORKSTATION: NwGetNextQueueEntry LastObjectId %lu\n",
  149. *LastObjectId));
  150. }
  151. #endif
  152. ntstatus = NwlibMakeNcp(
  153. PreferredServer,
  154. FSCTL_NWR_NCP_E3H, // Bindery function
  155. 58, // Max request packet size
  156. 59, // Max response packet size
  157. "bdwp|dwc", // Format string
  158. 0x37, // Scan bindery object
  159. *LastObjectId, // Previous ID
  160. 0x3, // Print Queue object
  161. "*", // Wildcard to match all
  162. LastObjectId, // Current ID
  163. &ObjectType, // Ignore
  164. QueueName // Currently returned print queue
  165. );
  166. //
  167. // Unmap Japanese special chars
  168. //
  169. UnmapSpecialJapaneseChars(QueueName,(WORD)lstrlenA(QueueName));
  170. #if DBG
  171. if ( NT_SUCCESS(ntstatus)) {
  172. IF_DEBUG(ENUM) {
  173. KdPrint(("NWWORKSTATION: NwGetNextQueueEntry NewObjectId %08lx, QueueName %s\n", *LastObjectId, QueueName));
  174. }
  175. }
  176. #endif
  177. return NwMapBinderyCompletionCode(ntstatus);
  178. }
  179. DWORD
  180. NwGetQueueId(
  181. IN HANDLE handleServer,
  182. IN LPWSTR QueueName,
  183. OUT LPDWORD QueueId
  184. )
  185. /*++
  186. Routine Description:
  187. This function opens a handle to the server and scan its bindery
  188. for the given queue object id.
  189. Arguments:
  190. handleServer - Supplies the handle of the server on which to
  191. scan the bindery.
  192. QueueName - Supplies the name of the print queue.
  193. QueueId - On output, supplies the object ID of the given queue.
  194. Return Value:
  195. NO_ERROR - Successfully gotten a file server name.
  196. --*/
  197. {
  198. NTSTATUS ntstatus;
  199. UNICODE_STRING UQueueName;
  200. OEM_STRING OemQueueName;
  201. #if DBG
  202. IF_DEBUG(QUEUE) {
  203. KdPrint(("NWWORKSTATION: NwGetQueueId %ws\n",
  204. QueueName ));
  205. }
  206. #endif
  207. RtlInitUnicodeString( &UQueueName, QueueName);
  208. ntstatus = RtlUnicodeStringToOemString( &OemQueueName, &UQueueName, TRUE);
  209. //
  210. // Map Japanese special characters
  211. //
  212. MapSpecialJapaneseChars(OemQueueName.Buffer,OemQueueName.Length);
  213. if ( NT_SUCCESS(ntstatus))
  214. {
  215. ntstatus = NwlibMakeNcp(
  216. handleServer,
  217. FSCTL_NWR_NCP_E3H, // Bindery function
  218. 58, // Max request packet size
  219. 59, // Max response packet size
  220. "bdwp|d", // Format string
  221. 0x37, // Scan bindery object
  222. 0xFFFFFFFF, // Previous ID
  223. 0x3, // Print Queue object
  224. OemQueueName.Buffer, // Queue Name
  225. QueueId // Queue ID
  226. );
  227. }
  228. #if DBG
  229. if ( NT_SUCCESS(ntstatus)) {
  230. IF_DEBUG(QUEUE) {
  231. KdPrint(("NWWORKSTATION: NwGetQueueId QueueId %08lx\n",
  232. *QueueId ));
  233. }
  234. }
  235. #endif
  236. RtlFreeOemString( &OemQueueName );
  237. return NwMapBinderyCompletionCode(ntstatus);
  238. }
  239. DWORD
  240. NwCreateQueueJobAndFile(
  241. IN HANDLE handleServer,
  242. IN DWORD QueueId,
  243. IN LPWSTR DocumentName,
  244. IN LPWSTR UserName,
  245. IN DWORD fGateway,
  246. IN DWORD PrintOption, //Multi-user change
  247. IN LPWSTR QueueName,
  248. OUT LPWORD JobId
  249. )
  250. /*++
  251. Routine Description:
  252. This function uses an opened handle to a server to
  253. enter a new job into the queue with the given QueueId.
  254. Arguments:
  255. handleServer - Supplies the handle to the server on
  256. which add the job.
  257. QueueId - Supplies the id of the queue in which to add the job.
  258. DocumentName - Supplies the name of the document to be printed
  259. UserName - Supplies the banner name to be printed
  260. fGateway - TRUE if gateway printing, FALSE otherwise
  261. QueueName - Supplies the header name to be printed
  262. JobId - Receives the job id of the newly added job.
  263. Return Value:
  264. NO_ERROR - Successfully added the job to the queue.
  265. --*/
  266. {
  267. NTSTATUS ntstatus = STATUS_SUCCESS;
  268. UNICODE_STRING UDocumentName;
  269. OEM_STRING OemDocumentName;
  270. UNICODE_STRING UUserName;
  271. OEM_STRING OemUserName;
  272. UNICODE_STRING UQueueName;
  273. OEM_STRING OemQueueName;
  274. #if DBG
  275. IF_DEBUG(QUEUE) {
  276. KdPrint(("NWWORKSTATION: NwCreateQueueJobAndFile QueueId %08lx\n",
  277. QueueId ));
  278. }
  279. #endif
  280. if ( UserName )
  281. {
  282. RtlInitUnicodeString( &UUserName, UserName);
  283. ntstatus = RtlUnicodeStringToOemString( &OemUserName,
  284. &UUserName,
  285. TRUE );
  286. }
  287. if ( NT_SUCCESS(ntstatus) && DocumentName )
  288. {
  289. RtlInitUnicodeString( &UDocumentName, DocumentName);
  290. ntstatus = RtlUnicodeStringToOemString( &OemDocumentName,
  291. &UDocumentName,
  292. TRUE );
  293. }
  294. if ( NT_SUCCESS(ntstatus) && QueueName )
  295. {
  296. RtlInitUnicodeString( &UQueueName, QueueName);
  297. ntstatus = RtlUnicodeStringToOemString( &OemQueueName,
  298. &UQueueName,
  299. TRUE );
  300. }
  301. if ( NT_SUCCESS( ntstatus)) {
  302. LPSTR pszDocument, pszUser, pszQueue;
  303. pszDocument = DocumentName? OemDocumentName.Buffer : "";
  304. pszUser = UserName? OemUserName.Buffer : "";
  305. pszQueue = QueueName? OemQueueName.Buffer : "";
  306. //Multi-user uses passed print flag
  307. //
  308. ntstatus = NwlibMakeNcp(
  309. handleServer,
  310. FSCTL_NWR_NCP_E3H, // Bindery function
  311. 263, // Max request packet size
  312. 56, // Max response packet size
  313. "bd_ddw_b_Cbbwwww_C-C-_|_w", // Format string
  314. 0x68, // Create Queue Job and File object
  315. QueueId, // Queue ID
  316. 6, // Skip bytes
  317. 0xffffffff, // Target Server ID number
  318. 0xffffffff, 0xffff, // Target Execution time
  319. 11, // Skip bytes
  320. 0x00, // Job Control Flags
  321. 26, // Skip bytes
  322. pszDocument, // TextJobDescription
  323. 50, // Skip bytes
  324. 0, // Version number (clientarea)
  325. 8, // Tab Size
  326. 1, // Number of copies
  327. PrintOption, // Print Control Flags
  328. 0x3C, // Maximum lines
  329. 0x84, // Maximum characters
  330. 22, // Skip bytes
  331. pszUser, // Banner Name
  332. 12, // Max Length of pszUser
  333. pszQueue, // Header Name
  334. 12, // Max Length of pszQueue
  335. 14 + 80, // Skip remainder of client area
  336. 22, // Skip bytes
  337. JobId // Job ID
  338. );
  339. }
  340. #if DBG
  341. if ( NT_SUCCESS( ntstatus)) {
  342. IF_DEBUG(QUEUE) {
  343. KdPrint(("NWWORKSTATION: NwCreateQueueJobAndFile JobId %d\n",
  344. *JobId ));
  345. }
  346. }
  347. #endif
  348. if ( DocumentName )
  349. RtlFreeOemString( &OemDocumentName );
  350. if ( UserName )
  351. RtlFreeOemString( &OemUserName );
  352. if ( QueueName )
  353. RtlFreeOemString( &OemQueueName );
  354. return NwMapStatus(ntstatus);
  355. }
  356. DWORD
  357. NwCloseFileAndStartQueueJob(
  358. IN HANDLE handleServer,
  359. IN DWORD QueueId,
  360. IN WORD JobId
  361. )
  362. /*++
  363. Routine Description:
  364. This function uses an opened handle to a server to
  365. close a job file and mark the job file ready for service.
  366. Arguments:
  367. handleServer - Supplies the handle to the server on
  368. which add the job.
  369. QueueId - Supplies the id of the queue in which to add the job.
  370. JobId - Supplies the job id.
  371. Return Value:
  372. NO_ERROR - Successfully added the job to the queue.
  373. --*/
  374. {
  375. NTSTATUS ntstatus;
  376. #if DBG
  377. IF_DEBUG(QUEUE) {
  378. KdPrint(("NWWORKSTATION: NwCloseFileAndStartQueueJob QueueId %08lx JobId %d\n", QueueId, JobId ));
  379. }
  380. #endif
  381. // Two versions of CloseFileAndStartQueueJobNCP
  382. ntstatus = NwlibMakeNcp(
  383. handleServer,
  384. FSCTL_NWR_NCP_E3H, // Bindery function
  385. 9, // Max request packet size
  386. 2, // Max response packet size
  387. "bdw|", // Format string
  388. 0x69, // Close File And Start Queue Job
  389. QueueId, // Queue ID
  390. JobId ); // Job ID
  391. return NwMapStatus(ntstatus);
  392. }
  393. DWORD
  394. NwRemoveJobFromQueue(
  395. IN HANDLE handleServer,
  396. IN DWORD QueueId,
  397. IN WORD JobId
  398. )
  399. /*++
  400. Routine Description:
  401. This function removes a job from a queue and closes the associate file.
  402. Arguments:
  403. handleServer - Supplies the handle to the server on
  404. which to remove the job.
  405. QueueId - Supplies the id of the queue in which to remove the job.
  406. JobId - Supplies the job id to be removed.
  407. Return Value:
  408. NO_ERROR - Successfully removed the job from the queue.
  409. --*/
  410. {
  411. NTSTATUS ntstatus;
  412. #if DBG
  413. IF_DEBUG(QUEUE) {
  414. KdPrint(("NWWORKSTATION: NwRemoveJobFromQueue QueueId %08lx JobId %d\n",
  415. QueueId, JobId ));
  416. }
  417. #endif
  418. ntstatus = NwlibMakeNcp(
  419. handleServer,
  420. FSCTL_NWR_NCP_E3H, // Bindery function
  421. 9, // Max request packet size
  422. 2, // Max response packet size
  423. "bdw|", // Format string
  424. 0x6A, // Remove Job From Queue
  425. QueueId, // Queue ID
  426. JobId ); // Job ID
  427. return NwMapStatus(ntstatus);
  428. }
  429. DWORD
  430. NwRemoveAllJobsFromQueue(
  431. IN HANDLE handleServer,
  432. IN DWORD QueueId
  433. )
  434. /*++
  435. Routine Description:
  436. This function removes all jobs from a queue.
  437. Arguments:
  438. handleServer - Supplies the handle to the server on
  439. which to remove all jobs.
  440. QueueId - Supplies the id of the queue in which to remove all jobs.
  441. Return Value:
  442. NO_ERROR - Successfully removed all jobs from the queue.
  443. --*/
  444. {
  445. DWORD err;
  446. WORD JobCount = 0;
  447. WORD pwJobList[250];
  448. WORD i;
  449. #if DBG
  450. IF_DEBUG(QUEUE)
  451. {
  452. KdPrint(("NWWORKSTATION: NwRemoveAllJobsFromQueue QueueId %08lx\n",
  453. QueueId ));
  454. }
  455. #endif
  456. pwJobList[0] = 0;
  457. err = NwGetQueueJobList( handleServer,
  458. QueueId,
  459. &JobCount,
  460. pwJobList );
  461. for ( i = 0; !err && i < JobCount; i++ )
  462. {
  463. err = NwRemoveJobFromQueue( handleServer,
  464. QueueId,
  465. pwJobList[i] );
  466. }
  467. return err;
  468. }
  469. DWORD
  470. NwReadQueueCurrentStatus(
  471. IN HANDLE handleServer,
  472. IN DWORD QueueId,
  473. OUT LPBYTE QueueStatus,
  474. OUT LPBYTE NumberOfJobs
  475. )
  476. /*++
  477. Routine Description:
  478. This function uses an opened handle to a server to
  479. query the status of the queue with the given QueueId.
  480. Arguments:
  481. handleServer - Supplies the handle to the server on
  482. which add the job.
  483. QueueId - Supplies the id of the queue
  484. QueueStatus - Receives the status of the queue
  485. NumberOfJobs - Receives the number of jobs in the queue.
  486. Return Value:
  487. NO_ERROR - Successfully retrieved the status of the queue.
  488. --*/
  489. {
  490. NTSTATUS ntstatus;
  491. #if DBG
  492. IF_DEBUG(QUEUE) {
  493. KdPrint(("NWWORKSTATION: NwReadQueueCurrentStatus QueueId %08lx\n",
  494. QueueId ));
  495. }
  496. #endif
  497. ntstatus = NwlibMakeNcp(
  498. handleServer,
  499. FSCTL_NWR_NCP_E3H, // Bindery function
  500. 7, // Max request packet size
  501. 135, // Max response packet size
  502. "bd|==bb", // Format string
  503. 0x66, // ReadQueueCurrentStatus
  504. QueueId, // Queue ID
  505. QueueStatus, // Queue status
  506. NumberOfJobs // Number of jobs in the queue
  507. );
  508. #if DBG
  509. if ( NT_SUCCESS( ntstatus)) {
  510. IF_DEBUG(QUEUE) {
  511. KdPrint(("NWWORKSTATION: NwReadQueueCurrentStatus QueueStatus %d Number of Jobs %d\n", *QueueStatus, *NumberOfJobs ));
  512. }
  513. }
  514. #endif
  515. return NwMapStatus(ntstatus);
  516. }
  517. DWORD
  518. NwSetQueueCurrentStatus(
  519. IN HANDLE handleServer,
  520. IN DWORD QueueId,
  521. IN BYTE QueueStatus
  522. )
  523. /*++
  524. Routine Description:
  525. This function uses an opened handle to a server to
  526. set the status (pause/ready...) of the queue with the given QueueId.
  527. Arguments:
  528. handleServer - Supplies the handle to the server on
  529. which add the job.
  530. QueueId - Supplies the id of the queue
  531. QueueStatus - Supplies the status of the queue
  532. Return Value:
  533. NO_ERROR - Successfully set the status of the queue.
  534. --*/
  535. {
  536. NTSTATUS ntstatus;
  537. #if DBG
  538. IF_DEBUG(QUEUE) {
  539. KdPrint(("NWWORKSTATION: NwSetQueueCurrentStatus QueueId %08lx\n",
  540. QueueId ));
  541. }
  542. #endif
  543. ntstatus = NwlibMakeNcp(
  544. handleServer,
  545. FSCTL_NWR_NCP_E3H, // Bindery function
  546. 8, // Max request packet size
  547. 2, // Max response packet size
  548. "bdb|", // Format string
  549. 0x67, // ReadQueueCurrentStatus
  550. QueueId, // Queue ID
  551. QueueStatus // Queue status
  552. );
  553. return NwMapStatus(ntstatus);
  554. }
  555. DWORD
  556. NwGetQueueJobList(
  557. IN HANDLE handleServer,
  558. IN DWORD QueueId,
  559. OUT LPWORD NumberOfJobs,
  560. OUT LPWORD JobIdList
  561. )
  562. /*++
  563. Routine Description:
  564. This function uses an opened handle to a server to
  565. get the job list of the queue with the given QueueId.
  566. Arguments:
  567. handleServer - Supplies the handle to the server on
  568. which add the job.
  569. QueueId - Supplies the id of the queue
  570. NumberOfJobs - Receives the number of jobs in the queue.
  571. JobIdList - Receives the array of job ids in the queue
  572. Return Value:
  573. NO_ERROR - Successfully added the job to the queue.
  574. --*/
  575. {
  576. NTSTATUS ntstatus;
  577. #if DBG
  578. WORD i;
  579. IF_DEBUG(QUEUE) {
  580. KdPrint(("NWWORKSTATION: NwGetQueueJobList QueueId %08lx\n",
  581. QueueId ));
  582. }
  583. #endif
  584. ntstatus = NwlibMakeNcp(
  585. handleServer,
  586. FSCTL_NWR_NCP_E3H, // Bindery function
  587. 7, // Max request packet size
  588. 506, // Max response packet size
  589. "bd|W", // Format string
  590. 0x6B, // Get Queue Job List
  591. QueueId, // Queue ID
  592. NumberOfJobs, // Number of jobs in the queue
  593. JobIdList // Array of job ids
  594. );
  595. #if DBG
  596. if ( NT_SUCCESS(ntstatus)) {
  597. IF_DEBUG(QUEUE) {
  598. KdPrint(("NWWORKSTATION: NwGetQueueJobList Number of Jobs %d\nJob List = ", *NumberOfJobs ));
  599. for ( i = 0; i < *NumberOfJobs; i++ )
  600. KdPrint(("%d ", JobIdList[i] ));
  601. KdPrint(("\n"));
  602. }
  603. }
  604. #endif
  605. return NwMapStatus(ntstatus);
  606. }
  607. DWORD
  608. NwReadQueueJobEntry(
  609. IN HANDLE handleServer,
  610. IN DWORD QueueId,
  611. IN WORD JobId,
  612. OUT JOBTIME TargetExecutionTime,
  613. OUT JOBTIME JobEntryTime,
  614. OUT LPBYTE JobPosition,
  615. OUT LPBYTE JobControlFlags,
  616. OUT LPSTR TextJobDescription,
  617. OUT LPSTR UserName
  618. )
  619. /*++
  620. Routine Description:
  621. This function uses an opened handle to a server to
  622. get the information about the job with the given JobId
  623. in the given QueueId.
  624. Arguments:
  625. handleServer - Supplies the handle to the server on
  626. which add the job.
  627. QueueId - Supplies the id of the queue
  628. JobId - Supplies the job we are interested in
  629. TargetExecutionTime -
  630. JobEntryTime -
  631. JobPosition -
  632. JobControlsFlags -
  633. TextJobDescription -
  634. Return Value:
  635. NO_ERROR - Successfully added the job to the queue.
  636. --*/
  637. {
  638. NTSTATUS ntstatus;
  639. #if DBG
  640. IF_DEBUG(QUEUE) {
  641. KdPrint(("NWWORKSTATION: NwReadQueueJobEntry QueueId %08lx JobId %d\n",
  642. QueueId, JobId ));
  643. }
  644. #endif
  645. ntstatus = NwlibMakeNcp(
  646. handleServer,
  647. FSCTL_NWR_NCP_E3H, // Bindery function
  648. 9, // Max request packet size
  649. 258, // Max response packet size
  650. "bdw|_rr==bb_C_c", // Format string
  651. 0x6C, // Read Queue Job Entry
  652. QueueId, // Queue ID
  653. JobId, // Job ID
  654. 10, // Skip bytes
  655. TargetExecutionTime, // Array storing execution time
  656. 6, // Size of TargetExecutionTime
  657. JobEntryTime, // Array storing job entry time
  658. 6, // Size of JobEntryTime
  659. JobPosition, // Job Position
  660. JobControlFlags, // Job Control Flag
  661. 26, // Skip bytes
  662. TextJobDescription, // Array storing the description
  663. 50, // Maximum size in the above array
  664. 32, // Skip bytes
  665. UserName // Banner Name
  666. );
  667. #if DBG
  668. if ( NT_SUCCESS( ntstatus)) {
  669. IF_DEBUG(QUEUE) {
  670. KdPrint(("NWWORKSTATION: NwReadQueueJobEntry JobPosition %d Status %d Description %s\n", *JobPosition, *JobControlFlags, TextJobDescription ));
  671. }
  672. }
  673. #endif
  674. return NwMapStatus(ntstatus);
  675. }
  676. DWORD
  677. NwGetQueueJobsFileSize(
  678. IN HANDLE handleServer,
  679. IN DWORD QueueId,
  680. IN WORD JobId,
  681. OUT LPDWORD FileSize
  682. )
  683. /*++
  684. Routine Description:
  685. This function uses an opened handle to a server to
  686. get the file size of the given job.
  687. Arguments:
  688. handleServer - Supplies the handle to the server on
  689. which add the job.
  690. QueueId - Supplies the id of the queue
  691. JobId - Identifying the job we are interested in
  692. FileSize - Receives the file size of the given job
  693. Return Value:
  694. NO_ERROR - Successfully retrieved the file size.
  695. --*/
  696. {
  697. NTSTATUS ntstatus;
  698. #if DBG
  699. IF_DEBUG(QUEUE) {
  700. KdPrint(("NWWORKSTATION: NwGetQueueJobsFileSize QueueId %08lx JobId %d\n", QueueId, JobId ));
  701. }
  702. #endif
  703. ntstatus = NwlibMakeNcp(
  704. handleServer,
  705. FSCTL_NWR_NCP_E3H, // Bindery function
  706. 9, // Max request packet size
  707. 12, // Max response packet size
  708. "bdw|===d", // Format string
  709. 0x78, // Get Queue Job's File Size
  710. QueueId, // Queue ID
  711. JobId, // Job ID
  712. FileSize // File Size
  713. );
  714. #if DBG
  715. if ( NT_SUCCESS( ntstatus)) {
  716. IF_DEBUG(QUEUE) {
  717. KdPrint(("NWWORKSTATION: NwGetQueueJobsFileSize File Size %d\n",
  718. *FileSize ));
  719. }
  720. }
  721. #endif
  722. return NwMapStatus(ntstatus);
  723. }
  724. DWORD
  725. NwChangeQueueJobPosition(
  726. IN HANDLE handleServer,
  727. IN DWORD QueueId,
  728. IN WORD JobId,
  729. IN BYTE NewPosition
  730. )
  731. /*++
  732. Routine Description:
  733. This function uses an opened handle to a server to
  734. get the change a job's position in a queue.
  735. Arguments:
  736. handleServer - Supplies the handle to the server on
  737. which add the job.
  738. QueueId - Supplies the id of the queue
  739. JobId - Identifying the job we are interested in
  740. NewPosition - Supplies the new position of the job
  741. Return Value:
  742. NO_ERROR - Successfully retrieved the file size.
  743. --*/
  744. {
  745. NTSTATUS ntstatus;
  746. #if DBG
  747. IF_DEBUG(QUEUE) {
  748. KdPrint(("NWWORKSTATION: NwChangeQueueJobPosition QueueId %08lx JobId %d NewPosition %d\n", QueueId, JobId, NewPosition ));
  749. }
  750. #endif
  751. ntstatus = NwlibMakeNcp(
  752. handleServer,
  753. FSCTL_NWR_NCP_E3H, // Bindery function
  754. 10, // Max request packet size
  755. 2, // Max response packet size
  756. "bdwb|", // Format string
  757. 0x6E, // Change Queue Job Position
  758. QueueId, // Queue ID
  759. JobId, // Job ID
  760. NewPosition // New position of the job
  761. );
  762. return NwMapStatus(ntstatus);
  763. }
  764. DWORD
  765. NwChangeQueueJobEntry(
  766. IN HANDLE handleServer,
  767. IN DWORD QueueId,
  768. IN WORD JobId,
  769. IN DWORD dwCommand,
  770. IN PNW_JOB_INFO pNwJobInfo
  771. )
  772. /*++
  773. Routine Description:
  774. This function uses an opened handle to a server to
  775. get the change a job's position in a queue.
  776. Arguments:
  777. handleServer - Supplies the handle to the server on
  778. which add the job.
  779. QueueId - Supplies the id of the queue
  780. JobId - Identifying the job we are interested in
  781. JobControlFlags - Supplies the new job control flags
  782. pNwJobInfo -
  783. Return Value:
  784. NO_ERROR - Successfully retrieved the file size.
  785. --*/
  786. {
  787. NTSTATUS ntstatus = STATUS_SUCCESS;
  788. DWORD TargetServerId;
  789. JOBTIME TargetExecutionTime;
  790. WORD JobType;
  791. BYTE JobControlFlags;
  792. BYTE TextJobDescription[50];
  793. BYTE ClientRecordArea[152];
  794. UNICODE_STRING UDocumentName;
  795. UNICODE_STRING UUserName;
  796. OEM_STRING OemDocumentName, *pOemDocumentName = NULL;
  797. OEM_STRING OemUserName, *pOemUserName = NULL;
  798. LPSTR pszDocument, pszUser;
  799. #if DBG
  800. IF_DEBUG(QUEUE) {
  801. KdPrint(("NWWORKSTATION: NwChangeQueueJobEntry QueueId %08lx JobId %d dwCommand %d\n", QueueId, JobId, dwCommand ));
  802. }
  803. #endif
  804. TextJobDescription[0] = 0;
  805. if ( pNwJobInfo )
  806. {
  807. if ( pNwJobInfo->pUserName )
  808. {
  809. RtlInitUnicodeString( &UUserName, pNwJobInfo->pUserName);
  810. ntstatus = RtlUnicodeStringToOemString( &OemUserName,
  811. &UUserName,
  812. TRUE );
  813. if ( NT_SUCCESS(ntstatus) )
  814. pOemUserName = &OemUserName ; // record to free later
  815. }
  816. if ( NT_SUCCESS(ntstatus) && pNwJobInfo->pDocument )
  817. {
  818. RtlInitUnicodeString( &UDocumentName, pNwJobInfo->pDocument);
  819. ntstatus = RtlUnicodeStringToOemString( &OemDocumentName,
  820. &UDocumentName,
  821. TRUE );
  822. if ( NT_SUCCESS(ntstatus) )
  823. pOemDocumentName = &OemDocumentName ; // record to free later
  824. }
  825. if ( NT_SUCCESS( ntstatus))
  826. {
  827. pszDocument = pNwJobInfo->pDocument? OemDocumentName.Buffer : "";
  828. pszUser = pNwJobInfo->pUserName? OemUserName.Buffer: "";
  829. }
  830. }
  831. if ( NT_SUCCESS( ntstatus))
  832. {
  833. ntstatus = NwlibMakeNcp(
  834. handleServer,
  835. FSCTL_NWR_NCP_E3H, // Bindery function
  836. 9, // Max request packet size
  837. 258, // Max response packet size
  838. "bdw|_dr_w-b_rr", // Format string
  839. 0x6C, // Read Queue Job Entry
  840. QueueId, // Queue ID
  841. JobId, // Job ID
  842. 6, // Skip bytes
  843. &TargetServerId, // Target Server ID Number
  844. TargetExecutionTime, // Target Execution Time
  845. 6, // sizeof TargetExecutionTime
  846. 8, // Skip bytes
  847. &JobType, // Job Type
  848. &JobControlFlags, // Job Control flags
  849. 26, // Skip bytes
  850. TextJobDescription, // TextJobDescription
  851. 50, // sizeof TextJobDescription
  852. ClientRecordArea, // Client record area
  853. 152 // sizeof ClientRecordArea
  854. );
  855. }
  856. if ( NT_SUCCESS( ntstatus))
  857. {
  858. switch ( dwCommand )
  859. {
  860. case JOB_CONTROL_PAUSE:
  861. JobControlFlags |= QF_USER_HOLD;
  862. break;
  863. case JOB_CONTROL_RESUME:
  864. JobControlFlags &= ~( QF_USER_HOLD | QF_OPERATOR_HOLD );
  865. break;
  866. default:
  867. break;
  868. }
  869. ntstatus = NwlibMakeNcp(
  870. handleServer,
  871. FSCTL_NWR_NCP_E3H, // Bindery function
  872. 263, // Max request packet size
  873. 2, // Max response packet size
  874. "bd_dr_ww-b_CrCr|", // Format string
  875. 0x6D, // Change Queue Job Entry
  876. QueueId, // Queue ID
  877. 6, // Skip bytes
  878. TargetServerId, // Target Server ID Number
  879. TargetExecutionTime, // Target Execution Time
  880. 6, // sizeof TargetExecutionTime
  881. 6, // Skip bytes
  882. JobId, // Job ID
  883. JobType, // Job Type
  884. JobControlFlags, // Job Control Flags
  885. 26, // Skip bytes
  886. pNwJobInfo? pszDocument
  887. : TextJobDescription, // Description
  888. 50, // Skip bytes of Description
  889. ClientRecordArea, // Client Record Area
  890. 32, // First 32 bytes of the above
  891. pNwJobInfo? pszUser
  892. : (LPSTR) &ClientRecordArea[32], // Banner Name
  893. 13, // sizeof BannerName
  894. &ClientRecordArea[45], // Rest of the Client Area
  895. 107 // sizeof the above
  896. );
  897. }
  898. if ( pOemDocumentName )
  899. RtlFreeOemString( pOemDocumentName );
  900. if ( pOemUserName )
  901. RtlFreeOemString( pOemUserName );
  902. return NwMapStatus(ntstatus);
  903. }
  904. DWORD
  905. NwGetQueueJobs(
  906. IN HANDLE handleServer,
  907. IN DWORD QueueId,
  908. IN LPWSTR PrinterName,
  909. IN DWORD FirstJobRequested,
  910. IN DWORD EntriesRequested,
  911. IN DWORD Level,
  912. OUT LPBYTE Buffer,
  913. IN DWORD cbBuf,
  914. OUT LPDWORD BytesNeeded,
  915. OUT LPDWORD Entries
  916. )
  917. /*++
  918. Routine Description:
  919. Arguments:
  920. handleServer - Supplies the handle to the server on
  921. which add the job.
  922. QueueId - Supplies the id of the queue
  923. Return Value:
  924. --*/
  925. {
  926. DWORD err = NO_ERROR;
  927. DWORD i;
  928. WORD JobCount = 0;
  929. WORD pwJobList[250];
  930. DWORD EntrySize = 0;
  931. LPBYTE FixedPortion = Buffer;
  932. LPWSTR EndOfVariableData = ( LPWSTR ) ( Buffer + cbBuf );
  933. #if DBG
  934. IF_DEBUG(QUEUE)
  935. KdPrint(("NWWORKSTATION: NwGetQueueJobs QueueId %08lx\n", QueueId));
  936. #endif
  937. *BytesNeeded = 0;
  938. *Entries = 0;
  939. err = NwGetQueueJobList( handleServer,
  940. QueueId,
  941. &JobCount,
  942. pwJobList );
  943. if ( err )
  944. {
  945. KdPrint(("NWWORKSTATION: NwGetQueueJobList Error %d\n", err ));
  946. return err;
  947. }
  948. for ( i = 0; (i < EntriesRequested) && ( i+FirstJobRequested+1 <= JobCount);
  949. i++ )
  950. {
  951. err = NwGetQueueJobInfo( handleServer,
  952. QueueId,
  953. pwJobList[i+FirstJobRequested],
  954. PrinterName,
  955. Level,
  956. &FixedPortion,
  957. &EndOfVariableData,
  958. &EntrySize );
  959. if ( err != NO_ERROR && err != ERROR_INSUFFICIENT_BUFFER )
  960. break;
  961. *BytesNeeded += EntrySize;
  962. }
  963. if ( err == ERROR_INSUFFICIENT_BUFFER )
  964. {
  965. *Entries = 0;
  966. }
  967. else if ( err == NO_ERROR )
  968. {
  969. *Entries = i;
  970. }
  971. return err;
  972. }
  973. DWORD
  974. NwGetQueueJobInfo(
  975. IN HANDLE handleServer,
  976. IN DWORD QueueId,
  977. IN WORD JobId,
  978. IN LPWSTR PrinterName,
  979. IN DWORD Level,
  980. IN OUT LPBYTE *FixedPortion,
  981. IN OUT LPWSTR *EndOfVariableData,
  982. OUT LPDWORD EntrySize
  983. )
  984. /*++
  985. Routine Description:
  986. Arguments:
  987. handleServer - Supplies the handle to the server on
  988. which add the job.
  989. QueueId - Supplies the id of the queue
  990. Return Value:
  991. --*/
  992. {
  993. DWORD err;
  994. LPWSTR UTextJobDescription = NULL;
  995. LPWSTR UUserName = NULL;
  996. JOBTIME TargetExecutionTime;
  997. JOBTIME JobEntryTime;
  998. BYTE JobPosition;
  999. BYTE JobControlFlags;
  1000. CHAR UserName[14];
  1001. CHAR TextJobDescription[50];
  1002. DWORD FileSize = 0;
  1003. TextJobDescription[0] = 0;
  1004. err = NwReadQueueJobEntry( handleServer,
  1005. QueueId,
  1006. JobId,
  1007. TargetExecutionTime,
  1008. JobEntryTime,
  1009. &JobPosition,
  1010. &JobControlFlags,
  1011. TextJobDescription,
  1012. UserName );
  1013. if ( err )
  1014. {
  1015. KdPrint(("NWWORKSTATION: NwReadQueueJobEntry JobId %d Error %d\n",
  1016. JobId, err ));
  1017. return err;
  1018. }
  1019. if (!NwConvertToUnicode( &UTextJobDescription, TextJobDescription ))
  1020. {
  1021. err = ERROR_NOT_ENOUGH_MEMORY ;
  1022. goto ErrorExit ;
  1023. }
  1024. if (!NwConvertToUnicode( &UUserName, UserName ))
  1025. {
  1026. err = ERROR_NOT_ENOUGH_MEMORY ;
  1027. goto ErrorExit ;
  1028. }
  1029. *EntrySize = ( Level == 1? sizeof( JOB_INFO_1W ) : sizeof( JOB_INFO_2W ))
  1030. + ( wcslen( UTextJobDescription ) + wcslen( UUserName) +
  1031. wcslen( PrinterName ) + 3 ) * sizeof( WCHAR );
  1032. //
  1033. // See if the buffer is large enough to fit the entry
  1034. //
  1035. if ( (LPWSTR)( *FixedPortion + *EntrySize ) > *EndOfVariableData )
  1036. {
  1037. err = ERROR_INSUFFICIENT_BUFFER;
  1038. goto ErrorExit ;
  1039. }
  1040. if ( Level == 2 )
  1041. {
  1042. err = NwGetQueueJobsFileSize( handleServer,
  1043. QueueId,
  1044. JobId,
  1045. &FileSize );
  1046. if ( err )
  1047. {
  1048. KdPrint(("NWWORKSTATION: NwGetQueueJobsFileSize JobId %d Error %d\n", JobId, err ));
  1049. goto ErrorExit ;
  1050. }
  1051. }
  1052. err = NwWriteJobInfoEntry( FixedPortion,
  1053. EndOfVariableData,
  1054. Level,
  1055. JobId,
  1056. PrinterName,
  1057. UTextJobDescription,
  1058. UUserName,
  1059. JobControlFlags,
  1060. JobPosition,
  1061. JobEntryTime,
  1062. TargetExecutionTime,
  1063. FileSize );
  1064. ErrorExit:
  1065. if (UTextJobDescription)
  1066. (void) LocalFree((HLOCAL) UTextJobDescription) ;
  1067. if (UUserName)
  1068. (void) LocalFree((HLOCAL) UUserName) ;
  1069. return err;
  1070. }
  1071. DWORD
  1072. NwWriteJobInfoEntry(
  1073. IN OUT LPBYTE *FixedPortion,
  1074. IN OUT LPWSTR *EndOfVariableData,
  1075. IN DWORD Level,
  1076. IN WORD JobId,
  1077. IN LPWSTR PrinterName,
  1078. IN LPWSTR JobDescription,
  1079. IN LPWSTR UserName,
  1080. IN BYTE JobControlFlags,
  1081. IN BYTE JobPosition,
  1082. IN JOBTIME JobEntryTime,
  1083. IN JOBTIME TargetExecutionTime,
  1084. IN DWORD FileSize
  1085. )
  1086. /*++
  1087. Routine Description:
  1088. This function packages a JOB_INFO_1 or JOB_INFO_2 entry into the
  1089. user output buffer.
  1090. Arguments:
  1091. FixedPortion - Supplies a pointer to the output buffer where the next
  1092. entry of the fixed portion of the use information will be written.
  1093. This pointer is updated to point to the next fixed portion entry
  1094. after a PRINT_INFO_1 entry is written.
  1095. EndOfVariableData - Supplies a pointer just off the last available byte
  1096. in the output buffer. This is because the variable portion of the
  1097. user information is written into the output buffer starting from
  1098. the end.
  1099. This pointer is updated after any variable length information is
  1100. written to the output buffer.
  1101. Return Value:
  1102. NO_ERROR - Successfully wrote entry into user buffer.
  1103. ERROR_INSUFFICIENT_BUFFER - Buffer was too small to fit entry.
  1104. --*/
  1105. {
  1106. DWORD err = NO_ERROR;
  1107. BOOL FitInBuffer = TRUE;
  1108. DWORD JobStatus = 0;
  1109. JOB_INFO_1W *pJobInfo1 = (JOB_INFO_1W *) *FixedPortion;
  1110. JOB_INFO_2W *pJobInfo2 = (JOB_INFO_2W *) *FixedPortion;
  1111. if ( ( JobControlFlags & QF_USER_HOLD )
  1112. || ( JobControlFlags & QF_OPERATOR_HOLD )
  1113. )
  1114. {
  1115. JobStatus = JOB_STATUS_PAUSED;
  1116. }
  1117. //
  1118. // See if buffer is large enough to fit the entry.
  1119. //
  1120. if ( Level == 1 )
  1121. {
  1122. pJobInfo1->JobId = JobId;
  1123. pJobInfo1->Position = JobPosition;
  1124. pJobInfo1->Status = JobStatus;
  1125. if ( err = ConvertToSystemTime( JobEntryTime, &pJobInfo1->Submitted ))
  1126. return err;
  1127. pJobInfo1->pMachineName = NULL;
  1128. pJobInfo1->pDatatype = NULL;
  1129. pJobInfo1->pStatus = NULL;
  1130. pJobInfo1->Priority = 0;
  1131. pJobInfo1->TotalPages = 0;
  1132. pJobInfo1->PagesPrinted = 0;
  1133. //
  1134. // Update fixed entry pointer to next entry.
  1135. //
  1136. (*FixedPortion) += sizeof(JOB_INFO_1W);
  1137. //
  1138. // PrinterName
  1139. //
  1140. FitInBuffer = NwlibCopyStringToBuffer(
  1141. PrinterName,
  1142. wcslen(PrinterName),
  1143. (LPCWSTR) *FixedPortion,
  1144. EndOfVariableData,
  1145. &pJobInfo1->pPrinterName
  1146. );
  1147. ASSERT(FitInBuffer);
  1148. //
  1149. // UserName
  1150. //
  1151. FitInBuffer = NwlibCopyStringToBuffer(
  1152. UserName,
  1153. wcslen(UserName),
  1154. (LPCWSTR) *FixedPortion,
  1155. EndOfVariableData,
  1156. &pJobInfo1->pUserName
  1157. );
  1158. ASSERT(FitInBuffer);
  1159. //
  1160. // Description
  1161. //
  1162. FitInBuffer = NwlibCopyStringToBuffer(
  1163. JobDescription,
  1164. wcslen(JobDescription),
  1165. (LPCWSTR) *FixedPortion,
  1166. EndOfVariableData,
  1167. &pJobInfo1->pDocument
  1168. );
  1169. ASSERT(FitInBuffer);
  1170. }
  1171. else // Level == 2
  1172. {
  1173. pJobInfo2->JobId = JobId;
  1174. pJobInfo2->Position = JobPosition;
  1175. pJobInfo2->Status = JobStatus;
  1176. if ( err = ConvertToSystemTime( JobEntryTime, &pJobInfo2->Submitted ))
  1177. return err;
  1178. pJobInfo2->StartTime = 0;
  1179. pJobInfo2->Size = FileSize;
  1180. pJobInfo2->pMachineName = NULL;
  1181. pJobInfo2->pNotifyName = NULL;
  1182. pJobInfo2->pDatatype = NULL;
  1183. pJobInfo2->pPrintProcessor = NULL;
  1184. pJobInfo2->pParameters = NULL;
  1185. pJobInfo2->pDriverName = NULL;
  1186. pJobInfo2->pDevMode = NULL;
  1187. pJobInfo2->pStatus = NULL;
  1188. pJobInfo2->pSecurityDescriptor = NULL;
  1189. pJobInfo2->Priority = 0;
  1190. pJobInfo2->TotalPages = 0;
  1191. pJobInfo2->UntilTime = 0;
  1192. pJobInfo2->Time = 0;
  1193. pJobInfo2->PagesPrinted = 0;
  1194. //
  1195. // Update fixed entry pointer to next entry.
  1196. //
  1197. (*FixedPortion) += sizeof(JOB_INFO_2W);
  1198. //
  1199. // PrinterName
  1200. //
  1201. FitInBuffer = NwlibCopyStringToBuffer(
  1202. PrinterName,
  1203. wcslen(PrinterName),
  1204. (LPCWSTR) *FixedPortion,
  1205. EndOfVariableData,
  1206. &pJobInfo2->pPrinterName
  1207. );
  1208. ASSERT(FitInBuffer);
  1209. //
  1210. // UserName
  1211. //
  1212. FitInBuffer = NwlibCopyStringToBuffer(
  1213. UserName,
  1214. wcslen(UserName),
  1215. (LPCWSTR) *FixedPortion,
  1216. EndOfVariableData,
  1217. &pJobInfo2->pUserName
  1218. );
  1219. ASSERT(FitInBuffer);
  1220. //
  1221. // Description
  1222. //
  1223. FitInBuffer = NwlibCopyStringToBuffer(
  1224. JobDescription,
  1225. wcslen(JobDescription),
  1226. (LPCWSTR) *FixedPortion,
  1227. EndOfVariableData,
  1228. &pJobInfo2->pDocument
  1229. );
  1230. ASSERT(FitInBuffer);
  1231. }
  1232. if (!FitInBuffer)
  1233. return ERROR_INSUFFICIENT_BUFFER;
  1234. return NO_ERROR;
  1235. }
  1236. DWORD
  1237. ConvertToSystemTime(
  1238. IN JOBTIME JobTime,
  1239. OUT LPSYSTEMTIME pSystemTime
  1240. )
  1241. /*++
  1242. Routine Description:
  1243. Arguments:
  1244. JobTime -
  1245. pSystemTime -
  1246. Return Value:
  1247. --*/
  1248. {
  1249. FILETIME fileTimeLocal, fileTimeUTC;
  1250. pSystemTime->wYear = JobTime[0] + 1900;
  1251. pSystemTime->wMonth = JobTime[1];
  1252. pSystemTime->wDay = JobTime[2];
  1253. pSystemTime->wDayOfWeek = 0;
  1254. pSystemTime->wHour = JobTime[3];
  1255. pSystemTime->wMinute = JobTime[4];
  1256. pSystemTime->wSecond = JobTime[5];
  1257. pSystemTime->wMilliseconds = 0;
  1258. if ( ( !SystemTimeToFileTime( pSystemTime, &fileTimeLocal ) )
  1259. || ( !LocalFileTimeToFileTime( &fileTimeLocal, &fileTimeUTC ) )
  1260. || ( !FileTimeToSystemTime( &fileTimeUTC, pSystemTime ) )
  1261. )
  1262. {
  1263. KdPrint(("NWWORKSTATION: Time Conversion Error = %d\n",GetLastError()));
  1264. return GetLastError();
  1265. }
  1266. return NO_ERROR;
  1267. }
  1268. #ifndef NOT_USED
  1269. DWORD
  1270. NwCreateQueue ( IN HANDLE hServer,
  1271. IN LPWSTR pszQueue,
  1272. OUT LPDWORD pQueueId
  1273. )
  1274. /*+++
  1275. Routine Description:
  1276. Uses the handle opened to a server to create a queue on the server.
  1277. Return the Queue Id if successful.
  1278. Arguments:
  1279. hServer : Handle to the file Server
  1280. pszQueue : Name of the queue that you are creating on the server
  1281. pQueueId : Address of QueueId
  1282. Return Value:
  1283. An error condition as it arises.
  1284. NO_ERROR: Successful in adding printer name
  1285. ERROR : otherwise
  1286. --*/
  1287. {
  1288. NTSTATUS ntstatus;
  1289. WORD ObjectType;
  1290. UNICODE_STRING UQueueName;
  1291. OEM_STRING OemQueueName;
  1292. *pQueueId = 0;
  1293. #if DBG
  1294. IF_DEBUG(PRINT) {
  1295. KdPrint(("NWWORKSTATION: NwCreateQueue : %ws\n",
  1296. pszQueue));
  1297. }
  1298. #endif
  1299. RtlInitUnicodeString( &UQueueName, pszQueue);
  1300. ntstatus = RtlUnicodeStringToOemString( &OemQueueName, &UQueueName, TRUE);
  1301. if ( NT_SUCCESS(ntstatus))
  1302. {
  1303. ntstatus = NwlibMakeNcp(
  1304. hServer,
  1305. FSCTL_NWR_NCP_E3H,
  1306. 174,
  1307. 6,
  1308. "bwpbp|d",
  1309. 0x64, //Create Queue
  1310. 0x0003, // Queue Type = Print Queue
  1311. OemQueueName.Buffer, //Queue Name
  1312. 0x00, // Directory Handle
  1313. "SYS:SYSTEM", //queue created in SYS:SYSTEM directory
  1314. pQueueId
  1315. );
  1316. }
  1317. else
  1318. {
  1319. goto Exit;
  1320. }
  1321. if ( NT_SUCCESS(ntstatus)) {
  1322. #if DBG
  1323. IF_DEBUG(ENUM) {
  1324. KdPrint(("NWWORKSTATION: NwCreateQueue successful\n" ));
  1325. }
  1326. #endif
  1327. }
  1328. else
  1329. goto FreeExit;
  1330. // Change Property Security on Q_OPERATORS
  1331. ntstatus = NwlibMakeNcp (
  1332. hServer,
  1333. FSCTL_NWR_NCP_E3H,
  1334. 70,
  1335. 2,
  1336. "bwpbp|",
  1337. 0x3B,
  1338. 0x0003,
  1339. OemQueueName.Buffer,
  1340. 0x1, //New Property security
  1341. "Q_OPERATORS"
  1342. );
  1343. if ( NT_SUCCESS(ntstatus)) {
  1344. #if DBG
  1345. IF_DEBUG(PRINT) {
  1346. KdPrint(("NWWORKSTATION: Change Property Security successful\n" ));
  1347. }
  1348. #endif
  1349. }
  1350. else
  1351. //unable to add new property security, so destroy queue and go to end
  1352. {
  1353. (void) NwDestroyQueue( hServer,
  1354. *pQueueId );
  1355. goto FreeExit;
  1356. }
  1357. // Add Bindery Object of Type Queue to Set
  1358. ntstatus = NwlibMakeNcp (
  1359. hServer,
  1360. FSCTL_NWR_NCP_E3H, // Bindery function
  1361. 122,
  1362. 2,
  1363. "bwppwp|",
  1364. 0x41,
  1365. 0x0003,
  1366. OemQueueName.Buffer,
  1367. "Q_OPERATORS",
  1368. 0x0001,
  1369. "SUPERVISOR"
  1370. );
  1371. if ( NT_SUCCESS(ntstatus)) {
  1372. #if DBG
  1373. IF_DEBUG(PRINT) {
  1374. KdPrint(("NWWORKSTATION: Add Bindery Object:Q_OPERATORS\n" ));
  1375. }
  1376. #endif
  1377. }
  1378. else
  1379. {
  1380. (void)NwDestroyQueue(hServer,*pQueueId);
  1381. goto FreeExit;
  1382. }
  1383. // Add Bindery Object to Set of Q_USERS
  1384. ntstatus = NwlibMakeNcp (
  1385. hServer,
  1386. FSCTL_NWR_NCP_E3H, // Bindery function
  1387. 122,
  1388. 2,
  1389. "bwppwp|",
  1390. 0x41,
  1391. 0x0003,
  1392. OemQueueName.Buffer,
  1393. "Q_USERS",
  1394. 0x0002,
  1395. "EVERYONE"
  1396. );
  1397. // bunch of parameters to Add Bindery Object to Set Q_USERS
  1398. if ( NT_SUCCESS(ntstatus)) {
  1399. #if DBG
  1400. IF_DEBUG(PRINT) {
  1401. KdPrint(("NWWORKSTATION: AddBinderyObjecttoSet Q_USERS\n" ));
  1402. }
  1403. #endif
  1404. }
  1405. FreeExit: RtlFreeOemString( &OemQueueName);
  1406. Exit:
  1407. return NwMapBinderyCompletionCode(ntstatus);
  1408. }
  1409. DWORD
  1410. NwAssocPServers ( IN HANDLE hServer,
  1411. IN LPWSTR pszQueue,
  1412. IN LPWSTR pszPServer
  1413. )
  1414. /*+++
  1415. Routine Description:
  1416. Associates a list of Q Servers with a queue id. This list is supplied
  1417. to this routine as pszPServer with entries separated by semicolons
  1418. Arguments:
  1419. hServer : Handle to the file Server
  1420. pszQueue : Name of the queue to which to associate the Q servers
  1421. pszPServer : List of Q Servers.
  1422. Return Value:
  1423. An error condition as it arises.
  1424. 0x0 is returned if there is no error
  1425. --*/
  1426. {
  1427. LPWSTR pszPServerlist = NULL;
  1428. LPWSTR pszNextPServer = NULL;
  1429. DWORD err = 0x00000000 ;
  1430. NTSTATUS ntstatus ;
  1431. UNICODE_STRING UQueueName, UNextPServer;
  1432. OEM_STRING OemQueueName,OemNextPServer;
  1433. if (pszPServer == NULL)
  1434. return NO_ERROR;
  1435. if((pszPServerlist = AllocNwSplStr(pszPServer)) == NULL)
  1436. {
  1437. err = ERROR_NOT_ENOUGH_MEMORY;
  1438. return err;
  1439. }
  1440. RtlInitUnicodeString( &UQueueName, pszQueue);
  1441. ntstatus = RtlUnicodeStringToOemString( &OemQueueName, &UQueueName, TRUE);
  1442. if (! NT_SUCCESS(ntstatus))
  1443. {
  1444. goto Exit;
  1445. }
  1446. while( (pszNextPServer = GetNextElement(&pszPServerlist, L';')) != NULL )
  1447. {
  1448. RtlInitUnicodeString( &UNextPServer, pszNextPServer);
  1449. ntstatus = RtlUnicodeStringToOemString( &OemNextPServer, &UNextPServer, TRUE);
  1450. if ( !NT_SUCCESS(ntstatus))
  1451. {
  1452. RtlFreeOemString(&OemNextPServer);
  1453. goto Exit;
  1454. }
  1455. //NwlibMakeNcp should associate a print server with a printer
  1456. // Add Bindery Object to Set
  1457. ntstatus = NwlibMakeNcp (
  1458. hServer,
  1459. FSCTL_NWR_NCP_E3H, // Bindery function
  1460. 122,
  1461. 2,
  1462. "bwppwp|",
  1463. 0x41,
  1464. 0x0003,
  1465. OemQueueName.Buffer,
  1466. "Q_SERVERS",
  1467. 0x0007, // Object of type Print Server
  1468. OemNextPServer.Buffer
  1469. );
  1470. RtlFreeOemString(&OemNextPServer);
  1471. if (!( NT_SUCCESS(ntstatus)))
  1472. {
  1473. RtlFreeOemString(&OemNextPServer);
  1474. goto Exit;
  1475. }
  1476. }
  1477. RtlFreeOemString(&OemQueueName);
  1478. Exit:
  1479. return NwMapBinderyCompletionCode(ntstatus);
  1480. }
  1481. DWORD
  1482. NwDestroyQueue (HANDLE hServer,
  1483. DWORD dwQueueId)
  1484. /*+++
  1485. Routine Description:
  1486. Makes the Ncp call to destroy the queue given by dwQueueId
  1487. Arguments:
  1488. dwQueueId : Id of the queue you are creating.
  1489. Return Value:
  1490. An error condition as it arises.
  1491. 0x0 is returned if there is no error
  1492. ---*/
  1493. {
  1494. NTSTATUS ntstatus;
  1495. ntstatus = NwlibMakeNcp(
  1496. hServer,
  1497. FSCTL_NWR_NCP_E3H,
  1498. 7,
  1499. 2,
  1500. "bd|",
  1501. 0x65,
  1502. dwQueueId
  1503. );
  1504. #if DBG
  1505. if ( NT_SUCCESS(ntstatus)) {
  1506. IF_DEBUG(PRINT) {
  1507. KdPrint(("NWWORKSTATION: Queue successfully destroyed\n"));
  1508. }
  1509. }
  1510. #endif
  1511. return NwMapBinderyCompletionCode(ntstatus);
  1512. }
  1513. #endif // #ifndef NOT_USED