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.

1005 lines
34 KiB

  1. /*
  2. * HrPrinterEntry.c v0.10
  3. * Generated in conjunction with Management Factory scripts:
  4. * script version: SNMPv1, 0.16, Apr 25, 1996
  5. * project: D:\TEMP\EXAMPLE\HOSTMIB
  6. ****************************************************************************
  7. * *
  8. * (C) Copyright 1995 DIGITAL EQUIPMENT CORPORATION *
  9. * *
  10. * This software is an unpublished work protected under the *
  11. * the copyright laws of the United States of America, all *
  12. * rights reserved. *
  13. * *
  14. * In the event this software is licensed for use by the United *
  15. * States Government, all use, duplication or disclosure by the *
  16. * United States Government is subject to restrictions as set *
  17. * forth in either subparagraph (c)(1)(ii) of the Rights in *
  18. * Technical Data And Computer Software Clause at DFARS *
  19. * 252.227-7013, or the Commercial Computer Software Restricted *
  20. * Rights Clause at FAR 52.221-19, whichever is applicable. *
  21. * *
  22. ****************************************************************************
  23. *
  24. * Facility:
  25. *
  26. * Windows NT SNMP Extension Agent
  27. *
  28. * Abstract:
  29. *
  30. * This module contains the code for dealing with the get, set, and
  31. * instance name routines for the HrPrinterEntry. Actual instrumentation code is
  32. * supplied by the developer.
  33. *
  34. * Functions:
  35. *
  36. * A get and set routine for each attribute in the class.
  37. *
  38. * The routines for instances within the class.
  39. *
  40. * Author:
  41. *
  42. * D. D. Burns @ Webenable Inc
  43. *
  44. * Revision History:
  45. *
  46. * V1.00 - 04/27/97 D. D. Burns Genned: Thu Nov 07 16:42:50 1996
  47. *
  48. */
  49. #include <windows.h>
  50. #include <malloc.h>
  51. #include <snmp.h>
  52. #include "mib.h"
  53. #include "smint.h"
  54. #include "hostmsmi.h"
  55. #include "user.h" /* Developer supplied include file */
  56. #include "HMCACHE.H" /* Cache-related definitions */
  57. #include "HRDEVENT.H" /* HrDevice Table related definitions */
  58. #include <winspool.h> /* Needed to acquire printer-status*/
  59. /*
  60. * GetHrPrinterStatus
  61. * The current status of this printer device.
  62. *
  63. * Gets the value for HrPrinterStatus.
  64. *
  65. * Arguments:
  66. *
  67. * outvalue address to return variable value
  68. * accesss Reserved for future security use
  69. * instance address of instance name as ordered native
  70. * data type(s)
  71. *
  72. * Return Codes:
  73. *
  74. * Standard PDU error codes.
  75. *
  76. * SNMP_ERRORSTATUS_NOERROR Successful get
  77. * SNMP_ERRORSTATUS_GENERR Catch-all failure code
  78. * mibtget.c v0.10
  79. *
  80. | =============== From WebEnable Design Spec Rev 3 04/11/97==================
  81. | hrPrinterStatus
  82. |
  83. | ACCESS SYNTAX
  84. | read-only INTEGER {other(1),unknown(2),idle(3),printing(4),warmup(5)}
  85. |
  86. | "The current status of this printer device. When in the idle(1), printing(2),
  87. | or warmup(3) state, the corresponding hrDeviceStatus should be running(2) or
  88. | warning(3). When in the unknown state, the corresponding hrDeviceStatus
  89. | should be unknown(1)."
  90. |
  91. | DISCUSSION:
  92. |
  93. | <POA-14> The actual status and error state of a hardware printer is deeply
  94. | buried with respect to the application level. Given that we can acquire
  95. | the name of the printer driver for a printer, some input on how best to
  96. | report the hardware status and error state would be appreciated.
  97. |
  98. | LIMITED RESOLUTION >>>>>>>>
  99. | <POA-14> We report logical printers as though they were hardware printers.
  100. | This results in certain "undercount" and "overcount" situations when using
  101. | Host MIB values for inventory purposes. For status purposes, the status
  102. | of the logical printers is returned.
  103. | LIMITED RESOLUTION >>>>>>>>
  104. |
  105. |============================================================================
  106. | 1.3.6.1.2.1.25.3.5.1.1.<instance>
  107. | | | | |
  108. | | | | *hrPrinterStatus
  109. | | | *hrPrinterEntry
  110. | | *hrPrinterTable
  111. | *-hrDevice
  112. */
  113. UINT
  114. GetHrPrinterStatus(
  115. OUT INThrPrinterStatus *outvalue ,
  116. IN Access_Credential *access ,
  117. IN InstanceName *instance )
  118. {
  119. ULONG index; /* As fetched from instance structure */
  120. CACHEROW *row; /* Row entry fetched from cache */
  121. /*
  122. | Grab the instance information
  123. */
  124. index = GET_INSTANCE(0);
  125. /*
  126. | Use it to find the right entry in the cache
  127. */
  128. if ((row = FindTableRow(index, &hrDevice_cache)) == NULL) {
  129. return SNMP_ERRORSTATUS_GENERR;
  130. }
  131. /*
  132. | Ok, here's the skinny: Just about all the status information that can
  133. | be acquired about a printer under NT is acquired by
  134. | "COMPUTE_hrPrinter_status()" that was written to service the need of
  135. | reporting general status for printer devices out of "hrDeviceStatus".
  136. |
  137. | Since we can't gather any more information reliably than this function
  138. | does, we simply call it and map the return codes it provides as values
  139. | for "hrDeviceStatus" into codes appropriate for this attribute variable.
  140. |
  141. */
  142. if (COMPUTE_hrPrinter_status(row, (UINT *) outvalue) != TRUE) {
  143. return SNMP_ERRORSTATUS_GENERR;
  144. }
  145. /* We get back:
  146. | "unknown" = 1 If we can't open the printer at all.
  147. |
  148. | "running" = 2 If we can open the printer and no status is
  149. | showing on it.
  150. | "warning" = 3 If we can open the printer but PAUSED or
  151. | PENDING_DELETION is showing on it.
  152. */
  153. switch (*outvalue) {
  154. case 1: // "unknown" for hrDeviceStatus
  155. *outvalue = 2; // goes to-> "unknown" for hrPrinterStatus
  156. break;
  157. case 2: // "running" for hrDeviceStatus
  158. case 3: // "warning" for hrDeviceStatus
  159. default:
  160. *outvalue = 1; // goes to-> "other" for hrPrinterStatus
  161. break;
  162. }
  163. return SNMP_ERRORSTATUS_NOERROR ;
  164. } /* end of GetHrPrinterStatus() */
  165. /*
  166. * GetHrPrinterDetectedErrorState
  167. * The error conditions as detected by the printer.
  168. *
  169. * Gets the value for HrPrinterDetectedErrorState.
  170. *
  171. * Arguments:
  172. *
  173. * outvalue address to return variable value
  174. * accesss Reserved for future security use
  175. * instance address of instance name as ordered native
  176. * data type(s)
  177. *
  178. * Return Codes:
  179. *
  180. * Standard PDU error codes.
  181. *
  182. * SNMP_ERRORSTATUS_NOERROR Successful get
  183. * SNMP_ERRORSTATUS_GENERR Catch-all failure code
  184. * mibtget.c v0.10
  185. *
  186. | =============== From WebEnable Design Spec Rev 3 04/11/97==================
  187. | hrPrinterDetectedErrorState
  188. |
  189. | ACCESS SYNTAX
  190. | read-only OCTET STRING
  191. |
  192. | "This object represents any error conditions detected by the printer. The
  193. | error conditions are encoded as bits in an octet string, with the following
  194. | definitions:
  195. |
  196. | Condition Bit # hrDeviceStatus
  197. |
  198. | lowPaper 0 warning(3)
  199. | noPaper 1 down(5)
  200. | lowToner 2 warning(3)
  201. | noToner 3 down(5)
  202. | doorOpen 4 down(5)
  203. | jammed 5 down(5)
  204. | offline 6 down(5)
  205. | serviceRequested 7 warning(3)
  206. |
  207. | If multiple conditions are currently detected and the hrDeviceStatus would not
  208. | otherwise be unknown(1) or testing(4), the hrDeviceStatus shall correspond to
  209. | the worst state of those indicated, where down(5) is worse than warning(3)
  210. | which is worse than running(2).
  211. |
  212. | Bits are numbered starting with the most significant bit of the first byte
  213. | being bit 0, the least significant bit of the first byte being bit 7, the most
  214. | significant bit of the second byte being bit 8, and so on. A one bit encodes
  215. | that the condition was detected, while a zero bit encodes that the condition
  216. | was not detected.
  217. |
  218. | This object is useful for alerting an operator to specific warning or error
  219. | conditions that may occur, especially those requiring human intervention."
  220. |
  221. | DISCUSSION:
  222. |
  223. | (See discussion above for "hrPrinterStatus").
  224. |
  225. |============================================================================
  226. | 1.3.6.1.2.1.25.3.5.1.2.<instance>
  227. | | | | |
  228. | | | | *hrPrinterDetectedErrorState
  229. | | | *hrPrinterEntry
  230. | | *hrPrinterTable
  231. | *-hrDevice
  232. */
  233. UINT
  234. GetHrPrinterDetectedErrorState(
  235. OUT OctetString *outvalue ,
  236. IN Access_Credential *access ,
  237. IN InstanceName *instance )
  238. {
  239. /*
  240. | The deal on this attribute is that under NT, you can barely tell
  241. | if the printer is on, unlike 95, where you can tell if it is on its
  242. | second bottle of toner for the day.
  243. |
  244. | Consequently we return a single all-bits zero octet regardless of
  245. | the instance value (which by now in the calling sequence of things
  246. | has been validated anyway).
  247. */
  248. outvalue->length = 1;
  249. outvalue->string = "\0";
  250. return SNMP_ERRORSTATUS_NOERROR ;
  251. } /* end of GetHrPrinterDetectedErrorState() */
  252. /*
  253. * HrPrinterEntryFindInstance
  254. *
  255. * This routine is used to verify that the specified instance is
  256. * valid.
  257. *
  258. * Arguments:
  259. *
  260. * FullOid Address for the full oid - group, variable,
  261. * and instance information
  262. * instance Address for instance specification as an oid
  263. *
  264. * Return Codes:
  265. *
  266. * SNMP_ERRORSTATUS_NOERROR Instance found and valid
  267. * SNMP_ERRORSTATUS_NOSUCHNAME Invalid instance
  268. *
  269. */
  270. UINT
  271. HrPrinterEntryFindInstance( IN ObjectIdentifier *FullOid ,
  272. IN OUT ObjectIdentifier *instance )
  273. {
  274. UINT tmp_instance; /* Instance arc value */
  275. CACHEROW *row; /* Row entry fetched from cache */
  276. //
  277. // Developer instrumentation code to find appropriate instance goes here.
  278. // For non-tables, it is not necessary to modify this routine. However, if
  279. // there is any context that needs to be set, it can be done here.
  280. //
  281. if ( FullOid->idLength <= HRPRINTERENTRY_VAR_INDEX )
  282. // No instance was specified
  283. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  284. else if ( FullOid->idLength != HRPRINTERENTRY_VAR_INDEX + 1 )
  285. // Instance length is more than 1
  286. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  287. else
  288. // The only valid instance for a non-table are instance 0. If this
  289. // is a non-table, the following code validates the instances. If this
  290. // is a table, developer modification is necessary below.
  291. tmp_instance = FullOid->ids[ HRPRINTERENTRY_VAR_INDEX ] ;
  292. /*
  293. | For hrPrinterTable, the instance arc(s) is a single arc, and it must
  294. | correctly select an entry in the hrDeviceTable cache.
  295. |
  296. | Check that here.
  297. */
  298. if ( (row = FindTableRow(tmp_instance, &hrDevice_cache)) == NULL ) {
  299. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  300. }
  301. else
  302. {
  303. /*
  304. | The instance arc selects an hrDeviceTable row entry, but is that
  305. | entry actually for a device of type "Printer"?
  306. |
  307. | (We examine the last arc of the OID that specifies the device
  308. | type in the row entry selected by the instance arc).
  309. */
  310. if (row->attrib_list[HRDV_TYPE].u.unumber_value !=
  311. HRDV_TYPE_LASTARC_PRINTER) {
  312. return SNMP_ERRORSTATUS_NOSUCHNAME;
  313. }
  314. // the instance is valid. Create the instance portion of the OID
  315. // to be returned from this call.
  316. instance->ids[ 0 ] = tmp_instance ;
  317. instance->idLength = 1 ;
  318. }
  319. return SNMP_ERRORSTATUS_NOERROR ;
  320. } /* end of HrPrinterEntryFindInstance() */
  321. /*
  322. * HrPrinterEntryFindNextInstance
  323. *
  324. * This routine is called to get the next instance. If no instance
  325. * was passed than return the first instance (1).
  326. *
  327. * Arguments:
  328. *
  329. * FullOid Address for the full oid - group, variable,
  330. * and instance information
  331. * instance Address for instance specification as an oid
  332. *
  333. * Return Codes:
  334. *
  335. * SNMP_ERRORSTATUS_NOERROR Instance found and valid
  336. * SNMP_ERRORSTATUS_NOSUCHNAME Invalid instance
  337. *
  338. */
  339. UINT
  340. HrPrinterEntryFindNextInstance( IN ObjectIdentifier *FullOid ,
  341. IN OUT ObjectIdentifier *instance )
  342. {
  343. //
  344. // Developer supplied code to find the next instance of class goes here.
  345. // If this is a class with cardinality 1, no modification of this routine
  346. // is necessary unless additional context needs to be set.
  347. // If the FullOid does not specify an instance, then the only instance
  348. // of the class is returned. If this is a table, the first row of the
  349. // table is returned.
  350. //
  351. // If an instance is specified and this is a non-table class, then NOSUCHNAME
  352. // is returned so that correct MIB rollover processing occurs. If this is
  353. // a table, then the next instance is the one following the current instance.
  354. // If there are no more instances in the table, return NOSUCHNAME.
  355. //
  356. CACHEROW *row;
  357. ULONG tmp_instance;
  358. if ( FullOid->idLength <= HRPRINTERENTRY_VAR_INDEX )
  359. {
  360. /*
  361. | Too short: must return the instance arc that selects the first
  362. | entry in the table if there is one.
  363. */
  364. tmp_instance = 0;
  365. }
  366. else {
  367. /*
  368. | There is at least one instance arc. Even if it is the only arc
  369. | we use it as the "index" in a request for the "NEXT" one.
  370. */
  371. tmp_instance = FullOid->ids[ HRPRINTERENTRY_VAR_INDEX ] ;
  372. }
  373. /* Now go off and try to find the next instance in the table */
  374. if ((row = FindNextTableRow(tmp_instance, &hrDevice_cache)) == NULL) {
  375. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  376. }
  377. /*
  378. | The instance arc selects an hrDeviceTable row entry, but is that
  379. | entry actually for a device of type "Printer"?
  380. |
  381. | (We examine the last arc of the OID that specifies the device
  382. | type in the row entry selected by the instance arc).
  383. */
  384. do {
  385. if (row->attrib_list[HRDV_TYPE].u.unumber_value ==
  386. HRDV_TYPE_LASTARC_PRINTER) {
  387. /* Found an hrDeviceTable entry for the right device type */
  388. break;
  389. }
  390. /* Step to the next row in the table */
  391. row = GetNextTableRow( row );
  392. }
  393. while ( row != NULL );
  394. /* If we found a proper device-type row . . . */
  395. if ( row != NULL) {
  396. instance->ids[ 0 ] = row->index ;
  397. instance->idLength = 1 ;
  398. }
  399. else {
  400. /*
  401. | Fell off the end of the hrDeviceTable without finding a row
  402. | entry that had the right device type.
  403. */
  404. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  405. }
  406. return SNMP_ERRORSTATUS_NOERROR ;
  407. } /* end of HrPrinterEntryFindNextInstance() */
  408. /*
  409. * HrPrinterEntryConvertInstance
  410. *
  411. * This routine is used to convert the object id specification of an
  412. * instance into an ordered native representation. The object id format
  413. * is that object identifier that is returned from the Find Instance
  414. * or Find Next Instance routines. It is NOT the full object identifier
  415. * that contains the group and variable object ids as well. The native
  416. * representation is an argc/argv-like structure that contains the
  417. * ordered variables that define the instance. This is specified by
  418. * the MIB's INDEX clause. See RFC 1212 for information about the INDEX
  419. * clause.
  420. *
  421. *
  422. * Arguments:
  423. *
  424. * oid_spec Address of the object id instance specification
  425. * native_spec Address to return the ordered native instance
  426. * specification
  427. *
  428. * Return Codes:
  429. *
  430. * SUCCESS Conversion complete successfully
  431. * FAILURE Unable to convert object id into native format
  432. *
  433. */
  434. UINT
  435. HrPrinterEntryConvertInstance( IN ObjectIdentifier *oid_spec ,
  436. IN OUT InstanceName *native_spec )
  437. {
  438. static char *array; /* The address of this (char *) is passed back */
  439. /* as though it were an array of length 1 of these */
  440. /* types. */
  441. static ULONG inst; /* The address of this ULONG is passed back */
  442. /* (Obviously, no "free()" action is needed) */
  443. /* We only expect the one arc in "oid_spec" */
  444. inst = oid_spec->ids[0];
  445. array = (char *) &inst;
  446. native_spec->count = 1;
  447. native_spec->array = &array;
  448. return SUCCESS ;
  449. } /* end of HrPrinterEntryConvertInstance() */
  450. /*
  451. * HrPrinterEntryFreeInstance
  452. *
  453. * This routine is used to free an ordered native representation of an
  454. * instance name.
  455. *
  456. * Arguments:
  457. *
  458. * instance Address to return the ordered native instance
  459. * specification
  460. *
  461. * Return Codes:
  462. *
  463. *
  464. */
  465. void
  466. HrPrinterEntryFreeInstance( IN OUT InstanceName *instance )
  467. {
  468. /* No action needed for hrPrinter Table */
  469. } /* end of HrPrinterEntryFreeInstance() */
  470. /*
  471. | End of Generated Code
  472. */
  473. /* Gen_HrPrinter_Cache - Generate a initial cache for HrDevice PRINTER Table */
  474. /* Gen_HrPrinter_Cache - Generate a initial cache for HrDevice PRINTER Table */
  475. /* Gen_HrPrinter_Cache - Generate a initial cache for HrDevice PRINTER Table */
  476. BOOL
  477. Gen_HrPrinter_Cache(
  478. ULONG type_arc
  479. )
  480. /*
  481. | EXPLICIT INPUTS:
  482. |
  483. | "type_arc" is the number "n" to be used as the last arc in the
  484. | device-type OID:
  485. |
  486. | 1.3.6.1.2.1.25.3.1.n
  487. | | | |
  488. | | | * Identifying arc for type
  489. | | *-hrDeviceTypes (OIDs specifying device types)
  490. | *-hrDevice
  491. |
  492. | for devices created by this cache-population routine.
  493. |
  494. | IMPLICIT INPUTS:
  495. |
  496. | None.
  497. |
  498. | OUTPUTS:
  499. |
  500. | On Success:
  501. | Function returns TRUE indicating that the HrDevice cache has been fully
  502. | populated with all rows required for Printer devices.
  503. |
  504. | On any Failure:
  505. | Function returns FALSE (indicating "not enough storage" or other
  506. | internal logic error).
  507. |
  508. | THE BIG PICTURE:
  509. |
  510. | At subagent startup time, the cache for each table in the MIB is
  511. | populated with rows for each row in the table. This function is
  512. | invoked by the start-up code in "Gen_HrDevice_Cache()" to
  513. | populate the cache for the HrDevice table with printer-specific
  514. | entries.
  515. |
  516. | OTHER THINGS TO KNOW:
  517. |
  518. | Since all the attributes in the HrPrinter "sub" table are computed
  519. | upon request (based on cached information in a selected row in the
  520. | HrDevice table) there is no need to build a cache specifically for
  521. | this sub-table. (This routine is loading the HrDevice cache despite
  522. | it's name). --------
  523. |
  524. | This function holds a convention with the GET routines earlier in
  525. | this module that the "HIDDEN_CTX" attribute for printers contains
  526. | a string that can be used in OpenPrinter to get a handle to that
  527. | printer.
  528. |============================================================================
  529. | 1.3.6.1.2.1.25.3.5.1...
  530. | | | |
  531. | | | *hrPrinterEntry
  532. | | *hrPrinterTable
  533. | *-hrDevice
  534. |
  535. */
  536. {
  537. CHAR temp[8]; /* Temporary buffer for first call */
  538. DWORD PI_request_len = 0; /* Printer Info: Storage actually needed */
  539. DWORD PI_count = 0; /* Count of Printer Infos returned */
  540. UINT i; /* Handy-Dandy loop index */
  541. PRINTER_INFO_4
  542. *PrinterInfo; /* --> allocated storage for drive strings */
  543. BOOL result; /* result of winspool API call */
  544. DWORD dwLastError; /* last error */
  545. /*
  546. | We're going to call EnumPrinters() twice, once to get the proper
  547. | buffer size, and the second time to actually get the printer info.
  548. */
  549. result = EnumPrinters(PRINTER_ENUM_LOCAL, // Flags
  550. NULL, // Name (ignored)
  551. 4, // Level
  552. temp, // Buffer
  553. 1, // "Too Small" Buffer size
  554. &PI_request_len, // Required length... comes back.
  555. &PI_count
  556. );
  557. if (result)
  558. {
  559. // When there is no data from spooler *and* spooler is
  560. // running, we'll be here.
  561. return TRUE; // empty table
  562. }
  563. // Assert: result == FALSE
  564. dwLastError = GetLastError(); // save last error
  565. if (ERROR_INSUFFICIENT_BUFFER != dwLastError)
  566. {
  567. //
  568. // EnumPrinters Failed and the last error is not
  569. // ERROR_INSUFFICIENT_BUFFER, we'll bail out with 0 entries in the
  570. // table.
  571. // For example, if spooler service was down, we will be here.
  572. //
  573. return TRUE; // empty table
  574. }
  575. // Assert: dwLastError == ERROR_INSUFFICIENT_BUFFER
  576. /*
  577. | Grab enough storage for the enumeration structures
  578. */
  579. if ( (PrinterInfo = malloc(PI_request_len)) == NULL) {
  580. /* Storage Request failed altogether, can't initialize */
  581. return ( FALSE );
  582. }
  583. /* Now get the real stuff */
  584. if (!EnumPrinters(PRINTER_ENUM_LOCAL, // Flags
  585. NULL, // Name (ignored)
  586. 4, // Level
  587. (unsigned char *) PrinterInfo, // Buffer to receive enumeration
  588. PI_request_len, // Actual buffer size
  589. &PI_request_len, // Required length... comes back.
  590. &PI_count
  591. )) {
  592. /* Failed for some reason */
  593. free( PrinterInfo );
  594. return ( TRUE ); // empty table
  595. }
  596. /*
  597. | Now swing down the list, and for every LOCAL printer,
  598. |
  599. | + Fetch the description
  600. | + Make an hrDevice table row entry with the printer name & description
  601. */
  602. for (i = 0; i < PI_count; i += 1) {
  603. /* If it is a Local printer ... */
  604. if (PrinterInfo[i].Attributes & PRINTER_ATTRIBUTE_LOCAL) {
  605. HANDLE hprinter; /* Handle to a printer */
  606. /* Open it to get a handle */
  607. if (OpenPrinter(PrinterInfo[i].pPrinterName, // Printer Name
  608. &hprinter, // Receive handle here
  609. NULL // Security
  610. ) == TRUE) {
  611. PRINTER_INFO_2 *p2;
  612. DWORD P2_request_len = 0 ; // Bytes-needed by GetPrinter
  613. /*
  614. | Printer is Open, get a PRINTER_INFO_2 "slug-o-data"
  615. |
  616. | 1st call: Fails, but gets buffer size needed.
  617. */
  618. result = GetPrinter(hprinter, // printer handle
  619. 2, // Level 2
  620. temp, // Buffer for INFO_2
  621. 1, // Buffer-too-small
  622. &P2_request_len // What we really need
  623. );
  624. if (result)
  625. {
  626. // 1 byte shouldn't be enough to hold PRINTER_INFO_2 structure
  627. ClosePrinter( hprinter );
  628. continue; // skip this printer
  629. }
  630. // Assert: result == FALSE
  631. dwLastError = GetLastError(); // save last error
  632. if (ERROR_INSUFFICIENT_BUFFER != dwLastError)
  633. {
  634. //
  635. // GetPrinter Failed and the last error is not
  636. // ERROR_INSUFFICIENT_BUFFER, we'll skip this printer.
  637. // For example, if spooler service was down, we will be here.
  638. //
  639. ClosePrinter(hprinter);
  640. continue; // skip this printer
  641. }
  642. // Assert: dwLastError == ERROR_INSUFFICIENT_BUFFER
  643. /*
  644. | Grab enough storage for the PRINTER_INFO_2 structure
  645. */
  646. if ( (p2 = malloc(P2_request_len)) == NULL) {
  647. /* Storage Request failed altogether, can't initialize */
  648. free( PrinterInfo );
  649. ClosePrinter( hprinter );
  650. return ( FALSE );
  651. }
  652. /*
  653. | 2nd call: Should succeed.
  654. */
  655. if (GetPrinter(hprinter, // printer handle
  656. 2, // Level 2
  657. (unsigned char *) p2, // Buffer for INFO_2
  658. P2_request_len, // Buffer-just-right
  659. &P2_request_len // What we really need
  660. ) == TRUE) {
  661. /* Add a row to HrDevice Table
  662. |
  663. | We're using the printer-driver name as a "Poor Man's"
  664. | description: the driver "names" are quite descriptive with
  665. | version numbers yet!.
  666. |
  667. | The Hidden Context is the name needed to open the printer
  668. | to gain information about its status.
  669. */
  670. if (AddHrDeviceRow(type_arc, // DeviceType OID Last-Arc
  671. p2->pDriverName, // Used as description
  672. PrinterInfo[i].pPrinterName, // Hidden Ctx
  673. CA_STRING // Hidden Ctx type
  674. ) == NULL ) {
  675. /* Failure at a lower level: drop everything */
  676. free( p2 );
  677. free( PrinterInfo );
  678. ClosePrinter( hprinter );
  679. return ( FALSE );
  680. }
  681. }
  682. /* Close up shop on this printer*/
  683. free( p2 );
  684. ClosePrinter( hprinter );
  685. }
  686. }
  687. }
  688. free( PrinterInfo );
  689. return ( TRUE );
  690. }
  691. /* COMPUTE_hrPrinter_errors - Compute "hrDeviceErrors" for a Printer device */
  692. /* COMPUTE_hrPrinter_errors - Compute "hrDeviceErrors" for a Printer device */
  693. /* COMPUTE_hrPrinter_errors - Compute "hrDeviceErrors" for a Printer device */
  694. BOOL
  695. COMPUTE_hrPrinter_errors(
  696. CACHEROW *row,
  697. UINT *outvalue
  698. )
  699. /*
  700. | EXPLICIT INPUTS:
  701. |
  702. | "row" points to the hrDevice cache row for the printer whose error
  703. | count is to be returned.
  704. |
  705. | Attribute "HIDDEN_CTX" has a string value that is the name of the
  706. | printer by convention with "Gen_HrPrinter_Cache()" above.
  707. |
  708. | "outvalue" is a pointer to an integer to receive the error count.
  709. |
  710. | IMPLICIT INPUTS:
  711. |
  712. | None.
  713. |
  714. | OUTPUTS:
  715. |
  716. | On Success:
  717. | Function returns TRUE and an error count for the specified printer.
  718. |
  719. | On any Failure:
  720. | Function returns FALSE.
  721. |
  722. | THE BIG PICTURE:
  723. |
  724. | For an hrDevice attribute whose value is "computed", at the time of
  725. | the request to see it is received, we dispatch to a "COMPUTE_" function
  726. | to get the value. This is such a routine for printers.
  727. |
  728. | OTHER THINGS TO KNOW:
  729. |
  730. | This function holds a convention with the Gen_cache routines earlier in
  731. | this module that the "HIDDEN_CTX" attribute for printers contains
  732. | a string that can be used in OpenPrinter to get a handle to that
  733. | printer.
  734. */
  735. {
  736. /*
  737. | No way to get any error counts under NT
  738. */
  739. *outvalue = 0;
  740. return ( TRUE );
  741. }
  742. /* COMPUTE_hrPrinter_status - Compute "hrDeviceStatus" for a Printer device */
  743. /* COMPUTE_hrPrinter_status - Compute "hrDeviceStatus" for a Printer device */
  744. /* COMPUTE_hrPrinter_status - Compute "hrDeviceStatus" for a Printer device */
  745. BOOL
  746. COMPUTE_hrPrinter_status(
  747. CACHEROW *row,
  748. UINT *outvalue
  749. )
  750. /*
  751. | EXPLICIT INPUTS:
  752. |
  753. | "row" points to the hrDevice cache row for the printer whose status
  754. | is to be returned.
  755. |
  756. | Attribute "HIDDEN_CTX" has a string value that is the name of the
  757. | printer by convention with "Gen_HrPrinter_Cache()" above.
  758. |
  759. | "outvalue" is a pointer to an integer to receive the status.
  760. |
  761. | IMPLICIT INPUTS:
  762. |
  763. | None.
  764. |
  765. | OUTPUTS:
  766. |
  767. | On Success:
  768. | Function returns TRUE and a status for the specified printer:
  769. |
  770. | "unknown" = 1 If we can't open the printer at all.
  771. |
  772. | "running" = 2 If we can open the printer and no status is
  773. | showing on it.
  774. | "warning" = 3 If we can open the printer but PAUSED or
  775. | PENDING_DELETION is showing on it.
  776. |
  777. |
  778. | On any Failure:
  779. | Function returns FALSE.
  780. |
  781. | THE BIG PICTURE:
  782. |
  783. | For an hrDevice attribute whose value is "computed", at the time of
  784. | the request to see it is received, we dispatch to a "COMPUTE_" function
  785. | to get the value. This is such a routine for printers.
  786. |
  787. | OTHER THINGS TO KNOW:
  788. |
  789. | This function holds a convention with the Gen_cache routines earlier in
  790. | this module that the "HIDDEN_CTX" attribute for printers contains
  791. | a string that can be used in OpenPrinter to get a handle to that
  792. | printer.
  793. */
  794. {
  795. CHAR temp[8]; /* Temporary buffer for first call */
  796. HANDLE hprinter; /* Handle to a printer */
  797. BOOL result;
  798. DWORD dwLastError;
  799. /* Open Printer whose name is in "Hidden Context" to get a handle */
  800. if (OpenPrinter(row->attrib_list[HIDDEN_CTX].u.string_value, // Printer Name
  801. &hprinter, // Receive handle here
  802. NULL // Security
  803. ) == TRUE ) {
  804. PRINTER_INFO_2 *p2;
  805. DWORD P2_request_len = 0; /* Bytes-needed by GetPrinter */
  806. /*
  807. | Printer is Open, get a PRINTER_INFO_2 "slug-o-data"
  808. |
  809. | 1st call: Fails, get buffer size needed.
  810. */
  811. result = GetPrinter(hprinter, // printer handle
  812. 2, // Level 2
  813. temp, // Buffer for INFO_2
  814. 1, // Buffer-too-small
  815. &P2_request_len // What we really need
  816. );
  817. if (result)
  818. {
  819. // 1 byte shouldn't be enough to hold PRINTER_INFO_2 structure
  820. *outvalue = 1; // "unknown"
  821. ClosePrinter( hprinter );
  822. return ( TRUE );
  823. }
  824. // Assert: result == FALSE
  825. dwLastError = GetLastError(); // save last error
  826. if (ERROR_INSUFFICIENT_BUFFER != dwLastError)
  827. {
  828. //
  829. // GetPrinter Failed and the last error is not
  830. // ERROR_INSUFFICIENT_BUFFER, returns with unknown status
  831. // For example, if spooler service was down, we will be here.
  832. //
  833. *outvalue = 1; // "unknown"
  834. ClosePrinter(hprinter);
  835. return ( TRUE );
  836. }
  837. // Assert: dwLastError == ERROR_INSUFFICIENT_BUFFER
  838. /*
  839. | Grab enough storage for the PRINTER_INFO_2 structure
  840. */
  841. if ( (p2 = malloc(P2_request_len)) == NULL) {
  842. /* Storage Request failed altogether */
  843. ClosePrinter( hprinter );
  844. return ( FALSE );
  845. }
  846. /*
  847. | 2nd call: Should succeed.
  848. */
  849. if (GetPrinter(hprinter, // printer handle
  850. 2, // Level 2
  851. (unsigned char *) p2, // Buffer for INFO_2
  852. P2_request_len, // Buffer-just-right
  853. &P2_request_len // What we really need
  854. ) == TRUE) {
  855. /*
  856. | As of this writing, only two status values are available
  857. | under NT:
  858. |
  859. | PRINTER_STATUS_PAUSED
  860. | PRINTER_STATUS_PENDING_DELETION
  861. |
  862. | Basically, if either of these is TRUE, we'll signal "warning".
  863. | If neither are TRUE, we'll signal "running" (on the basis that
  864. | we've managed to open the printer OK and it shows no status).
  865. */
  866. if ( (p2->Status & PRINTER_STATUS_PAUSED)
  867. || (p2->Status & PRINTER_STATUS_PENDING_DELETION)) {
  868. *outvalue = 3; // "warning"
  869. }
  870. else {
  871. *outvalue = 2; // "running"
  872. }
  873. }
  874. /* Free up and return */
  875. ClosePrinter( hprinter );
  876. free( p2 );
  877. }
  878. else {
  879. *outvalue = 1; // "unknown"
  880. }
  881. return ( TRUE );
  882. }