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.

2408 lines
59 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. spool.c
  5. Abstract:
  6. This module contains the Netware print provider.
  7. Author:
  8. Yi-Hsin Sung (yihsins) 15-May-1993
  9. Revision History:
  10. --*/
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <nw.h>
  14. #include <nwreg.h>
  15. #include <nwpkstr.h>
  16. #include <splutil.h>
  17. #include <queue.h>
  18. #include <nwmisc.h>
  19. //------------------------------------------------------------------
  20. //
  21. // Local Definitions
  22. //
  23. //------------------------------------------------------------------
  24. #define NW_SIGNATURE 0x574E /* "NW" is the signature */
  25. #define SPOOL_STATUS_STARTDOC 0x00000001
  26. #define SPOOL_STATUS_ADDJOB 0x00000002
  27. #define SPOOL_STATUS_ABORT 0x00000003
  28. #define PRINTER_CHANGE_VALID 0x55770F07
  29. #define PRINTER_CHANGE_DEFAULT_TIMEOUT_VALUE 10000
  30. #define PRINTER_CHANGE_MINIMUM_TIMEOUT_VALUE 1000
  31. #define REG_TIMEOUT_PATH L"System\\CurrentControlSet\\Services\\NWCWorkstation\\Parameters"
  32. #define REG_TIMEOUT_VALUE_NAME L"PrintNotifyTimeout"
  33. #define NDS_MAX_NAME_CHARS 256
  34. #define NDS_MAX_NAME_SIZE ( NDS_MAX_NAME_CHARS * 2 )
  35. //
  36. // Printer structure
  37. //
  38. typedef struct _NWPRINTER {
  39. LPWSTR pszServer; // Server Name
  40. LPWSTR pszQueue; // Queue Name
  41. LPWSTR pszUncConnection; // UNC Connection Name
  42. // (only present if NDS print queue
  43. DWORD nQueueId; // Queue Id
  44. struct _NWPRINTER *pNextPrinter; // Points to the next printer
  45. struct _NWSPOOL *pSpoolList; // Points to the list of open handles
  46. } NWPRINTER, *PNWPRINTER;
  47. //
  48. // Handle structure
  49. //
  50. typedef struct _NWSPOOL {
  51. DWORD nSignature; // Signature
  52. DWORD errOpenPrinter; // OpenPrinter API will always return
  53. // success on known printers. This will
  54. // contain the error that we get
  55. // if something went wrong in the API.
  56. PNWPRINTER pPrinter; // Points to the corresponding printer
  57. HANDLE hServer; // Opened handle to the server
  58. struct _NWSPOOL *pNextSpool; // Points to the next handle
  59. DWORD nStatus; // Status
  60. DWORD nJobNumber; // StartDocPrinter/AddJob: Job Number
  61. HANDLE hChangeEvent; // WaitForPrinterChange: event to wait on
  62. DWORD nWaitFlags; // WaitForPrinterChange: flags to wait on
  63. DWORD nChangeFlags; // Changes that occurred to the printer
  64. } NWSPOOL, *PNWSPOOL;
  65. //------------------------------------------------------------------
  66. //
  67. // Global Variables
  68. //
  69. //------------------------------------------------------------------
  70. // Stores the timeout value used in WaitForPrinterChange ( in milliseconds )
  71. STATIC DWORD NwTimeOutValue = PRINTER_CHANGE_DEFAULT_TIMEOUT_VALUE;
  72. // Points to the link list of printers
  73. STATIC PNWPRINTER NwPrinterList = NULL;
  74. //------------------------------------------------------------------
  75. //
  76. // Local Function Prototypes
  77. //
  78. //------------------------------------------------------------------
  79. VOID
  80. NwSetPrinterChange(
  81. IN PNWSPOOL pSpool,
  82. IN DWORD nFlags
  83. );
  84. PNWPRINTER
  85. NwFindPrinterEntry(
  86. IN LPWSTR pszServer,
  87. IN LPWSTR pszQueue
  88. );
  89. DWORD
  90. NwCreatePrinterEntry(
  91. IN LPWSTR pszServer,
  92. IN LPWSTR pszQueue,
  93. OUT PNWPRINTER *ppPrinter,
  94. OUT PHANDLE phServer
  95. );
  96. VOID
  97. NwRemovePrinterEntry(
  98. IN PNWPRINTER pPrinter
  99. );
  100. LPWSTR
  101. NwGetUncObjectName(
  102. IN LPWSTR ContainerName
  103. );
  104. VOID
  105. NwInitializePrintProvider(
  106. VOID
  107. )
  108. /*++
  109. Routine Description:
  110. This routine initializes the server side print provider when
  111. the workstation service starts up.
  112. Arguments:
  113. None.
  114. Return Value:
  115. --*/
  116. {
  117. DWORD err;
  118. HKEY hkey;
  119. DWORD dwTemp;
  120. DWORD dwSize = sizeof( dwTemp );
  121. //
  122. // Read the time out value from the registry.
  123. // We will ignore all errors since we can always have a default time out.
  124. // The default will be used if the key does not exist.
  125. //
  126. err = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  127. REG_TIMEOUT_PATH,
  128. 0,
  129. KEY_READ,
  130. &hkey );
  131. if ( !err )
  132. {
  133. err = RegQueryValueExW( hkey,
  134. REG_TIMEOUT_VALUE_NAME,
  135. NULL,
  136. NULL,
  137. (LPBYTE) &dwTemp,
  138. &dwSize );
  139. if ( !err )
  140. {
  141. NwTimeOutValue = dwTemp;
  142. //
  143. // tommye - bug 139469 - removed
  144. // if (NwTimeOutValue >= 0) because NwtimeOutValue is a DWORD
  145. //
  146. // Use the minimum timeout value if the
  147. // value set in the registry is too small.
  148. //
  149. if (NwTimeOutValue <= PRINTER_CHANGE_MINIMUM_TIMEOUT_VALUE)
  150. {
  151. NwTimeOutValue = PRINTER_CHANGE_MINIMUM_TIMEOUT_VALUE;
  152. }
  153. }
  154. RegCloseKey( hkey );
  155. }
  156. }
  157. VOID
  158. NwTerminatePrintProvider(
  159. VOID
  160. )
  161. /*++
  162. Routine Description:
  163. This routine cleans up the server side print provider when
  164. the workstation service shut downs.
  165. Arguments:
  166. None.
  167. Return Value:
  168. --*/
  169. {
  170. PNWPRINTER pPrinter, pNext;
  171. PNWSPOOL pSpool, pNextSpool;
  172. for ( pPrinter = NwPrinterList; pPrinter; pPrinter = pNext )
  173. {
  174. pNext = pPrinter->pNextPrinter;
  175. pPrinter->pNextPrinter = NULL;
  176. for ( pSpool = pPrinter->pSpoolList; pSpool; pSpool = pNextSpool )
  177. {
  178. pNextSpool = pSpool->pNextSpool;
  179. if ( pSpool->hChangeEvent )
  180. CloseHandle( pSpool->hChangeEvent );
  181. (VOID) NtClose( pSpool->hServer );
  182. //
  183. // Free all memory associated with the context handle
  184. //
  185. FreeNwSplMem( pSpool, sizeof( NWSPOOL) );
  186. }
  187. pPrinter->pSpoolList = NULL;
  188. FreeNwSplStr( pPrinter->pszServer );
  189. FreeNwSplStr( pPrinter->pszQueue );
  190. if ( pPrinter->pszUncConnection )
  191. {
  192. (void) NwrDeleteConnection( NULL,
  193. pPrinter->pszUncConnection,
  194. FALSE );
  195. FreeNwSplStr( pPrinter->pszUncConnection );
  196. }
  197. FreeNwSplMem( pPrinter, sizeof( NWPRINTER));
  198. }
  199. NwPrinterList = NULL;
  200. NwTimeOutValue = PRINTER_CHANGE_DEFAULT_TIMEOUT_VALUE;
  201. }
  202. DWORD
  203. NwrOpenPrinter(
  204. IN LPWSTR Reserved,
  205. IN LPWSTR pszPrinterName,
  206. IN DWORD fKnownPrinter,
  207. OUT LPNWWKSTA_PRINTER_CONTEXT phPrinter
  208. )
  209. /*++
  210. Routine Description:
  211. This routine retrieves a handle identifying the specified printer.
  212. Arguments:
  213. Reserved - Unused
  214. pszPrinterName - Name of the printer
  215. fKnownPrinter - TRUE if we have successfully opened the printer before,
  216. FALSE otherwise.
  217. phPrinter - Receives the handle that identifies the given printer
  218. Return Value:
  219. --*/
  220. {
  221. DWORD err;
  222. PNWSPOOL pSpool = NULL;
  223. LPWSTR pszServer = NULL;
  224. LPWSTR pszQueue = NULL;
  225. PNWPRINTER pPrinter = NULL;
  226. BOOL fImpersonate = FALSE ;
  227. HANDLE hServer;
  228. BOOL isPrinterNameValid;
  229. UNREFERENCED_PARAMETER( Reserved );
  230. if ( pszPrinterName[0] == L' ' &&
  231. pszPrinterName[1] == L'\\' &&
  232. pszPrinterName[2] == L'\\' )
  233. {
  234. if ( (pszServer = AllocNwSplStr( pszPrinterName + 1 )) == NULL )
  235. return ERROR_NOT_ENOUGH_MEMORY;
  236. isPrinterNameValid = ValidateUNCName( pszPrinterName + 1 );
  237. }
  238. else
  239. {
  240. if ( (pszServer = AllocNwSplStr( pszPrinterName )) == NULL )
  241. return ERROR_NOT_ENOUGH_MEMORY;
  242. isPrinterNameValid = ValidateUNCName( pszPrinterName );
  243. }
  244. CharUpperW( pszServer ); // convert in place
  245. //
  246. // ValidatePrinterName
  247. //
  248. if ( ( !isPrinterNameValid )
  249. || ( (pszQueue = wcschr( pszServer + 2, L'\\')) == NULL )
  250. || ( pszQueue == (pszServer + 2) )
  251. || ( *(pszQueue + 1) == L'\0' )
  252. )
  253. {
  254. FreeNwSplStr( pszServer );
  255. return ERROR_INVALID_NAME;
  256. }
  257. *pszQueue = L'\0'; // put a '\0' in place of '\\'
  258. pszQueue++; // Get past the '\0'
  259. if ( !(pSpool = AllocNwSplMem( LMEM_ZEROINIT, sizeof( NWSPOOL))))
  260. {
  261. err = ERROR_NOT_ENOUGH_MEMORY;
  262. goto ErrorExit;
  263. }
  264. //
  265. // Impersonate the client
  266. //
  267. if ((err = NwImpersonateClient()) != NO_ERROR)
  268. {
  269. goto ErrorExit;
  270. }
  271. fImpersonate = TRUE ;
  272. EnterCriticalSection( &NwPrintCritSec );
  273. if ((err = NwCreatePrinterEntry( pszServer, pszQueue, &pPrinter, &hServer)))
  274. {
  275. if ( !fKnownPrinter )
  276. {
  277. LeaveCriticalSection( &NwPrintCritSec );
  278. goto ErrorExit;
  279. }
  280. }
  281. //
  282. // Construct the print queue context handle to give back to the caller
  283. //
  284. pSpool->nSignature = NW_SIGNATURE;
  285. pSpool->errOpenPrinter = err;
  286. pSpool->hServer = hServer;
  287. pSpool->nStatus = 0;
  288. pSpool->nJobNumber = 0;
  289. pSpool->hChangeEvent= NULL;
  290. pSpool->nWaitFlags = 0;
  291. pSpool->nChangeFlags= 0;
  292. if ( !err )
  293. {
  294. pSpool->pPrinter = pPrinter;
  295. pSpool->pNextSpool = pPrinter->pSpoolList;
  296. pPrinter->pSpoolList= pSpool;
  297. }
  298. else
  299. {
  300. pSpool->pPrinter = NULL;
  301. pSpool->pNextSpool = NULL;
  302. }
  303. // We know about this printer before but failed to retrieve
  304. // it this time. Clean up the error and return successfully.
  305. // The error code is stored in the handle above which
  306. // will be returned on subsequent calls using this
  307. // dummy handle.
  308. err = NO_ERROR;
  309. LeaveCriticalSection( &NwPrintCritSec );
  310. ErrorExit:
  311. if (fImpersonate)
  312. (void) NwRevertToSelf() ;
  313. if ( err )
  314. {
  315. if ( pSpool )
  316. FreeNwSplMem( pSpool, sizeof( NWSPOOL) );
  317. }
  318. else
  319. {
  320. *phPrinter = (NWWKSTA_PRINTER_CONTEXT) pSpool;
  321. }
  322. //
  323. // Free up all allocated memories
  324. //
  325. *(pszServer + wcslen( pszServer)) = L'\\';
  326. FreeNwSplStr( pszServer );
  327. return err;
  328. }
  329. DWORD
  330. NwrClosePrinter(
  331. IN OUT LPNWWKSTA_PRINTER_CONTEXT phPrinter
  332. )
  333. /*++
  334. Routine Description:
  335. This routine closes the given printer object.
  336. Arguments:
  337. phPrinter - Handle of the printer object
  338. Return Value:
  339. --*/
  340. {
  341. PNWSPOOL pSpool = (PNWSPOOL) *phPrinter;
  342. PNWPRINTER pPrinter;
  343. PNWSPOOL pCur, pPrev = NULL;
  344. if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE ))
  345. return ERROR_INVALID_HANDLE;
  346. //
  347. // If OpenPrinter failed, then this is a dummy handle.
  348. // We just need to free up the memory.
  349. //
  350. if ( pSpool->errOpenPrinter )
  351. {
  352. //
  353. // invalidate the signature, but leave a recognizable value
  354. //
  355. pSpool->nSignature += 1 ;
  356. FreeNwSplMem( pSpool, sizeof( NWSPOOL) );
  357. *phPrinter = NULL;
  358. return NO_ERROR;
  359. }
  360. pPrinter = pSpool->pPrinter;
  361. ASSERT( pPrinter );
  362. //
  363. // Call EndDocPrinter if the user has not already done so
  364. //
  365. if ( pSpool->nStatus == SPOOL_STATUS_STARTDOC )
  366. {
  367. (void) NwrEndDocPrinter( *phPrinter );
  368. }
  369. else if ( pSpool->nStatus == SPOOL_STATUS_ADDJOB )
  370. {
  371. (void) NwrScheduleJob( *phPrinter, pSpool->nJobNumber );
  372. }
  373. if ( pSpool->hChangeEvent )
  374. CloseHandle( pSpool->hChangeEvent );
  375. pSpool->hChangeEvent = NULL;
  376. pSpool->nChangeFlags = 0;
  377. (VOID) NtClose( pSpool->hServer );
  378. EnterCriticalSection( &NwPrintCritSec );
  379. for ( pCur = pPrinter->pSpoolList; pCur;
  380. pPrev = pCur, pCur = pCur->pNextSpool )
  381. {
  382. if ( pCur == pSpool )
  383. {
  384. if ( pPrev )
  385. pPrev->pNextSpool = pCur->pNextSpool;
  386. else
  387. pPrinter->pSpoolList = pCur->pNextSpool;
  388. break;
  389. }
  390. }
  391. ASSERT( pCur );
  392. if ( pPrinter->pSpoolList == NULL )
  393. {
  394. #if DBG
  395. IF_DEBUG(PRINT)
  396. {
  397. KdPrint(("*************DELETED PRINTER ENTRY: %ws\\%ws\n\n",
  398. pPrinter->pszServer, pPrinter->pszQueue ));
  399. }
  400. #endif
  401. NwRemovePrinterEntry( pPrinter );
  402. }
  403. LeaveCriticalSection( &NwPrintCritSec );
  404. //
  405. // invalidate the signature, but leave a recognizable value
  406. //
  407. pSpool->nSignature += 1 ;
  408. pSpool->pNextSpool = NULL;
  409. pSpool->pPrinter = NULL;
  410. //
  411. // Free all memory associated with the context handle
  412. //
  413. FreeNwSplMem( pSpool, sizeof( NWSPOOL) );
  414. //
  415. // indicate to RPC we are done
  416. //
  417. *phPrinter = NULL;
  418. return NO_ERROR;
  419. }
  420. DWORD
  421. NwrGetPrinter(
  422. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  423. IN DWORD dwLevel,
  424. IN OUT LPBYTE pbPrinter,
  425. IN DWORD cbBuf,
  426. OUT LPDWORD pcbNeeded
  427. )
  428. /*++
  429. Routine Description:
  430. The routine retrieves information about the given printer.
  431. Arguments:
  432. hPrinter - Handle of the printer
  433. dwLevel - Specifies the level of the structure to which pbPrinter points.
  434. pbPrinter - Points to a buffer that receives the PRINTER_INFO object.
  435. cbBuf - Size, in bytes of the array pbPrinter points to.
  436. pcbNeeded - Points to a value which specifies the number of bytes copied
  437. if the function succeeds or the number of bytes required if
  438. cbBuf was too small.
  439. Return Value:
  440. --*/
  441. {
  442. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  443. PNWPRINTER pPrinter;
  444. LPBYTE pbEnd = pbPrinter + cbBuf;
  445. BOOL fFitInBuffer;
  446. DWORD_PTR *pOffsets;
  447. if ( !pSpool || pSpool->nSignature != NW_SIGNATURE )
  448. {
  449. return ERROR_INVALID_HANDLE;
  450. }
  451. else if ( pSpool->errOpenPrinter )
  452. {
  453. return pSpool->errOpenPrinter;
  454. }
  455. else if ( ( dwLevel != 1 ) && ( dwLevel != 2 ) && ( dwLevel != 3 ))
  456. {
  457. return ERROR_INVALID_LEVEL;
  458. }
  459. if ( !pbPrinter )
  460. {
  461. if ( cbBuf == 0 )
  462. {
  463. //
  464. // Calculate size needed
  465. //
  466. pPrinter = pSpool->pPrinter;
  467. ASSERT( pPrinter );
  468. if ( dwLevel == 1 )
  469. {
  470. *pcbNeeded = sizeof( PRINTER_INFO_1W ) +
  471. ( wcslen( pPrinter->pszServer )
  472. + wcslen( pPrinter->pszQueue ) + 2 ) * sizeof( WCHAR );
  473. }
  474. else if ( dwLevel == 2 )
  475. {
  476. *pcbNeeded = sizeof( PRINTER_INFO_2W ) +
  477. ( 2*wcslen( pPrinter->pszServer ) +
  478. 2*wcslen( pPrinter->pszQueue ) + 4 ) * sizeof( WCHAR );
  479. }
  480. else // Level == 3
  481. {
  482. PRINTER_INFO_3 *pPrinterInfo3 = (PRINTER_INFO_3 *) pbPrinter;
  483. *pcbNeeded = sizeof( PRINTER_INFO_3 );
  484. }
  485. return ERROR_INSUFFICIENT_BUFFER;
  486. }
  487. else
  488. return ERROR_INVALID_PARAMETER;
  489. }
  490. pPrinter = pSpool->pPrinter;
  491. ASSERT( pPrinter );
  492. if ( dwLevel == 1 )
  493. {
  494. PRINTER_INFO_1W *pPrinterInfo1 = (PRINTER_INFO_1W *) pbPrinter;
  495. LPBYTE pbFixedEnd = pbPrinter + sizeof( PRINTER_INFO_1W );
  496. //
  497. // Calculate size needed
  498. //
  499. *pcbNeeded = sizeof( PRINTER_INFO_1W ) +
  500. ( wcslen( pPrinter->pszServer )
  501. + wcslen( pPrinter->pszQueue ) + 2 ) * sizeof( WCHAR );
  502. if ( cbBuf < *pcbNeeded )
  503. return ERROR_INSUFFICIENT_BUFFER;
  504. pOffsets = PrinterInfo1Offsets;
  505. //
  506. // Fill in the structure
  507. //
  508. pPrinterInfo1->Flags = PRINTER_ENUM_REMOTE | PRINTER_ENUM_NAME;
  509. pPrinterInfo1->pComment = NULL;
  510. fFitInBuffer = NwlibCopyStringToBuffer(
  511. pPrinter->pszServer,
  512. wcslen( pPrinter->pszServer ),
  513. (LPWSTR) pbFixedEnd,
  514. (LPWSTR *) &pbEnd,
  515. &pPrinterInfo1->pDescription );
  516. ASSERT( fFitInBuffer );
  517. fFitInBuffer = NwlibCopyStringToBuffer(
  518. pPrinter->pszQueue,
  519. wcslen( pPrinter->pszQueue ),
  520. (LPWSTR) pbFixedEnd,
  521. (LPWSTR *) &pbEnd,
  522. &pPrinterInfo1->pName );
  523. ASSERT( fFitInBuffer );
  524. }
  525. else if ( dwLevel == 2 )
  526. {
  527. DWORD err;
  528. BYTE nQueueStatus;
  529. BYTE nNumJobs;
  530. PRINTER_INFO_2W *pPrinterInfo2 = (PRINTER_INFO_2W *) pbPrinter;
  531. LPBYTE pbFixedEnd = pbPrinter + sizeof( PRINTER_INFO_2W );
  532. //
  533. // Check if the buffer is big enough to hold all the data
  534. //
  535. *pcbNeeded = sizeof( PRINTER_INFO_2W ) +
  536. ( 2*wcslen( pPrinter->pszServer ) +
  537. 2*wcslen( pPrinter->pszQueue ) + 4 ) * sizeof( WCHAR );
  538. if ( cbBuf < *pcbNeeded )
  539. return ERROR_INSUFFICIENT_BUFFER;
  540. pOffsets = PrinterInfo2Offsets;
  541. err = NwReadQueueCurrentStatus( pSpool->hServer,
  542. pPrinter->nQueueId,
  543. &nQueueStatus,
  544. &nNumJobs );
  545. if ( err )
  546. return err;
  547. pPrinterInfo2->Status = (nQueueStatus & 0x05)? PRINTER_STATUS_PAUSED
  548. : 0;
  549. pPrinterInfo2->cJobs = nNumJobs;
  550. fFitInBuffer = NwlibCopyStringToBuffer(
  551. pPrinter->pszServer,
  552. wcslen( pPrinter->pszServer ),
  553. (LPCWSTR) pbFixedEnd,
  554. (LPWSTR *) &pbEnd,
  555. &pPrinterInfo2->pServerName );
  556. ASSERT( fFitInBuffer );
  557. pbEnd -= ( wcslen( pPrinter->pszQueue) + 1 ) * sizeof( WCHAR );
  558. wcscpy( (LPWSTR) pbEnd, pPrinter->pszQueue );
  559. pbEnd -= ( wcslen( pPrinter->pszServer) + 1 ) * sizeof( WCHAR );
  560. wcscpy( (LPWSTR) pbEnd, pPrinter->pszServer );
  561. *(pbEnd + wcslen( pPrinter->pszServer )*sizeof(WCHAR))= L'\\';
  562. pPrinterInfo2->pPrinterName = (LPWSTR) pbEnd;
  563. fFitInBuffer = NwlibCopyStringToBuffer(
  564. pPrinter->pszQueue,
  565. wcslen( pPrinter->pszQueue ),
  566. (LPCWSTR) pbFixedEnd,
  567. (LPWSTR *) &pbEnd,
  568. &pPrinterInfo2->pShareName );
  569. ASSERT( fFitInBuffer );
  570. pPrinterInfo2->pPortName = NULL;
  571. pPrinterInfo2->pDriverName = NULL;
  572. pPrinterInfo2->pComment = NULL;
  573. pPrinterInfo2->pLocation = NULL;
  574. pPrinterInfo2->pDevMode = NULL;
  575. pPrinterInfo2->pSepFile = NULL;
  576. pPrinterInfo2->pPrintProcessor = NULL;
  577. pPrinterInfo2->pDatatype = NULL;
  578. pPrinterInfo2->pParameters = NULL;
  579. pPrinterInfo2->pSecurityDescriptor = NULL;
  580. pPrinterInfo2->Attributes = PRINTER_ATTRIBUTE_QUEUED;
  581. pPrinterInfo2->Priority = 0;
  582. pPrinterInfo2->DefaultPriority = 0;
  583. pPrinterInfo2->StartTime = 0;
  584. pPrinterInfo2->UntilTime = 0;
  585. pPrinterInfo2->AveragePPM = 0;
  586. }
  587. else // Level == 3
  588. {
  589. PRINTER_INFO_3 *pPrinterInfo3 = (PRINTER_INFO_3 *) pbPrinter;
  590. *pcbNeeded = sizeof( PRINTER_INFO_3 );
  591. if ( cbBuf < *pcbNeeded )
  592. return ERROR_INSUFFICIENT_BUFFER;
  593. pOffsets = PrinterInfo3Offsets;
  594. pPrinterInfo3->pSecurityDescriptor = NULL;
  595. }
  596. MarshallDownStructure( pbPrinter, pOffsets, pbPrinter );
  597. return NO_ERROR;
  598. }
  599. DWORD
  600. NwrSetPrinter(
  601. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  602. IN DWORD dwCommand
  603. )
  604. /*++
  605. Routine Description:
  606. The routine sets information about the given printer.
  607. Arguments:
  608. hPrinter - Handle of the printer
  609. dwCommand - Specifies the new printer state
  610. Return Value:
  611. --*/
  612. {
  613. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  614. DWORD err = NO_ERROR;
  615. PNWPRINTER pPrinter;
  616. if ( !pSpool || pSpool->nSignature != NW_SIGNATURE )
  617. {
  618. return ERROR_INVALID_HANDLE;
  619. }
  620. else if ( pSpool->errOpenPrinter )
  621. {
  622. return pSpool->errOpenPrinter;
  623. }
  624. pPrinter = pSpool->pPrinter;
  625. ASSERT( pPrinter );
  626. switch ( dwCommand )
  627. {
  628. case PRINTER_CONTROL_PAUSE:
  629. case PRINTER_CONTROL_RESUME:
  630. {
  631. BYTE nQueueStatus = 0;
  632. BYTE nNumJobs;
  633. //
  634. // Get the original queue status so that we don't overwrite
  635. // some of the bits.
  636. //
  637. err = NwReadQueueCurrentStatus( pSpool->hServer,
  638. pPrinter->nQueueId,
  639. &nQueueStatus,
  640. &nNumJobs );
  641. if ( !err )
  642. {
  643. //
  644. // Clear the pause bits, and leave the rest alone.
  645. //
  646. nQueueStatus &= ~0x05;
  647. }
  648. if ( dwCommand == PRINTER_CONTROL_PAUSE )
  649. {
  650. nQueueStatus |= 0x04;
  651. }
  652. err = NwSetQueueCurrentStatus( pSpool->hServer,
  653. pPrinter->nQueueId,
  654. nQueueStatus );
  655. if ( !err )
  656. NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_PRINTER );
  657. break;
  658. }
  659. case PRINTER_CONTROL_PURGE:
  660. err = NwRemoveAllJobsFromQueue( pSpool->hServer,
  661. pPrinter->nQueueId );
  662. if ( !err )
  663. NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_PRINTER |
  664. PRINTER_CHANGE_DELETE_JOB );
  665. break;
  666. default:
  667. //
  668. // dwCommand is 0 so that means
  669. // some properties of the printer has changed.
  670. // We will ignore the properties that
  671. // are being modified since most properties
  672. // are stored in the registry by spooler.
  673. // All we need to do is to signal WaitForPrinterChange to
  674. // return so that print manager will refresh its data.
  675. //
  676. ASSERT( dwCommand == 0 );
  677. NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_PRINTER );
  678. break;
  679. }
  680. return err;
  681. }
  682. DWORD
  683. NwrEnumPrinters(
  684. IN LPWSTR Reserved,
  685. IN LPWSTR pszName,
  686. IN OUT LPBYTE pbPrinter,
  687. IN DWORD cbBuf,
  688. OUT LPDWORD pcbNeeded,
  689. OUT LPDWORD pcReturned
  690. )
  691. /*++
  692. Routine Description:
  693. This routine enumerates the available providers, servers, printers
  694. depending on the given pszName.
  695. Arguments:
  696. Reserved - Unused
  697. pszName - The name of the container object
  698. pbPrinter - Points to the array to receive the PRINTER_INFO objects
  699. cbBuf - Size, in bytes of pbPrinter
  700. pcbNeeded - Count of bytes needed
  701. pcReturned - Count of PRINTER_INFO objects
  702. Return Value:
  703. --*/
  704. {
  705. PRINTER_INFO_1W *pPrinterInfo1 = (PRINTER_INFO_1W *) pbPrinter;
  706. *pcbNeeded = 0;
  707. *pcReturned = 0;
  708. if ( ( cbBuf != 0 ) && !pbPrinter )
  709. {
  710. return ERROR_INVALID_PARAMETER;
  711. }
  712. if ( !pszName ) // Enumerate the provider name
  713. {
  714. BOOL fFitInBuffer;
  715. LPBYTE pbFixedEnd = pbPrinter + sizeof( PRINTER_INFO_1W );
  716. LPBYTE pbEnd = pbPrinter + cbBuf;
  717. *pcbNeeded = sizeof( PRINTER_INFO_1W ) +
  718. ( 2 * wcslen( NwProviderName ) +
  719. + 2) * sizeof(WCHAR);
  720. if ( *pcbNeeded > cbBuf )
  721. return ERROR_INSUFFICIENT_BUFFER;
  722. pPrinterInfo1->Flags = PRINTER_ENUM_ICON1 |
  723. PRINTER_ENUM_CONTAINER |
  724. PRINTER_ENUM_EXPAND;
  725. pPrinterInfo1->pComment = NULL;
  726. fFitInBuffer = NwlibCopyStringToBuffer(
  727. NwProviderName,
  728. wcslen( NwProviderName ),
  729. (LPWSTR) pbFixedEnd,
  730. (LPWSTR *) &pbEnd,
  731. &pPrinterInfo1->pDescription );
  732. ASSERT( fFitInBuffer );
  733. fFitInBuffer = NwlibCopyStringToBuffer(
  734. NwProviderName,
  735. wcslen( NwProviderName ),
  736. (LPWSTR) pbFixedEnd,
  737. (LPWSTR *) &pbEnd,
  738. &pPrinterInfo1->pName );
  739. ASSERT( fFitInBuffer );
  740. MarshallDownStructure( pbPrinter, PrinterInfo1Offsets, pbPrinter );
  741. *pcReturned = 1;
  742. }
  743. else if ( pszName && *pszName )
  744. {
  745. DWORD err;
  746. LPWSTR pszFullName;
  747. LPWSTR pszServer;
  748. NWWKSTA_CONTEXT_HANDLE handle;
  749. BYTE bTemp = 0;
  750. LPBYTE pbTempBuf = pbPrinter ? pbPrinter : &bTemp;
  751. if ( (pszFullName = LocalAlloc( 0, (wcslen( pszName ) + 1) *
  752. sizeof(WCHAR) ) ) == NULL )
  753. return ERROR_NOT_ENOUGH_MEMORY;
  754. wcscpy( pszFullName, pszName );
  755. pszServer = wcschr( pszFullName, L'!');
  756. if ( pszServer )
  757. *pszServer++ = 0;
  758. if ( lstrcmpiW( pszFullName, NwProviderName ) )
  759. {
  760. LocalFree( pszFullName );
  761. return ERROR_INVALID_NAME;
  762. }
  763. if ( !pszServer ) // Enumerate servers
  764. {
  765. LocalFree( pszFullName );
  766. err = NwOpenEnumPrintServers( &handle );
  767. if ( err != NO_ERROR )
  768. {
  769. return err;
  770. }
  771. err = NwrEnum( handle,
  772. (DWORD_PTR) -1,
  773. pbTempBuf,
  774. cbBuf,
  775. pcbNeeded,
  776. pcReturned );
  777. if ( err != NO_ERROR )
  778. {
  779. NwrCloseEnum( &handle );
  780. return err;
  781. }
  782. err = NwrCloseEnum( &handle );
  783. if ( err != NO_ERROR )
  784. {
  785. return err;
  786. }
  787. }
  788. else // Enumerate NDS sub-trees or print queues
  789. {
  790. LPWSTR tempStrPtr = pszServer;
  791. DWORD dwClassType = 0;
  792. if ( tempStrPtr[0] == L'\\' &&
  793. tempStrPtr[1] == L'\\' &&
  794. tempStrPtr[2] == L' ' )
  795. tempStrPtr = &tempStrPtr[1];
  796. err = NwrOpenEnumNdsSubTrees_Print( NULL, tempStrPtr, &dwClassType, &handle );
  797. if ( err == ERROR_NETWORK_ACCESS_DENIED && dwClassType == CLASS_TYPE_NCP_SERVER )
  798. {
  799. // An error code from the above NwOpenEnumNdsSubTrees could have
  800. // failed because the object was a server, which cannot be enumerated
  801. // with the NDS tree APIs. If so we try to get the print queues with the
  802. // regular NW APIs.
  803. tempStrPtr = NwGetUncObjectName( tempStrPtr );
  804. err = NwOpenEnumPrintQueues( tempStrPtr, &handle );
  805. if ( err != NO_ERROR )
  806. {
  807. LocalFree( pszFullName );
  808. return err;
  809. }
  810. }
  811. if ( err != NO_ERROR )
  812. {
  813. // An error code from the above NwOpenEnumNdsSubTrees could have
  814. // failed because the object was not a part of an NDS tree.
  815. // So we try to get the print queues with the regular NW APIs.
  816. err = NwOpenEnumPrintQueues( tempStrPtr, &handle );
  817. if ( err != NO_ERROR )
  818. {
  819. LocalFree( pszFullName );
  820. return err;
  821. }
  822. }
  823. //
  824. // Get rid of the allocated temp buffer that we've been using
  825. // indirectly through tempStrPtr and pszServer.
  826. //
  827. LocalFree( pszFullName );
  828. err = NwrEnum( handle,
  829. 0xFFFFFFFF,
  830. pbTempBuf,
  831. cbBuf,
  832. pcbNeeded,
  833. pcReturned );
  834. if ( err != NO_ERROR )
  835. {
  836. NwrCloseEnum( &handle );
  837. return err;
  838. }
  839. err = NwrCloseEnum( &handle );
  840. if ( err != NO_ERROR )
  841. {
  842. return err;
  843. }
  844. }
  845. }
  846. return NO_ERROR;
  847. }
  848. DWORD
  849. NwrStartDocPrinter(
  850. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  851. IN LPWSTR pszDocument,
  852. IN LPWSTR pszUser,
  853. IN DWORD PrintOptions, //Multi-User Addition
  854. IN DWORD fGateway
  855. )
  856. /*++
  857. Routine Description:
  858. This routine informs the print spooler that a document is to be spooled
  859. for printing.
  860. Arguments:
  861. hPrinter - Handle of the printer
  862. pszDocument - Name of the document to be printed
  863. pszUser - Name of the user submitting the print job
  864. fGateway - TRUE if it is gateway printing
  865. Return Value:
  866. --*/
  867. {
  868. DWORD err;
  869. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  870. if ( !pSpool || (pSpool->nSignature != NW_SIGNATURE) )
  871. {
  872. err = ERROR_INVALID_HANDLE;
  873. }
  874. else if ( pSpool->errOpenPrinter )
  875. {
  876. err = pSpool->errOpenPrinter;
  877. }
  878. else if ( pSpool->nStatus != 0 )
  879. {
  880. err = ERROR_INVALID_PARAMETER;
  881. }
  882. else
  883. {
  884. //
  885. // Get pSpool->nJobNumber from CreateQueueJobAndFile
  886. //
  887. PNWPRINTER pPrinter = pSpool->pPrinter;
  888. WORD nJobNumber = 0;
  889. ASSERT( pPrinter );
  890. err = NwCreateQueueJobAndFile( pSpool->hServer,
  891. pPrinter->nQueueId,
  892. pszDocument,
  893. pszUser,
  894. fGateway,
  895. PrintOptions, //Multi-User addition
  896. pPrinter->pszQueue,
  897. &nJobNumber );
  898. if ( !err )
  899. {
  900. pSpool->nJobNumber = nJobNumber;
  901. pSpool->nStatus = SPOOL_STATUS_STARTDOC;
  902. NwSetPrinterChange( pSpool, PRINTER_CHANGE_ADD_JOB |
  903. PRINTER_CHANGE_SET_PRINTER );
  904. }
  905. }
  906. return err;
  907. }
  908. DWORD
  909. NwrWritePrinter(
  910. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  911. IN LPBYTE pBuf,
  912. IN DWORD cbBuf,
  913. OUT LPDWORD pcbWritten
  914. )
  915. /*++
  916. Routine Description:
  917. This routine informs the print spooler that the specified data should be
  918. written to the given printer.
  919. Arguments:
  920. hPrinter - Handle of the printer object
  921. pBuf - Address of array that contains printer data
  922. cbBuf - Size, in bytes of pBuf
  923. pcbWritten - Receives the number of bytes actually written to the printer
  924. Return Value:
  925. --*/
  926. {
  927. DWORD err = NO_ERROR;
  928. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  929. if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE))
  930. {
  931. err = ERROR_INVALID_HANDLE;
  932. }
  933. else if ( pSpool->errOpenPrinter )
  934. {
  935. err = pSpool->errOpenPrinter;
  936. }
  937. else if ( pSpool->nStatus != SPOOL_STATUS_STARTDOC )
  938. {
  939. err = ERROR_INVALID_PARAMETER;
  940. }
  941. else
  942. {
  943. NTSTATUS ntstatus;
  944. IO_STATUS_BLOCK IoStatusBlock;
  945. PNWPRINTER pPrinter = pSpool->pPrinter;
  946. ASSERT( pPrinter );
  947. ntstatus = NtWriteFile( pSpool->hServer,
  948. NULL,
  949. NULL,
  950. NULL,
  951. &IoStatusBlock,
  952. pBuf,
  953. cbBuf,
  954. NULL,
  955. NULL );
  956. if ( NT_SUCCESS(ntstatus))
  957. ntstatus = IoStatusBlock.Status;
  958. if ( NT_SUCCESS(ntstatus) )
  959. {
  960. *pcbWritten = (DWORD) IoStatusBlock.Information;
  961. NwSetPrinterChange( pSpool, PRINTER_CHANGE_WRITE_JOB );
  962. }
  963. else
  964. {
  965. KdPrint(("NWWORKSTATION: NtWriteFile failed 0x%08lx\n", ntstatus));
  966. *pcbWritten = 0;
  967. err = RtlNtStatusToDosError( ntstatus );
  968. }
  969. }
  970. return err;
  971. }
  972. DWORD
  973. NwrAbortPrinter(
  974. IN NWWKSTA_PRINTER_CONTEXT hPrinter
  975. )
  976. /*++
  977. Routine Description:
  978. This routine deletes a printer's spool file if the printer is configured
  979. for spooling.
  980. Arguments:
  981. hPrinter - Handle of the printer object
  982. Return Value:
  983. --*/
  984. {
  985. DWORD err;
  986. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  987. if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE ))
  988. {
  989. err = ERROR_INVALID_HANDLE;
  990. }
  991. else if ( pSpool->errOpenPrinter )
  992. {
  993. err = pSpool->errOpenPrinter;
  994. }
  995. else if ( pSpool->nStatus != SPOOL_STATUS_STARTDOC )
  996. {
  997. err = ERROR_INVALID_PARAMETER;
  998. }
  999. else
  1000. {
  1001. PNWPRINTER pPrinter = pSpool->pPrinter;
  1002. ASSERT( pPrinter );
  1003. err = NwRemoveJobFromQueue( pSpool->hServer,
  1004. pPrinter->nQueueId,
  1005. (WORD) pSpool->nJobNumber );
  1006. if ( !err )
  1007. {
  1008. pSpool->nJobNumber = 0;
  1009. pSpool->nStatus = SPOOL_STATUS_ABORT;
  1010. NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_JOB );
  1011. }
  1012. }
  1013. return err;
  1014. }
  1015. DWORD
  1016. NwrEndDocPrinter(
  1017. IN NWWKSTA_PRINTER_CONTEXT hPrinter
  1018. )
  1019. /*++
  1020. Routine Description:
  1021. This routine ends the print job for the given printer.
  1022. Arguments:
  1023. hPrinter - Handle of the printer object
  1024. Return Value:
  1025. --*/
  1026. {
  1027. DWORD err = NO_ERROR;
  1028. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  1029. if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE ))
  1030. {
  1031. err = ERROR_INVALID_HANDLE;
  1032. }
  1033. else if ( pSpool->errOpenPrinter )
  1034. {
  1035. err = pSpool->errOpenPrinter;
  1036. }
  1037. else if ( ( pSpool->nStatus != SPOOL_STATUS_STARTDOC )
  1038. && ( pSpool->nStatus != SPOOL_STATUS_ABORT )
  1039. )
  1040. {
  1041. err = ERROR_INVALID_PARAMETER;
  1042. }
  1043. else
  1044. {
  1045. PNWPRINTER pPrinter = pSpool->pPrinter;
  1046. ASSERT( pPrinter );
  1047. if ( pSpool->nStatus == SPOOL_STATUS_STARTDOC )
  1048. {
  1049. err = NwCloseFileAndStartQueueJob( pSpool->hServer,
  1050. pPrinter->nQueueId,
  1051. (WORD) pSpool->nJobNumber );
  1052. if ( !err )
  1053. NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_JOB );
  1054. }
  1055. if ( !err )
  1056. {
  1057. pSpool->nJobNumber = 0;
  1058. pSpool->nStatus = 0;
  1059. }
  1060. }
  1061. return err;
  1062. }
  1063. DWORD
  1064. NwrGetJob(
  1065. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  1066. IN DWORD dwJobId,
  1067. IN DWORD dwLevel,
  1068. IN OUT LPBYTE pbJob,
  1069. IN DWORD cbBuf,
  1070. OUT LPDWORD pcbNeeded
  1071. )
  1072. /*++
  1073. Routine Description:
  1074. Arguments:
  1075. hPrinter - Handle of the printer
  1076. dwJobId -
  1077. dwLevel -
  1078. pbJob -
  1079. cbBuf -
  1080. pcbNeeded -
  1081. Return Value:
  1082. --*/
  1083. {
  1084. DWORD err;
  1085. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  1086. if ( !pSpool || pSpool->nSignature != NW_SIGNATURE )
  1087. {
  1088. err = ERROR_INVALID_HANDLE;
  1089. }
  1090. // allow NULL for bpJob if cbBuf is 0.
  1091. // Relies on NwGetQueueJobInfo to properly handle NULL pointer in request to fill pcbNeeded
  1092. else if ( (cbBuf != 0) && ( !pbJob ) )
  1093. {
  1094. err = ERROR_INVALID_PARAMETER;
  1095. }
  1096. else if ( pSpool->errOpenPrinter )
  1097. {
  1098. err = pSpool->errOpenPrinter;
  1099. }
  1100. else if (( dwLevel != 1 ) && ( dwLevel != 2 ))
  1101. {
  1102. err = ERROR_INVALID_LEVEL;
  1103. }
  1104. else
  1105. {
  1106. DWORD nPrinterLen;
  1107. LPWSTR pszPrinter;
  1108. LPBYTE FixedPortion = pbJob;
  1109. LPWSTR EndOfVariableData = (LPWSTR) (pbJob + cbBuf);
  1110. PNWPRINTER pPrinter = pSpool->pPrinter;
  1111. ASSERT( pPrinter );
  1112. pszPrinter = AllocNwSplMem( LMEM_ZEROINIT,
  1113. nPrinterLen = ( wcslen( pPrinter->pszServer) +
  1114. wcslen( pPrinter->pszQueue) + 2) * sizeof(WCHAR));
  1115. if ( pszPrinter == NULL )
  1116. return ERROR_NOT_ENOUGH_MEMORY;
  1117. wcscpy( pszPrinter, pPrinter->pszServer );
  1118. wcscat( pszPrinter, L"\\" );
  1119. wcscat( pszPrinter, pPrinter->pszQueue );
  1120. *pcbNeeded = 0;
  1121. err = NwGetQueueJobInfo( pSpool->hServer,
  1122. pPrinter->nQueueId,
  1123. (WORD) dwJobId,
  1124. pszPrinter,
  1125. dwLevel,
  1126. &FixedPortion,
  1127. &EndOfVariableData,
  1128. pcbNeeded );
  1129. FreeNwSplMem( pszPrinter, nPrinterLen );
  1130. if ( !err )
  1131. {
  1132. switch( dwLevel )
  1133. {
  1134. case 1:
  1135. MarshallDownStructure( pbJob, JobInfo1Offsets, pbJob );
  1136. break;
  1137. case 2:
  1138. MarshallDownStructure( pbJob, JobInfo2Offsets, pbJob );
  1139. break;
  1140. default:
  1141. ASSERT( FALSE );
  1142. break;
  1143. }
  1144. }
  1145. }
  1146. return err;
  1147. }
  1148. DWORD
  1149. NwrEnumJobs(
  1150. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  1151. IN DWORD dwFirstJob,
  1152. IN DWORD dwNoJobs,
  1153. IN DWORD dwLevel,
  1154. IN OUT LPBYTE pbJob,
  1155. IN DWORD cbBuf,
  1156. OUT LPDWORD pcbNeeded,
  1157. OUT LPDWORD pcReturned
  1158. )
  1159. /*++
  1160. Routine Description:
  1161. Arguments:
  1162. hPrinter - Handle of the printer
  1163. dwFirstJob -
  1164. dwNoJobs -
  1165. dwLevel -
  1166. pbJob -
  1167. cbBuf -
  1168. pcbNeeded -
  1169. pcReturned -
  1170. Return Value:
  1171. --*/
  1172. {
  1173. DWORD err;
  1174. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  1175. if ( !pSpool || pSpool->nSignature != NW_SIGNATURE )
  1176. {
  1177. err = ERROR_INVALID_HANDLE;
  1178. }
  1179. // allow NULL for bpJob if cbBuf is 0.
  1180. // Relies on NwGetQueueJobInfo to properly handle NULL pointer in request to fill pcbNeeded
  1181. else if ( (cbBuf != 0) && ( !pbJob ) )
  1182. {
  1183. err = ERROR_INVALID_PARAMETER;
  1184. }
  1185. else if ( pSpool->errOpenPrinter )
  1186. {
  1187. err = pSpool->errOpenPrinter;
  1188. }
  1189. else if ( ( dwLevel != 1 ) && ( dwLevel != 2 ) )
  1190. {
  1191. err = ERROR_INVALID_LEVEL;
  1192. }
  1193. else
  1194. {
  1195. PNWPRINTER pPrinter = pSpool->pPrinter;
  1196. LPWSTR pszPrinter;
  1197. DWORD nPrinterLen;
  1198. ASSERT( pPrinter );
  1199. pszPrinter = AllocNwSplMem( LMEM_ZEROINIT,
  1200. nPrinterLen = ( wcslen( pPrinter->pszServer ) +
  1201. wcslen( pPrinter->pszQueue) + 2) * sizeof(WCHAR));
  1202. if ( pszPrinter == NULL )
  1203. return ERROR_NOT_ENOUGH_MEMORY;
  1204. wcscpy( pszPrinter, pPrinter->pszServer );
  1205. wcscat( pszPrinter, L"\\" );
  1206. wcscat( pszPrinter, pPrinter->pszQueue );
  1207. err = NwGetQueueJobs( pSpool->hServer,
  1208. pPrinter->nQueueId,
  1209. pszPrinter,
  1210. dwFirstJob,
  1211. dwNoJobs,
  1212. dwLevel,
  1213. pbJob,
  1214. cbBuf,
  1215. pcbNeeded,
  1216. pcReturned );
  1217. FreeNwSplMem( pszPrinter, nPrinterLen );
  1218. if ( !err )
  1219. {
  1220. DWORD_PTR *pOffsets;
  1221. DWORD cbStruct;
  1222. DWORD cReturned = *pcReturned;
  1223. LPBYTE pbBuffer = pbJob;
  1224. switch( dwLevel )
  1225. {
  1226. case 1:
  1227. pOffsets = JobInfo1Offsets;
  1228. cbStruct = sizeof( JOB_INFO_1W );
  1229. break;
  1230. case 2:
  1231. pOffsets = JobInfo2Offsets;
  1232. cbStruct = sizeof( JOB_INFO_2W );
  1233. break;
  1234. default:
  1235. ASSERT( FALSE );
  1236. break;
  1237. }
  1238. while ( cReturned-- )
  1239. {
  1240. MarshallDownStructure( pbBuffer, pOffsets, pbJob );
  1241. pbBuffer += cbStruct;
  1242. }
  1243. }
  1244. }
  1245. return err;
  1246. }
  1247. DWORD
  1248. NwrSetJob(
  1249. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  1250. IN DWORD dwJobId,
  1251. IN DWORD dwLevel,
  1252. IN PNW_JOB_INFO pNwJobInfo,
  1253. IN DWORD dwCommand
  1254. )
  1255. /*++
  1256. Routine Description:
  1257. Arguments:
  1258. hPrinter - Handle of the printer
  1259. dwJobId -
  1260. dwLevel -
  1261. pNwJobInfo-
  1262. dwCommand -
  1263. Return Value:
  1264. --*/
  1265. {
  1266. DWORD err = NO_ERROR;
  1267. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  1268. PNWPRINTER pPrinter;
  1269. if ( !pSpool || pSpool->nSignature != NW_SIGNATURE )
  1270. {
  1271. err = ERROR_INVALID_HANDLE;
  1272. }
  1273. else if ( ( dwLevel != 0 ) && ( !pNwJobInfo ) )
  1274. {
  1275. err = ERROR_INVALID_PARAMETER;
  1276. }
  1277. else if ( pSpool->errOpenPrinter )
  1278. {
  1279. err = pSpool->errOpenPrinter;
  1280. }
  1281. else if ( ( dwLevel != 0 ) && ( dwLevel != 1 ) && ( dwLevel != 2 ) )
  1282. {
  1283. err = ERROR_INVALID_LEVEL;
  1284. }
  1285. if ( err )
  1286. return err;
  1287. pPrinter = pSpool->pPrinter;
  1288. ASSERT( pPrinter );
  1289. if ( ( dwCommand == JOB_CONTROL_CANCEL ) ||
  1290. ( dwCommand == JOB_CONTROL_DELETE ) )
  1291. {
  1292. err = NwRemoveJobFromQueue( pSpool->hServer,
  1293. pPrinter->nQueueId,
  1294. (WORD) dwJobId );
  1295. if ( !err )
  1296. NwSetPrinterChange( pSpool, PRINTER_CHANGE_DELETE_JOB |
  1297. PRINTER_CHANGE_SET_PRINTER );
  1298. // Since the job is removed, we don't need to change other
  1299. // information about it.
  1300. }
  1301. else
  1302. {
  1303. if ( dwLevel != 0 )
  1304. {
  1305. if ( pNwJobInfo->nPosition != JOB_POSITION_UNSPECIFIED )
  1306. {
  1307. err = NwChangeQueueJobPosition( pSpool->hServer,
  1308. pPrinter->nQueueId,
  1309. (WORD) dwJobId,
  1310. (BYTE) pNwJobInfo->nPosition );
  1311. }
  1312. }
  1313. if ( ( !err ) && ( dwCommand == JOB_CONTROL_RESTART ))
  1314. {
  1315. err = ERROR_NOT_SUPPORTED;
  1316. }
  1317. else if ( !err )
  1318. {
  1319. err = NwChangeQueueJobEntry( pSpool->hServer,
  1320. pPrinter->nQueueId,
  1321. (WORD) dwJobId,
  1322. dwCommand,
  1323. pNwJobInfo );
  1324. }
  1325. if ( !err )
  1326. NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_JOB );
  1327. }
  1328. return err;
  1329. }
  1330. DWORD
  1331. NwrAddJob(
  1332. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  1333. OUT LPADDJOB_INFO_1W pAddInfo1,
  1334. IN DWORD cbBuf,
  1335. OUT LPDWORD pcbNeeded
  1336. )
  1337. /*++
  1338. Routine Description:
  1339. Arguments:
  1340. hPrinter - Handle of the printer.
  1341. pAddInfo1 - Output buffer to hold ADDJOB_INFO_1W structure.
  1342. cbBuf - Output buffer size in bytes.
  1343. pcbNeeded - Required output buffer size in bytes.
  1344. Return Value:
  1345. --*/
  1346. {
  1347. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  1348. PNWPRINTER pPrinter;
  1349. if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE )) {
  1350. return ERROR_INVALID_HANDLE;
  1351. }
  1352. if ( pSpool->errOpenPrinter ) {
  1353. return pSpool->errOpenPrinter;
  1354. }
  1355. if ( pSpool->nStatus != 0 ) {
  1356. return ERROR_INVALID_PARAMETER;
  1357. }
  1358. pPrinter = pSpool->pPrinter;
  1359. ASSERT( pPrinter );
  1360. *pcbNeeded = sizeof(ADDJOB_INFO_1W) +
  1361. (wcslen(pPrinter->pszServer) +
  1362. wcslen(pPrinter->pszQueue) + 2) * sizeof(WCHAR);
  1363. if (cbBuf < *pcbNeeded) {
  1364. return ERROR_INSUFFICIENT_BUFFER;
  1365. }
  1366. //
  1367. // Write UNC path name into the output buffer.
  1368. //
  1369. // dfergus 19 Apr 2001 - 348006
  1370. // DWORD cast
  1371. pAddInfo1->Path = (LPWSTR) ((DWORD) pAddInfo1 + sizeof(ADDJOB_INFO_1W));
  1372. //
  1373. wcscpy(pAddInfo1->Path, pPrinter->pszServer);
  1374. wcscat(pAddInfo1->Path, L"\\" );
  1375. wcscat(pAddInfo1->Path, pPrinter->pszQueue);
  1376. //
  1377. // Return special job id value which the client (winspool.drv) looks
  1378. // for and does an FSCTL call to our redirector to get the real
  1379. // job id. We cannot return a real job id at this point because
  1380. // the CreateQueueJobAndFile NCP is not issue until the client opens
  1381. // the UNC name we return in this API.
  1382. //
  1383. pAddInfo1->JobId = (DWORD) -1;
  1384. //
  1385. // Save context information
  1386. //
  1387. pSpool->nJobNumber = pAddInfo1->JobId;
  1388. pSpool->nStatus = SPOOL_STATUS_ADDJOB;
  1389. #if DBG
  1390. IF_DEBUG(PRINT) {
  1391. KdPrint(("NWWORKSTATION: NwrAddJob Path=%ws, JobId=%lu, BytesNeeded=%lu\n",
  1392. pAddInfo1->Path, pAddInfo1->JobId, *pcbNeeded));
  1393. }
  1394. #endif
  1395. NwSetPrinterChange( pSpool, PRINTER_CHANGE_ADD_JOB |
  1396. PRINTER_CHANGE_SET_PRINTER );
  1397. return NO_ERROR;
  1398. }
  1399. DWORD
  1400. NwrScheduleJob(
  1401. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  1402. IN DWORD dwJobId
  1403. )
  1404. /*++
  1405. Routine Description:
  1406. Arguments:
  1407. hPrinter - Handle of the printer
  1408. dwJobId - Job identification number
  1409. Return Value:
  1410. --*/
  1411. {
  1412. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  1413. PNWPRINTER pPrinter;
  1414. if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE )) {
  1415. return ERROR_INVALID_HANDLE;
  1416. }
  1417. if ( pSpool->errOpenPrinter ) {
  1418. return pSpool->errOpenPrinter;
  1419. }
  1420. if (pSpool->nStatus != SPOOL_STATUS_ADDJOB) {
  1421. return ERROR_INVALID_PARAMETER;
  1422. }
  1423. pPrinter = pSpool->pPrinter;
  1424. ASSERT( pPrinter );
  1425. pSpool->nJobNumber = 0;
  1426. pSpool->nStatus = 0;
  1427. NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_JOB );
  1428. return NO_ERROR;
  1429. }
  1430. DWORD
  1431. NwrWaitForPrinterChange(
  1432. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  1433. IN OUT LPDWORD pdwFlags
  1434. )
  1435. /*++
  1436. Routine Description:
  1437. Arguments:
  1438. hPrinter - Handle of the printer
  1439. pdwFlags -
  1440. Return Value:
  1441. --*/
  1442. {
  1443. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  1444. HANDLE hChangeEvent = NULL;
  1445. DWORD nRetVal;
  1446. HANDLE ahWaitEvents[2];
  1447. DWORD err = NO_ERROR;
  1448. if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE ))
  1449. {
  1450. return ERROR_INVALID_HANDLE;
  1451. }
  1452. else if ( pSpool->errOpenPrinter )
  1453. {
  1454. return pSpool->errOpenPrinter;
  1455. }
  1456. else if ( pSpool->hChangeEvent )
  1457. {
  1458. return ERROR_ALREADY_WAITING;
  1459. }
  1460. else if ( !(*pdwFlags & PRINTER_CHANGE_VALID ))
  1461. {
  1462. return ERROR_INVALID_PARAMETER;
  1463. }
  1464. if ( pSpool->nChangeFlags & *pdwFlags )
  1465. {
  1466. //
  1467. // There is a change since we last called
  1468. //
  1469. *pdwFlags &= pSpool->nChangeFlags;
  1470. EnterCriticalSection( &NwPrintCritSec );
  1471. pSpool->nChangeFlags = 0;
  1472. LeaveCriticalSection( &NwPrintCritSec );
  1473. return NO_ERROR;
  1474. }
  1475. hChangeEvent = CreateEvent( NULL,
  1476. FALSE, // automatic reset
  1477. FALSE, // initial state not signalled
  1478. NULL );
  1479. if ( !hChangeEvent )
  1480. {
  1481. KdPrint(("WaitForPrinterChange: CreateEvent failed with error %d\n",
  1482. GetLastError() ));
  1483. return GetLastError();
  1484. }
  1485. pSpool->nWaitFlags = *pdwFlags;
  1486. EnterCriticalSection( &NwPrintCritSec );
  1487. pSpool->hChangeEvent = hChangeEvent;
  1488. pSpool->nChangeFlags = 0;
  1489. LeaveCriticalSection( &NwPrintCritSec );
  1490. ahWaitEvents[0] = pSpool->hChangeEvent;
  1491. ahWaitEvents[1] = NwDoneEvent;
  1492. nRetVal = WaitForMultipleObjects( 2, // Two events to wait for
  1493. ahWaitEvents,
  1494. FALSE, // Wait for one to signal
  1495. NwTimeOutValue );
  1496. switch ( nRetVal )
  1497. {
  1498. case WAIT_FAILED:
  1499. err = GetLastError();
  1500. break;
  1501. case WAIT_TIMEOUT:
  1502. case WAIT_OBJECT_0 + 1: // treats service stopping as timeout
  1503. *pdwFlags |= PRINTER_CHANGE_TIMEOUT;
  1504. break;
  1505. case WAIT_OBJECT_0:
  1506. *pdwFlags &= pSpool->nChangeFlags;
  1507. break;
  1508. default:
  1509. KdPrint(("WaitForPrinterChange: WaitForMultipleObjects returned with %d\n", nRetVal ));
  1510. *pdwFlags |= PRINTER_CHANGE_TIMEOUT;
  1511. break;
  1512. }
  1513. if ( ( !err ) && ( nRetVal != WAIT_OBJECT_0 + 1 ) )
  1514. {
  1515. pSpool->nWaitFlags = 0;
  1516. EnterCriticalSection( &NwPrintCritSec );
  1517. pSpool->nChangeFlags = 0;
  1518. pSpool->hChangeEvent = NULL;
  1519. LeaveCriticalSection( &NwPrintCritSec );
  1520. }
  1521. if ( !CloseHandle( hChangeEvent ) )
  1522. {
  1523. KdPrint(("WaitForPrinterChange: CloseHandle failed with error %d\n",
  1524. GetLastError()));
  1525. }
  1526. return err;
  1527. }
  1528. VOID
  1529. NwSetPrinterChange(
  1530. PNWSPOOL pSpool,
  1531. DWORD nFlags
  1532. )
  1533. {
  1534. PNWPRINTER pPrinter = pSpool->pPrinter;
  1535. PNWSPOOL pCurSpool = pSpool;
  1536. EnterCriticalSection( &NwPrintCritSec );
  1537. do {
  1538. if ( pCurSpool->nWaitFlags & nFlags )
  1539. {
  1540. pCurSpool->nChangeFlags |= nFlags;
  1541. if ( pCurSpool->hChangeEvent )
  1542. {
  1543. SetEvent( pCurSpool->hChangeEvent );
  1544. pCurSpool->hChangeEvent = NULL;
  1545. }
  1546. }
  1547. pCurSpool = pCurSpool->pNextSpool;
  1548. if ( pCurSpool == NULL )
  1549. pCurSpool = pPrinter->pSpoolList;
  1550. } while ( pCurSpool && (pCurSpool != pSpool) );
  1551. LeaveCriticalSection( &NwPrintCritSec );
  1552. }
  1553. PNWPRINTER
  1554. NwFindPrinterEntry(
  1555. IN LPWSTR pszServer,
  1556. IN LPWSTR pszQueue
  1557. )
  1558. {
  1559. PNWPRINTER pPrinter = NULL;
  1560. //
  1561. // Check to see if we already have the given printer in our printer
  1562. // link list. If yes, return the printer.
  1563. //
  1564. for ( pPrinter = NwPrinterList; pPrinter; pPrinter = pPrinter->pNextPrinter)
  1565. {
  1566. if ( ( lstrcmpiW( pPrinter->pszServer, pszServer ) == 0 )
  1567. && ( lstrcmpiW( pPrinter->pszQueue, pszQueue ) == 0 )
  1568. )
  1569. {
  1570. return pPrinter;
  1571. }
  1572. }
  1573. return NULL;
  1574. }
  1575. DWORD
  1576. NwCreatePrinterEntry(
  1577. IN LPWSTR pszServer,
  1578. IN LPWSTR pszQueue,
  1579. OUT PNWPRINTER *ppPrinter,
  1580. OUT PHANDLE phServer
  1581. )
  1582. {
  1583. DWORD err = NO_ERROR;
  1584. DWORD nQueueId = 0;
  1585. HANDLE TreeHandle = NULL;
  1586. UNICODE_STRING TreeName;
  1587. PNWPRINTER pNwPrinter = NULL;
  1588. BOOL fCreatedNWConnection = FALSE;
  1589. LPWSTR lpRemoteName = NULL;
  1590. DWORD dwBufSize = ( wcslen(pszServer) + wcslen(pszQueue) + 2 )
  1591. * sizeof(WCHAR);
  1592. lpRemoteName = (LPWSTR) AllocNwSplMem( LMEM_ZEROINIT, dwBufSize );
  1593. if ( lpRemoteName == NULL )
  1594. return ERROR_NOT_ENOUGH_MEMORY;
  1595. wcscpy( lpRemoteName, pszServer );
  1596. wcscat( lpRemoteName, L"\\" );
  1597. wcscat( lpRemoteName, pszQueue );
  1598. *ppPrinter = NULL;
  1599. *phServer = NULL;
  1600. //
  1601. // See if we already know about this print queue.
  1602. //
  1603. pNwPrinter = NwFindPrinterEntry( pszServer, pszQueue );
  1604. /* Changing to get queue status to verify access instead
  1605. if ( pNwPrinter == NULL )
  1606. {
  1607. // We don't know about this NetWare print queue. We need to see if
  1608. // we are authorized to use this queue. If so, then go ahead
  1609. // and continue to open printer. Otherwise, fail with not
  1610. // authorized error code.
  1611. err = NwCreateConnection( NULL,
  1612. lpRemoteName,
  1613. RESOURCETYPE_PRINT,
  1614. NULL,
  1615. NULL );
  1616. if ( err != NO_ERROR )
  1617. {
  1618. if ( ( err == ERROR_INVALID_PASSWORD ) ||
  1619. ( err == ERROR_ACCESS_DENIED ) ||
  1620. ( err == ERROR_NO_SUCH_USER ) )
  1621. {
  1622. err = ERROR_ACCESS_DENIED;
  1623. }
  1624. FreeNwSplMem( lpRemoteName, dwBufSize );
  1625. return err;
  1626. }
  1627. fCreatedNWConnection = TRUE;
  1628. }
  1629. */
  1630. //
  1631. // See if pszServer is really a NDS tree name, if so call
  1632. // NwNdsGetQueueInformation to get the QueueId and possible referred
  1633. // server for which we open handle.
  1634. //
  1635. RtlInitUnicodeString( &TreeName, pszServer + 2 );
  1636. err = NwNdsOpenTreeHandle( &TreeName, &TreeHandle );
  1637. if ( err == NO_ERROR )
  1638. {
  1639. NTSTATUS ntstatus;
  1640. WCHAR szRefServer[NDS_MAX_NAME_CHARS];
  1641. UNICODE_STRING ObjectName;
  1642. UNICODE_STRING QueuePath;
  1643. ObjectName.Buffer = szRefServer;
  1644. ObjectName.MaximumLength = NDS_MAX_NAME_CHARS;
  1645. ObjectName.Length = 0;
  1646. RtlInitUnicodeString( &QueuePath, pszQueue );
  1647. ntstatus = NwNdsGetQueueInformation( TreeHandle,
  1648. &QueuePath,
  1649. &ObjectName,
  1650. &nQueueId );
  1651. if ( TreeHandle )
  1652. {
  1653. CloseHandle( TreeHandle );
  1654. TreeHandle = NULL;
  1655. }
  1656. if ( ntstatus )
  1657. {
  1658. err = RtlNtStatusToDosError( ntstatus );
  1659. goto ErrorExit;
  1660. }
  1661. //
  1662. // If we got a referred server, it's name would look like:
  1663. // "CN=SERVER.OU=DEV.O=MICROSOFT" . . . Convert it to "C\\SERVER"
  1664. //
  1665. if ( ObjectName.Length > 0 )
  1666. {
  1667. WORD i;
  1668. LPWSTR EndOfServerName = NULL;
  1669. //
  1670. // First convert the referred server name to
  1671. // "C\\SERVER.OU=DEV.O=MICROSOFT"
  1672. //
  1673. szRefServer[1] = L'\\';
  1674. szRefServer[2] = L'\\';
  1675. //
  1676. // Put a NULL terminator at the first '.'
  1677. //
  1678. EndOfServerName = wcschr( szRefServer + 3, L'.' );
  1679. if (EndOfServerName)
  1680. *EndOfServerName = L'\0';
  1681. //
  1682. // pszServer now equals the referred server "C\\SERVER"
  1683. //
  1684. //
  1685. // Get the handle of the referred server skipping the 'C' character.
  1686. //
  1687. err = NwAttachToNetwareServer( szRefServer + 1, phServer);
  1688. }
  1689. }
  1690. else // Not an NDS tree, so get handle of server.
  1691. {
  1692. err = NwAttachToNetwareServer( pszServer, phServer);
  1693. if ( err == NO_ERROR )
  1694. {
  1695. if ( err = NwGetQueueId( *phServer, pszQueue, &nQueueId))
  1696. err = ERROR_INVALID_NAME;
  1697. }
  1698. }
  1699. if ( ( err == ERROR_INVALID_PASSWORD ) ||
  1700. ( err == ERROR_ACCESS_DENIED ) ||
  1701. ( err == ERROR_NO_SUCH_USER ) )
  1702. {
  1703. err = ERROR_ACCESS_DENIED;
  1704. goto ErrorExit;
  1705. }
  1706. else if ( err != NO_ERROR )
  1707. {
  1708. err = ERROR_INVALID_NAME;
  1709. goto ErrorExit;
  1710. }
  1711. //
  1712. // Test to see if there already was a entry for this print queue. If so,
  1713. // we can now return with NO_ERROR since pNwPrinter and phServer are
  1714. // now set.
  1715. //
  1716. if ( pNwPrinter )
  1717. {
  1718. if ( lpRemoteName )
  1719. {
  1720. FreeNwSplMem( lpRemoteName, dwBufSize );
  1721. }
  1722. *ppPrinter = pNwPrinter;
  1723. return NO_ERROR;
  1724. }
  1725. //
  1726. // The printer entry was not found in our list of printers in the
  1727. // call to NwFindPrinterEntry. So, we must create one.
  1728. //
  1729. // First, verify access rights
  1730. else
  1731. {
  1732. BYTE nQueueStatus;
  1733. BYTE nJobCount;
  1734. err = NwReadQueueCurrentStatus(*phServer, nQueueId, &nQueueStatus, &nJobCount);
  1735. if ( ( err == ERROR_INVALID_PASSWORD ) ||
  1736. ( err == ERROR_ACCESS_DENIED ) ||
  1737. ( err == ERROR_NO_SUCH_USER ) )
  1738. {
  1739. err = ERROR_ACCESS_DENIED;
  1740. goto ErrorExit;
  1741. }
  1742. else if ( err != NO_ERROR )
  1743. {
  1744. err = ERROR_INVALID_NAME;
  1745. goto ErrorExit;
  1746. }
  1747. }
  1748. if ( *ppPrinter = AllocNwSplMem( LMEM_ZEROINIT, sizeof(NWPRINTER) ))
  1749. {
  1750. if ( !( (*ppPrinter)->pszServer = AllocNwSplStr( pszServer )) )
  1751. {
  1752. err = ERROR_NOT_ENOUGH_MEMORY;
  1753. goto ErrorExit;
  1754. }
  1755. else if ( !( (*ppPrinter)->pszQueue = AllocNwSplStr( pszQueue )))
  1756. {
  1757. err = ERROR_NOT_ENOUGH_MEMORY;
  1758. goto ErrorExit;
  1759. }
  1760. if ( fCreatedNWConnection )
  1761. {
  1762. if ( !( (*ppPrinter)->pszUncConnection =
  1763. AllocNwSplStr( lpRemoteName )) )
  1764. {
  1765. err = ERROR_NOT_ENOUGH_MEMORY;
  1766. goto ErrorExit;
  1767. }
  1768. FreeNwSplMem( lpRemoteName, dwBufSize );
  1769. lpRemoteName = NULL;
  1770. }
  1771. else
  1772. {
  1773. (*ppPrinter)->pszUncConnection = NULL;
  1774. }
  1775. #if DBG
  1776. IF_DEBUG(PRINT)
  1777. {
  1778. KdPrint(("*************CREATED PRINTER ENTRY: %ws\\%ws\n\n",
  1779. (*ppPrinter)->pszServer, (*ppPrinter)->pszQueue ));
  1780. }
  1781. #endif
  1782. (*ppPrinter)->nQueueId = nQueueId;
  1783. (*ppPrinter)->pSpoolList = NULL;
  1784. (*ppPrinter)->pNextPrinter = NwPrinterList;
  1785. NwPrinterList = *ppPrinter;
  1786. err = NO_ERROR;
  1787. }
  1788. else
  1789. {
  1790. err = ERROR_NOT_ENOUGH_MEMORY;
  1791. }
  1792. if ( err == NO_ERROR )
  1793. return err;
  1794. ErrorExit:
  1795. if ( *phServer )
  1796. {
  1797. (VOID) NtClose( *phServer );
  1798. *phServer = NULL;
  1799. }
  1800. if ( *ppPrinter )
  1801. {
  1802. if ( (*ppPrinter)->pszServer )
  1803. {
  1804. FreeNwSplStr( (*ppPrinter)->pszServer );
  1805. }
  1806. if ( (*ppPrinter)->pszQueue )
  1807. {
  1808. FreeNwSplStr( (*ppPrinter)->pszQueue );
  1809. }
  1810. if ( (*ppPrinter)->pszUncConnection )
  1811. {
  1812. (void) NwrDeleteConnection( NULL,
  1813. (*ppPrinter)->pszUncConnection,
  1814. FALSE );
  1815. FreeNwSplStr( (*ppPrinter)->pszUncConnection );
  1816. }
  1817. FreeNwSplMem( *ppPrinter, sizeof( NWPRINTER));
  1818. *ppPrinter = NULL;
  1819. }
  1820. if ( lpRemoteName )
  1821. {
  1822. FreeNwSplMem( lpRemoteName, dwBufSize );
  1823. }
  1824. return err;
  1825. }
  1826. VOID
  1827. NwRemovePrinterEntry(
  1828. IN PNWPRINTER pPrinter
  1829. )
  1830. {
  1831. PNWPRINTER pCur, pPrev = NULL;
  1832. ASSERT( pPrinter->pSpoolList == NULL );
  1833. pPrinter->pSpoolList = NULL;
  1834. for ( pCur = NwPrinterList; pCur; pPrev = pCur, pCur = pCur->pNextPrinter )
  1835. {
  1836. if ( pCur == pPrinter )
  1837. {
  1838. if ( pPrev )
  1839. pPrev->pNextPrinter = pCur->pNextPrinter;
  1840. else
  1841. NwPrinterList = pCur->pNextPrinter;
  1842. break;
  1843. }
  1844. }
  1845. ASSERT( pCur );
  1846. pPrinter->pNextPrinter = NULL;
  1847. FreeNwSplStr( pPrinter->pszServer );
  1848. FreeNwSplStr( pPrinter->pszQueue );
  1849. if ( pPrinter->pszUncConnection )
  1850. {
  1851. (void) NwrDeleteConnection( NULL,
  1852. pPrinter->pszUncConnection,
  1853. FALSE );
  1854. FreeNwSplStr( pPrinter->pszUncConnection );
  1855. }
  1856. FreeNwSplMem( pPrinter, sizeof( NWPRINTER));
  1857. }
  1858. VOID
  1859. NWWKSTA_PRINTER_CONTEXT_rundown(
  1860. IN NWWKSTA_PRINTER_CONTEXT hPrinter
  1861. )
  1862. /*++
  1863. Routine Description:
  1864. This function is called by RPC when a client terminates with an
  1865. opened handle. This allows us to clean up and deallocate any context
  1866. data associated with the handle.
  1867. Arguments:
  1868. hPrinter - Supplies the opened handle
  1869. Return Value:
  1870. None.
  1871. --*/
  1872. {
  1873. (void) NwrClosePrinter(&hPrinter);
  1874. }
  1875. LPWSTR
  1876. NwGetUncObjectName(
  1877. IN LPWSTR ContainerName
  1878. )
  1879. {
  1880. WORD length = 2;
  1881. WORD totalLength = (WORD) wcslen( ContainerName );
  1882. if ( totalLength < 2 )
  1883. return 0;
  1884. while ( length < totalLength )
  1885. {
  1886. if ( ContainerName[length] == L'.' )
  1887. ContainerName[length] = L'\0';
  1888. length++;
  1889. }
  1890. length = 2;
  1891. while ( length < totalLength && ContainerName[length] != L'\\' )
  1892. {
  1893. length++;
  1894. }
  1895. ContainerName[length + 2] = L'\\';
  1896. ContainerName[length + 3] = L'\\';
  1897. return (ContainerName + length + 2);
  1898. }