File Coverage

blib/lib/FusionInventory/Agent/Task/Inventory/Win32/Printers.pm
Criterion Covered Total %
statement 56 74 75.6
branch 18 26 69.2
condition 11 21 52.3
subroutine 9 11 81.8
pod 0 2 0.0
total 94 134 70.1


line stmt bran cond sub pod time code
1             package FusionInventory::Agent::Task::Inventory::Win32::Printers;
2              
3 2     2   72140484 use strict;
  2         12  
  2         80  
4 2     2   11 use warnings;
  2         5  
  2         121  
5              
6 2     2   10 use English qw(-no_match_vars);
  2         91  
  2         34  
7              
8 2     2   2965 use FusionInventory::Agent::Tools::Win32;
  2         7  
  2         2129  
9              
10             my @status = (
11             'Unknown', # 0 is not defined
12             'Other',
13             'Unknown',
14             'Idle',
15             'Printing',
16             'Warming Up',
17             'Stopped printing',
18             'Offline',
19             );
20              
21             my @errStatus = (
22             'Unknown',
23             'Other',
24             'No Error',
25             'Low Paper',
26             'No Paper',
27             'Low Toner',
28             'No Toner',
29             'Door Open',
30             'Jammed',
31             'Service Requested',
32             'Output Bin Full',
33             'Paper Problem',
34             'Cannot Print Page',
35             'User Intervention Required',
36             'Out of Memory',
37             'Server Unknown',
38             );
39              
40             sub isEnabled {
41 0     0 0 0 my (%params) = @_;
42              
43 0         0 return !$params{no_category}->{printer};
44             }
45              
46             sub doInventory {
47 0     0 0 0 my (%params) = @_;
48              
49 0         0 my $inventory = $params{inventory};
50 0         0 my $logger = $params{logger};
51              
52 0         0 foreach my $object (getWMIObjects(
53             class => 'Win32_Printer',
54             properties => [ qw/
55             ExtendedDetectedErrorState HorizontalResolution VerticalResolution Name
56             Comment Description DriverName PortName Network Shared PrinterStatus
57             ServerName ShareName PrintProcessor
58             / ]
59             )) {
60              
61 0         0 my $errStatus;
62 0 0       0 if ($object->{ExtendedDetectedErrorState}) {
63 0         0 $errStatus = $errStatus[$object->{ExtendedDetectedErrorState}];
64             }
65              
66 0         0 my $resolution;
67              
68 0 0       0 if ($object->{HorizontalResolution}) {
69             $resolution =
70             $object->{HorizontalResolution} .
71             "x" .
72 0         0 $object->{VerticalResolution};
73             }
74              
75             $object->{Serial} = _getUSBPrinterSerial($object->{PortName}, $logger)
76 0 0 0     0 if $object->{PortName} && $object->{PortName} =~ /USB/;
77              
78             $inventory->addEntry(
79             section => 'PRINTERS',
80             entry => {
81             NAME => $object->{Name},
82             COMMENT => $object->{Comment},
83             DESCRIPTION => $object->{Description},
84             DRIVER => $object->{DriverName},
85             PORT => $object->{PortName},
86             RESOLUTION => $resolution,
87             NETWORK => $object->{Network},
88             SHARED => $object->{Shared},
89             STATUS => $status[$object->{PrinterStatus}],
90             ERRSTATUS => $errStatus,
91             SERVERNAME => $object->{ServerName},
92             SHARENAME => $object->{ShareName},
93             PRINTPROCESSOR => $object->{PrintProcessor},
94             SERIAL => $object->{Serial}
95             }
96 0         0 );
97              
98             }
99             }
100              
101             sub _getUSBPrinterSerial {
102 9     9   4098 my ($portName, $logger) = @_;
103              
104             # the serial number can be extracted from the USB registry key, containing
105             # all USB devices, but we only know the USB port identifier, meaning we
106             # must first look in USBPRINT registry key, containing USB printers only,
107             # and find some way to correlate entries
108 9         29 my $usbprint_key = getRegistryKey(
109             path => "HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Enum/USBPRINT",
110             logger => $logger
111             );
112              
113 9         13463 my $usb_key = getRegistryKey(
114             path => "HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Enum/USB",
115             logger => $logger
116             );
117              
118             # the ContainerID variable seems more reliable, but is not always available
119 9         180072 my $containerId = _getUSBContainerID($usbprint_key, $portName);
120 9 100       23 if ($containerId) {
121 2         8 my $serial = _getUSBSerialFromContainerID($usb_key, $containerId);
122 2 50       186 return $serial if $serial;
123             }
124              
125             # fallback on ParentIdPrefix variable otherwise
126 7         20 my $prefix = _getUSBPrefix($usbprint_key, $portName);
127 7 50       21 if ($prefix) {
128 7         17 my $serial = _getUSBSerialFromPrefix($usb_key, $prefix);
129 7 100       503 return $serial if $serial;
130             }
131              
132             # bad luck
133 3         356 return;
134             }
135              
136             sub _getUSBContainerID {
137 9     9   20 my ($print, $portName) = @_;
138              
139             # registry data structure:
140             # USBPRINT
141             # └── device
142             # └── subdevice
143             # └── ContainerID:value
144             # └── Device Parameters
145             # └── PortName:value
146              
147 9         29 foreach my $device (values %$print) {
148 13         41 foreach my $subdeviceName (keys %$device) {
149 14         29 my $subdevice = $device->{$subdeviceName};
150             next unless
151             $subdevice->{'Device Parameters/'} &&
152             $subdevice->{'Device Parameters/'}->{'/PortName'} &&
153 14 100 33     128 $subdevice->{'Device Parameters/'}->{'/PortName'} eq $portName;
      66        
154             # got it
155 9         27 return $subdevice->{'/ContainerID'};
156             };
157             }
158              
159 0         0 return;
160             }
161              
162             sub _getUSBPrefix {
163 7     7   10 my ($print, $portName) = @_;
164              
165             # registry data structure:
166             # USBPRINT
167             # └── device
168             # └── subdevice
169             # └── Device Parameters
170             # └── PortName:value
171              
172 7         14 foreach my $device (values %$print) {
173 11         25 foreach my $subdeviceName (keys %$device) {
174 12         21 my $subdevice = $device->{$subdeviceName};
175             next unless
176             $subdevice->{'Device Parameters/'} &&
177             $subdevice->{'Device Parameters/'}->{'/PortName'} &&
178 12 100 33     83 $subdevice->{'Device Parameters/'}->{'/PortName'} eq $portName;
      66        
179             # got it
180 7         13 my $prefix = $subdeviceName;
181 7         141 $prefix =~ s{&$portName/$}{};
182 7         23 return $prefix;
183             };
184             }
185              
186 0         0 return;
187             }
188              
189             sub _getUSBSerialFromPrefix {
190 7     7   12 my ($usb, $prefix) = @_;
191              
192             # registry data structure:
193             # USB
194             # └── device
195             # └── subdevice
196             # └── ParentIdPrefix:value
197              
198 7         35 foreach my $device (values %$usb) {
199 58         147 foreach my $subdeviceName (keys %$device) {
200 115         203 my $subdevice = $device->{$subdeviceName};
201             next unless
202             $subdevice->{'/ParentIdPrefix'} &&
203 115 100 100     477 $subdevice->{'/ParentIdPrefix'} eq $prefix;
204             # got it
205 7         16 my $serial = $subdeviceName;
206             # pseudo serial generated by windows
207 7 100       27 return if $serial =~ /&/;
208 4         15 $serial =~ s{/$}{};
209 4         13 return $serial;
210             }
211             }
212              
213 0         0 return;
214             }
215              
216             sub _getUSBSerialFromContainerID {
217 2     2   4 my ($usb, $containerId) = @_;
218              
219             # registry data structure:
220             # USB
221             # └── device
222             # └── subdevice
223             # └── ContainerId:value
224              
225 2         9 foreach my $device (values %$usb) {
226 29         67 foreach my $subdeviceName (keys %$device) {
227 38         64 my $subdevice = $device->{$subdeviceName};
228             next unless
229             $subdevice->{'/ContainerID'} &&
230 38 100 66     188 $subdevice->{'/ContainerID'} eq $containerId;
231             # pseudo serial generated by windows
232 4 100       15 next if $subdeviceName =~ /&/;
233             # got it
234 2         5 my $serial = $subdeviceName;
235 2         11 $serial =~ s{/$}{};
236 2         7 return $serial;
237             }
238             }
239              
240 0           return;
241             }
242              
243             1;