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

1761 lines
44 KiB

  1. /*++
  2. Copyright (c) 1993 - 1995 Microsoft Corporation
  3. Abstract:
  4. This module provides the exported API WaitForPrinterChange,
  5. and the support functions internal to the local spooler.
  6. Author:
  7. Andrew Bell (AndrewBe) March 1993
  8. Revision History:
  9. --*/
  10. #include<precomp.h>
  11. typedef struct _NOTIFY_FIELD_TABLE {
  12. WORD Field;
  13. WORD Table;
  14. WORD Offset;
  15. } NOTIFY_FIELD_TYPE, *PNOTIFY_FIELD_TYPE;
  16. //
  17. // Translation table from PRINTER_NOTIFY_FIELD_* to bit vector
  18. //
  19. NOTIFY_FIELD_TYPE NotifyFieldTypePrinter[] = {
  20. #define DEFINE(field, x, y, table, offset) \
  21. { PRINTER_NOTIFY_FIELD_##field, table, OFFSETOF(INIPRINTER, offset) },
  22. #include <ntfyprn.h>
  23. #undef DEFINE
  24. { 0, 0, 0 }
  25. };
  26. NOTIFY_FIELD_TYPE NotifyFieldTypeJob[] = {
  27. #define DEFINE(field, x, y, table, offset) \
  28. { JOB_NOTIFY_FIELD_##field, table, OFFSETOF(INIJOB, offset) },
  29. #include <ntfyjob.h>
  30. #undef DEFINE
  31. { 0, 0, 0 }
  32. };
  33. typedef struct _NOTIFY_RAW_DATA {
  34. PVOID pvData;
  35. DWORD dwId;
  36. } NOTIFY_RAW_DATA, *PNOTIFY_RAW_DATA;
  37. //
  38. // Currently we assume that the number of PRINTER_NOTIFY_FIELD_* elements
  39. // will fit in one DWORD vector (32 bits). If this is ever false,
  40. // we need to re-write this code.
  41. //
  42. PNOTIFY_FIELD_TYPE apNotifyFieldTypes[NOTIFY_TYPE_MAX] = {
  43. NotifyFieldTypePrinter,
  44. NotifyFieldTypeJob
  45. };
  46. DWORD adwNotifyFieldOffsets[NOTIFY_TYPE_MAX] = {
  47. I_PRINTER_END,
  48. I_JOB_END
  49. };
  50. #define NOTIFY_FIELD_TOTAL (I_PRINTER_END + I_JOB_END)
  51. //
  52. // Common NotifyVectors used in the system.
  53. // NV*
  54. //
  55. NOTIFYVECTOR NVPrinterStatus = {
  56. BIT(I_PRINTER_STATUS), // | BIT(I_PRINTER_STATUS_STRING),
  57. BIT_NONE
  58. };
  59. NOTIFYVECTOR NVPrinterSD = {
  60. BIT(I_PRINTER_SECURITY_DESCRIPTOR),
  61. BIT_NONE
  62. };
  63. NOTIFYVECTOR NVJobStatus = {
  64. BIT_NONE,
  65. BIT(I_JOB_STATUS)
  66. };
  67. NOTIFYVECTOR NVJobStatusAndString = {
  68. BIT_NONE,
  69. BIT(I_JOB_STATUS) | BIT(I_JOB_STATUS_STRING)
  70. };
  71. NOTIFYVECTOR NVJobStatusString = {
  72. BIT_NONE,
  73. BIT(I_JOB_STATUS_STRING)
  74. };
  75. NOTIFYVECTOR NVPurge = {
  76. BIT(I_PRINTER_STATUS),
  77. BIT_NONE,
  78. };
  79. NOTIFYVECTOR NVDeletedJob = {
  80. BIT(I_PRINTER_CJOBS),
  81. BIT(I_JOB_STATUS)
  82. };
  83. NOTIFYVECTOR NVAddJob = {
  84. BIT(I_PRINTER_CJOBS),
  85. BIT_ALL
  86. };
  87. NOTIFYVECTOR NVPrinterAll = {
  88. BIT_ALL,
  89. BIT_NONE
  90. };
  91. NOTIFYVECTOR NVSpoolJob = {
  92. BIT_NONE,
  93. BIT(I_JOB_TOTAL_BYTES) | BIT(I_JOB_TOTAL_PAGES)
  94. };
  95. NOTIFYVECTOR NVWriteJob = {
  96. BIT_NONE,
  97. BIT(I_JOB_BYTES_PRINTED) | BIT(I_JOB_PAGES_PRINTED)
  98. };
  99. NOTIFYVECTOR NVJobPrinted = {
  100. BIT_NONE,
  101. BIT(I_JOB_BYTES_PRINTED) | BIT(I_JOB_PAGES_PRINTED) | BIT(I_JOB_STATUS)
  102. };
  103. //
  104. // Forward prototypes.
  105. //
  106. ESTATUS
  107. ValidateStartNotify(
  108. PSPOOL pSpool,
  109. DWORD fdwFilterFlags,
  110. DWORD fdwOptions,
  111. PPRINTER_NOTIFY_OPTIONS pPrinterNotifyOptions,
  112. PINIPRINTER* ppIniPrinter);
  113. BOOL
  114. SetSpoolChange(
  115. PSPOOL pSpool,
  116. PNOTIFY_RAW_DATA pNotifyRawData,
  117. PDWORD pdwNotifyVectors,
  118. DWORD Flags);
  119. BOOL
  120. SetupNotifyOptions(
  121. PSPOOL pSpool,
  122. PPRINTER_NOTIFY_OPTIONS pPrinterNotifyOptions);
  123. VOID
  124. NotifyInfoTypes(
  125. PSPOOL pSpool,
  126. PNOTIFY_RAW_DATA pNotifyRawData,
  127. PDWORD pdwNotifyVectors,
  128. DWORD ChangeFlags);
  129. BOOL
  130. RefreshBuildInfoData(
  131. PSPOOL pSpool,
  132. PPRINTER_NOTIFY_INFO pInfo,
  133. UINT cInfo,
  134. WORD Type,
  135. PNOTIFY_RAW_DATA pNotifyRawData);
  136. DWORD
  137. LocalWaitForPrinterChange(
  138. HANDLE hPrinter,
  139. DWORD fdwFilterFlags)
  140. /*++
  141. Routine Description:
  142. This API may be called by an application if it wants to know
  143. when the status of a printer or print server changes.
  144. Valid events to wait for are defined by the PRINTER_CHANGE_* manifests.
  145. Arguments:
  146. hPrinter - A printer handle returned by OpenPrinter.
  147. This may correspond to either a printer or a server.
  148. fdwFilterFlags - One or more PRINTER_CHANGE_* values combined.
  149. The function will return if any of these changes occurs.
  150. Return Value:
  151. Non-zero: A mask containing the change which occurred.
  152. Zero: Either an error occurred or the handle (hPrinter) was closed
  153. by another thread. In the latter case GetLastError returns
  154. ERROR_INVALID_HANDLE.
  155. When a call is made to WaitForPrinterChange, we create an event in the
  156. SPOOL structure pointed to by the handle, to enable signaling between
  157. the thread causing the printer change and the thread waiting for it.
  158. When a change occurs, e.g. StartDocPrinter, the function SetPrinterChange
  159. is called, which traverses the linked list of handles pointed to by
  160. the PRINTERINI structure associated with that printer, and also any
  161. open handles on the server, then signals any events which it finds
  162. which has reuested to be informed if this change takes place.
  163. If there is no thread currently waiting, the change flag is maintained,
  164. so that later calls to WaitForPrinterChange can return immediately.
  165. This ensures that changes which occur between calls will not be lost.
  166. --*/
  167. {
  168. PSPOOL pSpool = (PSPOOL)hPrinter;
  169. PINIPRINTER pIniPrinter = NULL; /* Remains NULL for server */
  170. DWORD rc = 0;
  171. DWORD ChangeFlags = 0;
  172. HANDLE ChangeEvent = 0;
  173. DWORD TimeoutFlags = 0;
  174. #if DBG
  175. static DWORD Count = 0;
  176. #endif
  177. DBGMSG(DBG_NOTIFY,
  178. ("WaitForPrinterChange( %08x, %08x )\n", hPrinter, fdwFilterFlags));
  179. EnterSplSem();
  180. switch (ValidateStartNotify(pSpool,
  181. fdwFilterFlags,
  182. 0,
  183. NULL,
  184. &pIniPrinter)) {
  185. case STATUS_PORT:
  186. DBGMSG(DBG_NOTIFY, ("Port with no monitor: Calling WaitForPrinterChange\n"));
  187. LeaveSplSem();
  188. return WaitForPrinterChange(pSpool->hPort, fdwFilterFlags);
  189. case STATUS_FAIL:
  190. LeaveSplSem();
  191. return 0;
  192. case STATUS_VALID:
  193. break;
  194. }
  195. DBGMSG(DBG_NOTIFY, ("WaitForPrinterChange %08x on %ws:\n%d caller%s waiting\n",
  196. fdwFilterFlags,
  197. pIniPrinter ? pIniPrinter->pName : pSpool->pIniSpooler->pMachineName,
  198. Count, Count == 1 ? "" : "s"));
  199. //
  200. // There may already have been a change since we last called:
  201. //
  202. if ((pSpool->ChangeFlags == PRINTER_CHANGE_CLOSE_PRINTER) ||
  203. (pSpool->ChangeFlags & fdwFilterFlags)) {
  204. if (pSpool->ChangeFlags == PRINTER_CHANGE_CLOSE_PRINTER)
  205. ChangeFlags = 0;
  206. else
  207. ChangeFlags = pSpool->ChangeFlags;
  208. DBGMSG(DBG_NOTIFY, ("No need to wait: Printer change %08x detected on %ws:\n%d remaining caller%s\n",
  209. (ChangeFlags & fdwFilterFlags),
  210. pIniPrinter ? pIniPrinter->pName : pSpool->pIniSpooler->pMachineName,
  211. Count, Count == 1 ? "" : "s"));
  212. pSpool->ChangeFlags = 0;
  213. LeaveSplSem();
  214. return (ChangeFlags & fdwFilterFlags);
  215. }
  216. ChangeEvent = CreateEvent(NULL,
  217. EVENT_RESET_AUTOMATIC,
  218. EVENT_INITIAL_STATE_NOT_SIGNALED,
  219. NULL);
  220. if ( !ChangeEvent ) {
  221. DBGMSG( DBG_WARNING, ("CreateEvent( ChangeEvent ) failed: Error %d\n", GetLastError()));
  222. LeaveSplSem();
  223. return 0;
  224. }
  225. DBGMSG(DBG_NOTIFY, ("ChangeEvent == %x\n", ChangeEvent));
  226. //
  227. // SetSpoolChange checks that pSpool->ChangeEvent is non-null
  228. // to decide whether to call SetEvent().
  229. //
  230. pSpool->WaitFlags = fdwFilterFlags;
  231. pSpool->ChangeEvent = ChangeEvent;
  232. pSpool->pChangeFlags = &ChangeFlags;
  233. pSpool->Status |= SPOOL_STATUS_NOTIFY;
  234. LeaveSplSem();
  235. DBGMSG( DBG_NOTIFY,
  236. ( "WaitForPrinterChange: Calling WaitForSingleObject( %x )\n",
  237. pSpool->ChangeEvent ));
  238. rc = WaitForSingleObject(pSpool->ChangeEvent,
  239. PRINTER_CHANGE_TIMEOUT_VALUE);
  240. DBGMSG( DBG_NOTIFY,
  241. ( "WaitForPrinterChange: WaitForSingleObject( %x ) returned\n",
  242. pSpool->ChangeEvent ));
  243. EnterSplSem();
  244. pSpool->Status &= ~SPOOL_STATUS_NOTIFY;
  245. pSpool->ChangeEvent = NULL;
  246. pSpool->pChangeFlags = NULL;
  247. if (rc == WAIT_TIMEOUT) {
  248. DBGMSG(DBG_INFO, ("WaitForPrinterChange on %ws timed out after %d minutes\n",
  249. pIniPrinter ? pIniPrinter->pName : pSpool->pIniSpooler->pMachineName,
  250. (PRINTER_CHANGE_TIMEOUT_VALUE / 60000)));
  251. ChangeFlags |= fdwFilterFlags;
  252. TimeoutFlags = PRINTER_CHANGE_TIMEOUT;
  253. }
  254. if (ChangeFlags == PRINTER_CHANGE_CLOSE_PRINTER) {
  255. ChangeFlags = 0;
  256. SetLastError(ERROR_INVALID_HANDLE);
  257. }
  258. DBGMSG(DBG_NOTIFY, ("Printer change %08x detected on %ws:\n%d remaining caller%s\n",
  259. ((ChangeFlags & fdwFilterFlags) | TimeoutFlags),
  260. pIniPrinter ? pIniPrinter->pName : pSpool->pIniSpooler->pMachineName,
  261. Count, Count == 1 ? "" : "s"));
  262. if (ChangeEvent && !CloseHandle(ChangeEvent)) {
  263. DBGMSG(DBG_WARNING, ("CloseHandle( %x ) failed: Error %d\n",
  264. ChangeEvent, GetLastError()));
  265. }
  266. //
  267. // If the pSpool is pending deletion, we must free it here.
  268. //
  269. if (pSpool->eStatus & STATUS_PENDING_DELETION) {
  270. FreeSplMem(pSpool);
  271. }
  272. LeaveSplSem();
  273. return ((ChangeFlags & fdwFilterFlags) | TimeoutFlags);
  274. }
  275. BOOL
  276. SetSpoolClosingChange(
  277. PSPOOL pSpool)
  278. /*++
  279. Routine Description:
  280. A print handle is closing; trigger a notification.
  281. Arguments:
  282. Return Value:
  283. --*/
  284. {
  285. return SetSpoolChange(pSpool,
  286. NULL,
  287. NULL,
  288. PRINTER_CHANGE_CLOSE_PRINTER);
  289. }
  290. BOOL
  291. SetSpoolChange(
  292. PSPOOL pSpool,
  293. PNOTIFY_RAW_DATA pNotifyRawData,
  294. PDWORD pdwNotifyVectors,
  295. DWORD Flags)
  296. /*++
  297. Routine Description:
  298. Sets the event for notification or calls ReplyPrinterChangeNotification.
  299. This is called by SetPrinterChange for every open handle on a printer
  300. and the local server.
  301. It should also be called when an individual handle is closed.
  302. Assumes we're INSIDE the spooler critical section
  303. Arguments:
  304. pSpool -- Specifies handle that changed.
  305. pIniJob -- Used if there is a watch on job information.
  306. pdwNotifyVectors -- Specifies what things have changed.
  307. Flags -- WaitForPrinterChange flags.
  308. Return Value:
  309. --*/
  310. {
  311. DWORD ChangeFlags;
  312. SplInSem();
  313. if( Flags == PRINTER_CHANGE_CLOSE_PRINTER ) {
  314. ChangeFlags = PRINTER_CHANGE_CLOSE_PRINTER;
  315. } else {
  316. ChangeFlags = ( pSpool->ChangeFlags | Flags ) & pSpool->WaitFlags;
  317. }
  318. //
  319. // If we have STATUS_VALID set
  320. // then we are using the new FFPCN code.
  321. //
  322. if ( pSpool->eStatus & STATUS_VALID ) {
  323. NotifyInfoTypes(pSpool,
  324. pNotifyRawData,
  325. pdwNotifyVectors,
  326. ChangeFlags);
  327. }
  328. if ( ChangeFlags ) {
  329. pSpool->ChangeFlags = 0;
  330. if ( pSpool->pChangeFlags ) {
  331. *pSpool->pChangeFlags = ChangeFlags;
  332. DBGMSG( DBG_NOTIFY, ( "SetSpoolChange: Calling SetEvent( %x )\n", pSpool->ChangeEvent ));
  333. SetEvent(pSpool->ChangeEvent);
  334. DBGMSG( DBG_NOTIFY, ( "SetSpoolChange: SetEvent( %x ) returned\n", pSpool->ChangeEvent ));
  335. pSpool->pChangeFlags = NULL;
  336. }
  337. }
  338. return TRUE;
  339. }
  340. /*++
  341. Routine Name:
  342. PrinterNotificationVisible
  343. Routine Description:
  344. This checks to see whether the given printer handle uses the new printer
  345. change notifications, it then checks to see whether the given printer is
  346. a TS printer and then checks to see whether this printer is visible to the
  347. user who opened the printer handle. This need only be called for server
  348. handles since the fact that the user was able to open the printer handle
  349. implies that it is visible to this.
  350. Arguments:
  351. pIniPrinter - NULL, or a valid pointer to the INIPRINTER for the printer
  352. on which the change occurred.
  353. pSpool - The printer handle which we are testing for access.
  354. Return Value:
  355. TRUE if the printer notification should be delivered, FALSE if the printer
  356. change notification should not be delivered.
  357. --*/
  358. BOOL
  359. PrinterNotificationVisible(
  360. IN PINIPRINTER pIniPrinter OPTIONAL,
  361. IN PSPOOL pSpool
  362. )
  363. {
  364. BOOL bRet = TRUE;
  365. //
  366. // If the pSpool handle is a new notification handle and we have a printer
  367. // and it is a TS printer and we can't show it, then return FALSE otherwise
  368. // the notification can be sent.
  369. //
  370. if (pSpool->eStatus & STATUS_VALID &&
  371. pIniPrinter &&
  372. (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_TS) &&
  373. pSpool->hClientToken &&
  374. !ShowThisPrinter(pIniPrinter, pSpool->hClientToken))
  375. {
  376. bRet = FALSE;
  377. }
  378. return bRet;
  379. }
  380. /*++
  381. Routine Name:
  382. SetPrinterChange
  383. Routine Description:
  384. Calls SetSpoolChange for every open handle for the server
  385. and printer, if specified.
  386. Arguments:
  387. pIniPrinter - NULL, or a valid pointer to the INIPRINTER for the printer
  388. on which the change occurred.
  389. Flags - PRINTER_CHANGE_* constant indicating what happened.
  390. Note: we pass a pointer to pPrinterNotifyInfo to SetSpoolChange.
  391. If one call needs it, it will check this parm, then create it if
  392. necessary. This way it is retrieved only once.
  393. Return Value:
  394. --*/
  395. BOOL
  396. SetPrinterChange(
  397. PINIPRINTER pIniPrinter,
  398. PINIJOB pIniJob,
  399. PDWORD pdwNotifyVectors,
  400. DWORD Flags,
  401. PINISPOOLER pIniSpooler)
  402. {
  403. NOTIFY_RAW_DATA aNotifyRawData[NOTIFY_TYPE_MAX];
  404. PSPOOL pSpool;
  405. PINIPRINTER mypIniPrinter;
  406. SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
  407. SplInSem();
  408. if ( pIniSpooler->SpoolerFlags & SPL_PRINTER_CHANGES ) {
  409. aNotifyRawData[0].pvData = pIniPrinter;
  410. aNotifyRawData[0].dwId = pIniPrinter ? pIniPrinter->dwUniqueSessionID : 0;
  411. aNotifyRawData[1].pvData = pIniJob;
  412. aNotifyRawData[1].dwId = pIniJob ? pIniJob->JobId : 0;
  413. if ( pIniPrinter ) {
  414. SPLASSERT( ( pIniPrinter->signature == IP_SIGNATURE ) &&
  415. ( pIniPrinter->pIniSpooler == pIniSpooler ));
  416. DBGMSG(DBG_NOTIFY, ("SetPrinterChange %ws; Flags: %08x\n",
  417. pIniPrinter->pName, Flags));
  418. for (pSpool = pIniPrinter->pSpool; pSpool; pSpool = pSpool->pNext) {
  419. SetSpoolChange( pSpool,
  420. aNotifyRawData,
  421. pdwNotifyVectors,
  422. Flags );
  423. }
  424. } else {
  425. // WorkStation Caching requires a time stamp change
  426. // any time cached data changes
  427. if ( Flags & ( PRINTER_CHANGE_FORM | PRINTER_CHANGE_ADD_PRINTER_DRIVER ) ) {
  428. for ( mypIniPrinter = pIniSpooler->pIniPrinter;
  429. mypIniPrinter != NULL ;
  430. mypIniPrinter = mypIniPrinter->pNext ) {
  431. UpdatePrinterIni ( mypIniPrinter, CHANGEID_ONLY );
  432. }
  433. }
  434. }
  435. if ( pSpool = pIniSpooler->pSpool ) {
  436. DBGMSG( DBG_NOTIFY, ("SetPrinterChange %ws; Flags: %08x\n",
  437. pIniSpooler->pMachineName, Flags));
  438. for ( ; pSpool; pSpool = pSpool->pNext) {
  439. //
  440. // Only send the notification to the user if the printer is visible.
  441. //
  442. if (PrinterNotificationVisible(pIniPrinter, pSpool)) {
  443. SetSpoolChange( pSpool,
  444. aNotifyRawData,
  445. pdwNotifyVectors,
  446. Flags );
  447. }
  448. }
  449. }
  450. }
  451. return TRUE;
  452. }
  453. BOOL
  454. LocalFindFirstPrinterChangeNotification(
  455. HANDLE hPrinter,
  456. DWORD fdwFilterFlags,
  457. DWORD fdwOptions,
  458. HANDLE hNotify,
  459. PDWORD pfdwStatus,
  460. PPRINTER_NOTIFY_OPTIONS pPrinterNotifyOptions,
  461. PVOID pvReserved1)
  462. {
  463. PINIPRINTER pIniPrinter = NULL;
  464. PSPOOL pSpool = (PSPOOL)hPrinter;
  465. EnterSplSem();
  466. switch (ValidateStartNotify(pSpool,
  467. fdwFilterFlags,
  468. fdwOptions,
  469. pPrinterNotifyOptions,
  470. &pIniPrinter)) {
  471. case STATUS_PORT:
  472. DBGMSG(DBG_NOTIFY, ("LFFPCN: Port nomon 0x%x\n", pSpool));
  473. pSpool->eStatus |= STATUS_PORT;
  474. LeaveSplSem();
  475. *pfdwStatus = 0;
  476. return ProvidorFindFirstPrinterChangeNotification(pSpool->hPort,
  477. fdwFilterFlags,
  478. fdwOptions,
  479. hNotify,
  480. pPrinterNotifyOptions,
  481. pvReserved1);
  482. case STATUS_FAIL:
  483. DBGMSG(DBG_WARNING, ("ValidateStartNotify failed!\n"));
  484. LeaveSplSem();
  485. return FALSE;
  486. case STATUS_VALID:
  487. break;
  488. }
  489. //
  490. // Get any other handle state we need into this notification handle. This
  491. // operation is guaranteed to be stateless.
  492. //
  493. if (!GetClientTokenForNotification(pSpool)) {
  494. return FALSE;
  495. }
  496. pSpool->eStatus = STATUS_NULL;
  497. if (pPrinterNotifyOptions) {
  498. if (!SetupNotifyOptions(pSpool, pPrinterNotifyOptions)) {
  499. DBGMSG(DBG_WARNING, ("SetupNotifyOptions failed!\n"));
  500. LeaveSplSem();
  501. return FALSE;
  502. }
  503. }
  504. //
  505. // Setup notification
  506. //
  507. DBGMSG(DBG_NOTIFY, ("LFFPCN: Port has monitor: Setup 0x%x\n", pSpool));
  508. pSpool->WaitFlags = fdwFilterFlags;
  509. pSpool->hNotify = hNotify;
  510. pSpool->eStatus |= STATUS_VALID;
  511. pSpool->Status |= SPOOL_STATUS_NOTIFY;
  512. LeaveSplSem();
  513. *pfdwStatus = PRINTER_NOTIFY_STATUS_ENDPOINT;
  514. return TRUE;
  515. }
  516. BOOL
  517. LocalFindClosePrinterChangeNotification(
  518. HANDLE hPrinter)
  519. {
  520. PSPOOL pSpool = (PSPOOL)hPrinter;
  521. BOOL bReturn = FALSE;
  522. if (ValidateSpoolHandle(pSpool, 0)) {
  523. EnterSplSem();
  524. //
  525. // If it's the port case (false connect) we pass the close
  526. // request to the right providor.
  527. // Otherwise, close ourselves.
  528. //
  529. if (pSpool->eStatus & STATUS_PORT) {
  530. DBGMSG(DBG_TRACE, ("LFCPCN: Port nomon 0x%x\n", pSpool));
  531. LeaveSplSem();
  532. bReturn = ProvidorFindClosePrinterChangeNotification(pSpool->hPort);
  533. } else {
  534. if (pSpool->eStatus & STATUS_VALID) {
  535. DBGMSG(DBG_TRACE, ("LFCPCN: Close notify 0x%x\n", pSpool));
  536. pSpool->WaitFlags = 0;
  537. pSpool->eStatus = STATUS_NULL;
  538. pSpool->Status &= ~SPOOL_STATUS_NOTIFY;
  539. bReturn = TRUE;
  540. } else {
  541. DBGMSG(DBG_WARNING, ("LFCPCN: Invalid handle 0x%x\n", pSpool));
  542. SetLastError(ERROR_INVALID_PARAMETER);
  543. }
  544. LeaveSplSem();
  545. }
  546. }
  547. return bReturn;
  548. }
  549. ESTATUS
  550. ValidateStartNotify(
  551. PSPOOL pSpool,
  552. DWORD fdwFilterFlags,
  553. DWORD fdwOptions,
  554. PPRINTER_NOTIFY_OPTIONS pPrinterNotifyOptions,
  555. PINIPRINTER* ppIniPrinter)
  556. /*++
  557. Routine Description:
  558. Validates the pSpool and Flags for notifications.
  559. Arguments:
  560. pSpool - pSpool to validate
  561. fdwFilterFlags - Flags to validate
  562. fdwOptions - Options to validate
  563. pPrinterNotifyOptions
  564. ppIniPrinter - returned pIniPrinter; valid only STATUS_VALID
  565. Return Value:
  566. EWAITSTATUS
  567. --*/
  568. {
  569. PINIPORT pIniPort;
  570. if (ValidateSpoolHandle(pSpool, 0)) {
  571. if ( pSpool->TypeofHandle & PRINTER_HANDLE_PRINTER ) {
  572. *ppIniPrinter = pSpool->pIniPrinter;
  573. } else if (pSpool->TypeofHandle & PRINTER_HANDLE_SERVER) {
  574. *ppIniPrinter = NULL;
  575. } else if ((pSpool->TypeofHandle & PRINTER_HANDLE_PORT) &&
  576. (pIniPort = pSpool->pIniPort) &&
  577. (pIniPort->signature == IPO_SIGNATURE) &&
  578. !(pSpool->pIniPort->Status & PP_MONITOR)) {
  579. if (pSpool->hPort == INVALID_PORT_HANDLE) {
  580. DBGMSG(DBG_WARNING, ("WaitForPrinterChange called for invalid port handle. Setting last error to %d\n",
  581. pSpool->OpenPortError));
  582. SetLastError(pSpool->OpenPortError);
  583. return STATUS_FAIL;
  584. }
  585. return STATUS_PORT;
  586. } else {
  587. DBGMSG(DBG_WARNING, ("The handle is invalid\n"));
  588. SetLastError(ERROR_INVALID_HANDLE);
  589. return STATUS_FAIL;
  590. }
  591. } else {
  592. *ppIniPrinter = NULL;
  593. }
  594. //
  595. // Allow only one wait on each handle.
  596. //
  597. if( pSpool->Status & SPOOL_STATUS_NOTIFY ) {
  598. DBGMSG(DBG_WARNING, ("There is already a thread waiting on this handle\n"));
  599. SetLastError(ERROR_ALREADY_WAITING);
  600. return STATUS_FAIL;
  601. }
  602. if (!(fdwFilterFlags & PRINTER_CHANGE_VALID) && !pPrinterNotifyOptions) {
  603. DBGMSG(DBG_WARNING, ("The wait flags specified are invalid\n"));
  604. SetLastError(ERROR_INVALID_PARAMETER);
  605. return STATUS_FAIL;
  606. }
  607. return STATUS_VALID;
  608. }
  609. //-------------------------------------------------------------------
  610. VOID
  611. GetInfoData(
  612. PSPOOL pSpool,
  613. PNOTIFY_RAW_DATA pNotifyRawData,
  614. PNOTIFY_FIELD_TYPE pNotifyFieldType,
  615. PPRINTER_NOTIFY_INFO_DATA pData,
  616. PBYTE* ppBuffer)
  617. /*++
  618. Routine Description:
  619. Based on the type and field, find and add the information.
  620. Arguments:
  621. Return Value:
  622. --*/
  623. {
  624. static LPWSTR szNULL = L"";
  625. DWORD cbData = 0;
  626. DWORD cbNeeded = 0;
  627. union {
  628. DWORD dwData;
  629. PDWORD pdwData;
  630. PWSTR pszData;
  631. PVOID pvData;
  632. PINIJOB pIniJob;
  633. PINIPORT pIniPort;
  634. PDEVMODE pDevMode;
  635. PSECURITY_DESCRIPTOR pSecurityDescriptor;
  636. PINIPRINTER pIniPrinter;
  637. PWSTR* ppszData;
  638. PINIPORT* ppIniPort;
  639. PINIPRINTER* ppIniPrinter;
  640. PINIDRIVER* ppIniDriver;
  641. PINIPRINTPROC* ppIniPrintProc;
  642. LPDEVMODE* ppDevMode;
  643. PSECURITY_DESCRIPTOR* ppSecurityDescriptor;
  644. } Var;
  645. Var.pvData = (PBYTE)pNotifyRawData->pvData + pNotifyFieldType->Offset;
  646. *ppBuffer = NULL;
  647. //
  648. // Determine space needed, and convert Data from an offset into the
  649. // actual data.
  650. //
  651. switch (pNotifyFieldType->Table) {
  652. case TABLE_JOB_POSITION:
  653. FindJob(Var.pIniJob->pIniPrinter,
  654. Var.pIniJob->JobId,
  655. &Var.dwData);
  656. goto DoDWord;
  657. case TABLE_JOB_STATUS:
  658. Var.dwData = MapJobStatus(MAP_READABLE, *Var.pdwData);
  659. goto DoDWord;
  660. case TABLE_DWORD:
  661. Var.dwData = *Var.pdwData;
  662. goto DoDWord;
  663. case TABLE_DEVMODE:
  664. Var.pDevMode = *Var.ppDevMode;
  665. if (Var.pDevMode) {
  666. cbData = Var.pDevMode->dmSize + Var.pDevMode->dmDriverExtra;
  667. } else {
  668. cbData = 0;
  669. }
  670. break;
  671. case TABLE_SECURITYDESCRIPTOR:
  672. Var.pSecurityDescriptor = *Var.ppSecurityDescriptor;
  673. cbData = GetSecurityDescriptorLength(Var.pSecurityDescriptor);
  674. break;
  675. case TABLE_STRING:
  676. Var.pszData = *Var.ppszData;
  677. goto DoString;
  678. case TABLE_TIME:
  679. //
  680. // Var already points to the SystemTime.
  681. //
  682. cbData = sizeof(SYSTEMTIME);
  683. break;
  684. case TABLE_PRINTPROC:
  685. Var.pszData = (*Var.ppIniPrintProc)->pName;
  686. goto DoString;
  687. case TABLE_JOB_PRINTERNAME:
  688. Var.pszData = (*Var.ppIniPrinter)->pName;
  689. goto DoString;
  690. case TABLE_JOB_PORT:
  691. Var.pIniPort = *Var.ppIniPort;
  692. //
  693. // Only if the job has been scheduled will pIniJob->pIniPort be
  694. // valid. If it is NULL, then just call DoString which will
  695. // return a NULL string.
  696. //
  697. if (Var.pIniPort) {
  698. Var.pszData = Var.pIniPort->pName;
  699. }
  700. goto DoString;
  701. case TABLE_DRIVER:
  702. Var.pszData = (*Var.ppIniDriver)->pName;
  703. goto DoString;
  704. case TABLE_PRINTER_SERVERNAME:
  705. Var.pszData = pSpool->pFullMachineName;
  706. goto DoString;
  707. case TABLE_PRINTER_STATUS:
  708. Var.dwData = MapPrinterStatus(MAP_READABLE, Var.pIniPrinter->Status) |
  709. Var.pIniPrinter->PortStatus;
  710. goto DoDWord;
  711. case TABLE_PRINTER_PORT:
  712. // Get required printer port size
  713. cbNeeded = 0;
  714. GetPrinterPorts(Var.pIniPrinter, 0, &cbNeeded);
  715. *ppBuffer = AllocSplMem(cbNeeded);
  716. if (*ppBuffer)
  717. GetPrinterPorts(Var.pIniPrinter, (LPWSTR) *ppBuffer, &cbNeeded);
  718. Var.pszData = (LPWSTR) *ppBuffer;
  719. goto DoString;
  720. case TABLE_NULLSTRING:
  721. Var.pszData = NULL;
  722. goto DoString;
  723. case TABLE_ZERO:
  724. Var.dwData = 0;
  725. goto DoDWord;
  726. default:
  727. SPLASSERT(FALSE);
  728. break;
  729. }
  730. pData->NotifyData.Data.pBuf = Var.pvData;
  731. pData->NotifyData.Data.cbBuf = cbData;
  732. return;
  733. DoDWord:
  734. pData->NotifyData.adwData[0] = Var.dwData;
  735. pData->NotifyData.adwData[1] = 0;
  736. return;
  737. DoString:
  738. if (Var.pszData) {
  739. //
  740. // Calculate string length.
  741. //
  742. pData->NotifyData.Data.cbBuf = (wcslen(Var.pszData)+1) *
  743. sizeof(Var.pszData[0]);
  744. pData->NotifyData.Data.pBuf = Var.pszData;
  745. } else {
  746. //
  747. // Use NULL string.
  748. //
  749. pData->NotifyData.Data.cbBuf = sizeof(Var.pszData[0]);
  750. pData->NotifyData.Data.pBuf = szNULL;
  751. }
  752. return;
  753. }
  754. //-------------------------------------------------------------------
  755. VOID
  756. NotifyInfoTypes(
  757. PSPOOL pSpool,
  758. PNOTIFY_RAW_DATA pNotifyRawData,
  759. PDWORD pdwNotifyVectors,
  760. DWORD ChangeFlags)
  761. /*++
  762. Routine Description:
  763. Sends notification info (possibly with PRINTER_NOTIFY_INFO) to
  764. the router.
  765. Arguments:
  766. pSpool -- Handle the notification is occurring on.
  767. pNotifyRawData -- Array of size NOTIFY_TYPE_MAX that has the
  768. offset structure can be used against + id.
  769. pdwNotifyVectors -- Identifies what's changing (# elements
  770. is also NOTIFY_TYPE_MAX).
  771. NULL if no changes needed.
  772. ChangeFlags -- Old style change flags.
  773. Return Value:
  774. --*/
  775. {
  776. PNOTIFY_FIELD_TYPE pNotifyFieldType;
  777. PRINTER_NOTIFY_INFO_DATA Data;
  778. PBYTE pBuffer;
  779. BOOL bReturn;
  780. DWORD i,j;
  781. DWORD dwMask;
  782. //
  783. // If we are not valid, OR
  784. // we have no notify vectors, OR
  785. // we have no RAW data OR
  786. // our vectors don't match what change
  787. // then
  788. // If no ChangeFlags return
  789. // DoReply and avoid any Partials.
  790. //
  791. if (!(pSpool->eStatus & STATUS_INFO) ||
  792. !pdwNotifyVectors ||
  793. !pNotifyRawData ||
  794. (!(pdwNotifyVectors[0] & pSpool->adwNotifyVectors[0] ||
  795. pdwNotifyVectors[1] & pSpool->adwNotifyVectors[1]))) {
  796. if (!ChangeFlags)
  797. return;
  798. goto DoReply;
  799. }
  800. //
  801. // HACK: Special case NVPurge so that it causes a discard.
  802. // (We don't want to send all those notifications.)
  803. //
  804. if (pdwNotifyVectors == NVPurge) {
  805. PartialReplyPrinterChangeNotification(pSpool->hNotify, NULL);
  806. goto DoReply;
  807. }
  808. for (i=0; i< NOTIFY_TYPE_MAX; i++, pdwNotifyVectors++) {
  809. dwMask = 0x1;
  810. SPLASSERT(adwNotifyFieldOffsets[i] < sizeof(DWORD)*8);
  811. for (j=0; j< adwNotifyFieldOffsets[i]; j++, dwMask <<= 1) {
  812. //
  813. // If we have a change we are interested in,
  814. // PartialReply.
  815. //
  816. if (dwMask & *pdwNotifyVectors & pSpool->adwNotifyVectors[i]) {
  817. pNotifyFieldType = &apNotifyFieldTypes[i][j];
  818. GetInfoData(pSpool,
  819. &pNotifyRawData[i],
  820. pNotifyFieldType,
  821. &Data,
  822. &pBuffer);
  823. Data.Type = (WORD)i;
  824. Data.Field = pNotifyFieldType->Field;
  825. Data.Reserved = 0;
  826. Data.Id = pNotifyRawData[i].dwId;
  827. //
  828. // If the partial reply failed, then we will be refreshing
  829. // soon, so exit now.
  830. //
  831. bReturn = PartialReplyPrinterChangeNotification(
  832. pSpool->hNotify,
  833. &Data);
  834. if (pBuffer) {
  835. FreeSplMem(pBuffer);
  836. }
  837. if (!bReturn) {
  838. DBGMSG(DBG_TRACE, ("PartialReplyPCN %x failed: %d!\n",
  839. pSpool->hNotify,
  840. GetLastError()));
  841. goto DoReply;
  842. }
  843. }
  844. }
  845. }
  846. DoReply:
  847. //
  848. // A full reply is needed to kick off the notification.
  849. //
  850. ReplyPrinterChangeNotification(pSpool->hNotify,
  851. ChangeFlags,
  852. NULL,
  853. NULL);
  854. }
  855. BOOL
  856. RefreshBuildInfoData(
  857. PSPOOL pSpool,
  858. PPRINTER_NOTIFY_INFO pInfo,
  859. UINT cInfo,
  860. WORD Type,
  861. PNOTIFY_RAW_DATA pNotifyRawData)
  862. /*++
  863. Routine Description:
  864. Sends notification info (possibly with PRINTER_NOTIFY_INFO) to
  865. the router.
  866. Arguments:
  867. pSpool -- Handle the notification is occurring on.
  868. pInfo -- Array of structure to receive new info.
  869. cInfo -- Number of structures in array pInfo.
  870. Type -- Indicates type of notification: job or printer.
  871. pNotifyRawData -- Array of size NOTIFY_TYPE_MAX that has the
  872. offset structure can be used against + id.
  873. Return Value:
  874. --*/
  875. {
  876. PRINTER_NOTIFY_INFO_DATA Data;
  877. DWORD cbData;
  878. PNOTIFY_FIELD_TYPE pNotifyFieldType;
  879. PBYTE pBuffer;
  880. BOOL bReturn;
  881. DWORD j;
  882. DWORD dwMask;
  883. dwMask = 0x1;
  884. SPLASSERT(adwNotifyFieldOffsets[Type] < sizeof(DWORD)*8);
  885. for (j=0; j< adwNotifyFieldOffsets[Type]; j++, dwMask <<= 1) {
  886. //
  887. // If we have a change we are interested in,
  888. // add it.
  889. //
  890. if (dwMask & pSpool->adwNotifyVectors[Type]) {
  891. //
  892. // Check if we have enough space.
  893. //
  894. if (pInfo->Count >= cInfo) {
  895. SPLASSERT(pInfo->Count < cInfo);
  896. return FALSE;
  897. }
  898. pNotifyFieldType = &apNotifyFieldTypes[Type][j];
  899. GetInfoData(pSpool,
  900. pNotifyRawData,
  901. pNotifyFieldType,
  902. &Data,
  903. &pBuffer);
  904. Data.Type = Type;
  905. Data.Field = pNotifyFieldType->Field;
  906. Data.Reserved = 0;
  907. Data.Id = pNotifyRawData->dwId;
  908. bReturn = AppendPrinterNotifyInfoData(pInfo, &Data, 0);
  909. if (pBuffer)
  910. FreeSplMem(pBuffer);
  911. if (!bReturn) {
  912. DBGMSG(DBG_WARNING, ("AppendPrinterNotifyInfoData failed: %d!\n",
  913. GetLastError()));
  914. return FALSE;
  915. }
  916. }
  917. }
  918. return TRUE;
  919. }
  920. //-------------------------------------------------------------------
  921. BOOL
  922. SetupNotifyVector(
  923. PDWORD pdwNotifyVectors,
  924. PPRINTER_NOTIFY_OPTIONS_TYPE pType)
  925. /*++
  926. Routine Description:
  927. Setup the notification vector based on pPrinterNotifyType.
  928. We assume that the size of pPrinterNotifyType has been validated
  929. (so that it fits within the containing structure). We only
  930. need to verify that the Count falls within its stated Size.
  931. Arguments:
  932. pdwNotifyVectors - Structure to fill in.
  933. pType - Source information.
  934. Return Value:
  935. TRUE = success,
  936. FALSE = failure.
  937. --*/
  938. {
  939. PNOTIFY_FIELD_TYPE pNotifyFieldType;
  940. PWORD pFields;
  941. DWORD i, j;
  942. DWORD Count;
  943. BOOL bReturn = FALSE;
  944. __try {
  945. if( pType ){
  946. Count = pType->Count;
  947. pFields = pType->pFields;
  948. if (pType->Type >= NOTIFY_TYPE_MAX) {
  949. DBGMSG(DBG_WARN, ("SetupNotifyVector: type %d field %d not found!\n",
  950. pType->Type, *pFields));
  951. } else {
  952. for (i=0; i < Count; i++, pFields++) {
  953. if (*pFields >= adwNotifyFieldOffsets[pType->Type]) {
  954. DBGMSG(DBG_WARN, ("SetupNotifyVector: type %d field %d not found!\n",
  955. pType->Type, *pFields));
  956. break;
  957. }
  958. SPLASSERT(apNotifyFieldTypes[pType->Type][*pFields].Table != TABLE_SPECIAL);
  959. SPLASSERT(apNotifyFieldTypes[pType->Type][*pFields].Field == *pFields);
  960. SPLASSERT(*pFields < 32);
  961. //
  962. // Found index j, set this bit in our array.
  963. //
  964. pdwNotifyVectors[pType->Type] |= (1 << *pFields);
  965. }
  966. if( i == Count ){
  967. bReturn = TRUE;
  968. }
  969. }
  970. }
  971. } __except( EXCEPTION_EXECUTE_HANDLER ){
  972. }
  973. return bReturn;
  974. }
  975. BOOL
  976. SetupNotifyOptions(
  977. PSPOOL pSpool,
  978. PPRINTER_NOTIFY_OPTIONS pOptions)
  979. /*++
  980. Routine Description:
  981. Initializes pSpool->adwNotifyVectors.
  982. Arguments:
  983. pSpool - Spool handle to setup the notification against.
  984. pOptions - Options that specify the notification.
  985. Return Value:
  986. TRUE - Success, FALSE - FAILURE
  987. LastError set.
  988. --*/
  989. {
  990. DWORD i;
  991. BOOL bAccessGranted = TRUE;
  992. SplInSem();
  993. ZeroMemory(pSpool->adwNotifyVectors, sizeof(pSpool->adwNotifyVectors));
  994. //
  995. // Traverse Options structure.
  996. //
  997. for (i = 0; i < pOptions->Count; i++) {
  998. if (!SetupNotifyVector(pSpool->adwNotifyVectors,
  999. &pOptions->pTypes[i])){
  1000. SetLastError( ERROR_INVALID_PARAMETER );
  1001. return FALSE;
  1002. }
  1003. }
  1004. //
  1005. // Now check if we have sufficient privilege to setup the notification.
  1006. //
  1007. //
  1008. // Check if we are looking for the security descriptor on
  1009. // a printer. If so, we need READ_CONTROL or ACCESS_SYSTEM_SECURITY
  1010. // enabled.
  1011. //
  1012. if( pSpool->adwNotifyVectors[PRINTER_NOTIFY_TYPE] &
  1013. BIT(I_PRINTER_SECURITY_DESCRIPTOR )){
  1014. if( !AreAnyAccessesGranted( pSpool->GrantedAccess,
  1015. READ_CONTROL | ACCESS_SYSTEM_SECURITY )){
  1016. bAccessGranted = FALSE;
  1017. }
  1018. }
  1019. if( pSpool->adwNotifyVectors[PRINTER_NOTIFY_TYPE] &
  1020. ~BIT(I_PRINTER_SECURITY_DESCRIPTOR )){
  1021. if( pSpool->TypeofHandle & PRINTER_HANDLE_SERVER ){
  1022. //
  1023. // There does not appear to be a check for EnumPrinters.
  1024. //
  1025. // This seems odd since you there is a security check on a
  1026. // GetPrinter call, but there is none on EnumPrinters (aside
  1027. // from enumerating share printers only for remote non-admins).
  1028. //
  1029. } else {
  1030. //
  1031. // This matches the check in SplGetPrinter: we need to
  1032. // have PRINTER_ACCESS_USE to read the non-security information.
  1033. //
  1034. if( !AccessGranted( SPOOLER_OBJECT_PRINTER,
  1035. PRINTER_ACCESS_USE,
  1036. pSpool )){
  1037. bAccessGranted = FALSE;
  1038. }
  1039. }
  1040. }
  1041. if( !bAccessGranted ){
  1042. SetLastError( ERROR_ACCESS_DENIED );
  1043. return FALSE;
  1044. }
  1045. pSpool->eStatus |= STATUS_INFO;
  1046. return TRUE;
  1047. }
  1048. UINT
  1049. PopCount(
  1050. DWORD dwValue)
  1051. {
  1052. UINT i;
  1053. UINT cPopCount = 0;
  1054. for(i=0; i< sizeof(dwValue)*8; i++) {
  1055. if (dwValue & (1<<i))
  1056. cPopCount++;
  1057. }
  1058. return cPopCount;
  1059. }
  1060. BOOL
  1061. LocalRefreshPrinterChangeNotification(
  1062. HANDLE hPrinter,
  1063. DWORD dwColor,
  1064. PPRINTER_NOTIFY_OPTIONS pOptions,
  1065. PPRINTER_NOTIFY_INFO* ppInfo)
  1066. /*++
  1067. Routine Description:
  1068. Refreshes data in the case of overflows.
  1069. Arguments:
  1070. Return Value:
  1071. --*/
  1072. {
  1073. PINIJOB pIniJob;
  1074. PINIPRINTER pIniPrinter;
  1075. DWORD cPrinters;
  1076. PSPOOL pSpool = (PSPOOL)hPrinter;
  1077. PDWORD pdwNotifyVectors = pSpool->adwNotifyVectors;
  1078. UINT cInfo = 0;
  1079. PPRINTER_NOTIFY_INFO pInfo = NULL;
  1080. NOTIFY_RAW_DATA NotifyRawData;
  1081. EnterSplSem();
  1082. if (!ValidateSpoolHandle(pSpool, 0 ) ||
  1083. !(pSpool->eStatus & STATUS_INFO)) {
  1084. SetLastError( ERROR_INVALID_HANDLE );
  1085. goto Fail;
  1086. }
  1087. //
  1088. // New bits added, can't compare directly against PRINTER_HANDLE_SERVER.
  1089. //
  1090. if( pSpool->TypeofHandle & PRINTER_HANDLE_SERVER ){
  1091. //
  1092. // If the call is a remote one, and the user is not an admin, then
  1093. // we don't want to show unshared printers.
  1094. //
  1095. BOOL bHideUnshared = (pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE_CALL) &&
  1096. !(pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE_ADMIN);
  1097. for (cPrinters = 0, pIniPrinter = pSpool->pIniSpooler->pIniPrinter;
  1098. pIniPrinter;
  1099. pIniPrinter=pIniPrinter->pNext ) {
  1100. if ((!(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED) &&
  1101. bHideUnshared)
  1102. || !ShowThisPrinter(pIniPrinter, NULL)
  1103. ) {
  1104. continue;
  1105. }
  1106. cPrinters++;
  1107. }
  1108. cInfo += PopCount(pSpool->adwNotifyVectors[PRINTER_NOTIFY_TYPE]) *
  1109. cPrinters;
  1110. //
  1111. // Traverse all printers and create info.
  1112. //
  1113. pInfo = RouterAllocPrinterNotifyInfo(cInfo);
  1114. if (!pInfo)
  1115. goto Fail;
  1116. if (pSpool->adwNotifyVectors[PRINTER_NOTIFY_TYPE]) {
  1117. for (pIniPrinter = pSpool->pIniSpooler->pIniPrinter;
  1118. pIniPrinter;
  1119. pIniPrinter=pIniPrinter->pNext) {
  1120. //
  1121. // Do not send notification for non-shared printers for remote
  1122. // users who are not admins
  1123. //
  1124. if ((!(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED) &&
  1125. bHideUnshared )
  1126. || !ShowThisPrinter(pIniPrinter, NULL)
  1127. ) {
  1128. continue;
  1129. }
  1130. NotifyRawData.pvData = pIniPrinter;
  1131. NotifyRawData.dwId = pIniPrinter->dwUniqueSessionID;
  1132. if (!RefreshBuildInfoData(pSpool,
  1133. pInfo,
  1134. cInfo,
  1135. PRINTER_NOTIFY_TYPE,
  1136. &NotifyRawData)) {
  1137. goto Fail;
  1138. }
  1139. }
  1140. }
  1141. } else {
  1142. //
  1143. // Calculate size of buffer needed.
  1144. //
  1145. if (pSpool->adwNotifyVectors[PRINTER_NOTIFY_TYPE]) {
  1146. //
  1147. // Setup printer info.
  1148. //
  1149. cInfo += PopCount(pSpool->adwNotifyVectors[PRINTER_NOTIFY_TYPE]);
  1150. }
  1151. if (pSpool->adwNotifyVectors[JOB_NOTIFY_TYPE]) {
  1152. cInfo += PopCount(pSpool->adwNotifyVectors[JOB_NOTIFY_TYPE]) *
  1153. pSpool->pIniPrinter->cJobs;
  1154. }
  1155. //
  1156. // Traverse all jobs and create info.
  1157. //
  1158. pInfo = RouterAllocPrinterNotifyInfo(cInfo);
  1159. if (!pInfo)
  1160. goto Fail;
  1161. if (pSpool->adwNotifyVectors[PRINTER_NOTIFY_TYPE]) {
  1162. NotifyRawData.pvData = pSpool->pIniPrinter;
  1163. NotifyRawData.dwId = pSpool->pIniPrinter->dwUniqueSessionID;
  1164. if (!RefreshBuildInfoData(pSpool,
  1165. pInfo,
  1166. cInfo,
  1167. PRINTER_NOTIFY_TYPE,
  1168. &NotifyRawData)) {
  1169. goto Fail;
  1170. }
  1171. }
  1172. if (pSpool->adwNotifyVectors[JOB_NOTIFY_TYPE]) {
  1173. for (pIniJob = pSpool->pIniPrinter->pIniFirstJob;
  1174. pIniJob;
  1175. pIniJob = pIniJob->pIniNextJob) {
  1176. //
  1177. // Hide Chained Jobs
  1178. //
  1179. if (!(pIniJob->Status & JOB_HIDDEN )) {
  1180. NotifyRawData.pvData = pIniJob;
  1181. NotifyRawData.dwId = pIniJob->JobId;
  1182. if (!RefreshBuildInfoData(pSpool,
  1183. pInfo,
  1184. cInfo,
  1185. JOB_NOTIFY_TYPE,
  1186. &NotifyRawData)) {
  1187. goto Fail;
  1188. }
  1189. }
  1190. }
  1191. }
  1192. }
  1193. SPLASSERT(cInfo >= pInfo->Count);
  1194. LeaveSplSem();
  1195. *ppInfo = pInfo;
  1196. return TRUE;
  1197. Fail:
  1198. SPLASSERT(!pInfo || cInfo >= pInfo->Count);
  1199. LeaveSplSem();
  1200. *ppInfo = NULL;
  1201. if (pInfo) {
  1202. RouterFreePrinterNotifyInfo(pInfo);
  1203. }
  1204. return FALSE;
  1205. }
  1206. /*++
  1207. Routine Name:
  1208. GetClientTokenForNotification
  1209. Routine Description:
  1210. Populate the client handle with the callers token if this is a server handle
  1211. (printer handles have implicitely been access checked by virtue of the fact
  1212. that you could open it).
  1213. Arguments:
  1214. pSpool - The printer handle that we are populating with the token
  1215. information
  1216. Return Value:
  1217. TRUE if we could in fact return the token.
  1218. --*/
  1219. BOOL
  1220. GetClientTokenForNotification(
  1221. IN OUT SPOOL *pSpool
  1222. )
  1223. {
  1224. BOOL bRet = TRUE;
  1225. if (!pSpool)
  1226. {
  1227. SetLastError(ERROR_INVALID_PARAMETER);
  1228. bRet = FALSE;
  1229. }
  1230. if (bRet)
  1231. {
  1232. //
  1233. // If this is a printer handle, then we need to get the client token handle
  1234. //
  1235. if (pSpool->TypeofHandle & PRINTER_HANDLE_SERVER)
  1236. {
  1237. //
  1238. // Only get the new client token if we don't have one already.
  1239. //
  1240. if (!pSpool->hClientToken)
  1241. {
  1242. bRet = GetTokenHandle(&pSpool->hClientToken);
  1243. }
  1244. }
  1245. }
  1246. return bRet;
  1247. }