File Coverage

blib/lib/FusionInventory/Agent/Task/Inventory/Win32/Printers.pm
Criterion Covered Total %
statement 12 74 16.2
branch 0 26 0.0
condition 0 21 0.0
subroutine 4 11 36.3
pod 0 2 0.0
total 16 134 11.9


line stmt bran cond sub pod time code
1             package FusionInventory::Agent::Task::Inventory::Win32::Printers;
2              
3 1     1   53590700 use strict;
  1         9  
  1         71  
4 1     1   6 use warnings;
  1         2  
  1         74  
5              
6 1     1   4 use English qw(-no_match_vars);
  1         33  
  1         19  
7              
8 1     1   1044 use FusionInventory::Agent::Tools::Win32;
  1         3  
  1         800  
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   my (%params) = @_;
42              
43 0           return !$params{no_category}->{printer};
44             }
45              
46             sub doInventory {
47 0     0 0   my (%params) = @_;
48              
49 0           my $inventory = $params{inventory};
50 0           my $logger = $params{logger};
51              
52 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           my $errStatus;
62 0 0         if ($object->{ExtendedDetectedErrorState}) {
63 0           $errStatus = $errStatus[$object->{ExtendedDetectedErrorState}];
64             }
65              
66 0           my $resolution;
67              
68 0 0         if ($object->{HorizontalResolution}) {
69 0           $resolution =
70             $object->{HorizontalResolution} .
71             "x" .
72             $object->{VerticalResolution};
73             }
74              
75 0 0 0       $object->{Serial} = _getUSBPrinterSerial($object->{PortName}, $logger)
76             if $object->{PortName} && $object->{PortName} =~ /USB/;
77              
78 0           $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             );
97              
98             }
99             }
100              
101             sub _getUSBPrinterSerial {
102 0     0     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 0           my $usbprint_key = getRegistryKey(
109             path => "HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Enum/USBPRINT",
110             logger => $logger
111             );
112              
113 0           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 0           my $containerId = _getUSBContainerID($usbprint_key, $portName);
120 0 0         if ($containerId) {
121 0           my $serial = _getUSBSerialFromContainerID($usb_key, $containerId);
122 0 0         return $serial if $serial;
123             }
124              
125             # fallback on ParentIdPrefix variable otherwise
126 0           my $prefix = _getUSBPrefix($usbprint_key, $portName);
127 0 0         if ($prefix) {
128 0           my $serial = _getUSBSerialFromPrefix($usb_key, $prefix);
129 0 0         return $serial if $serial;
130             }
131              
132             # bad luck
133 0           return;
134             }
135              
136             sub _getUSBContainerID {
137 0     0     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 0           foreach my $device (values %$print) {
148 0           foreach my $subdeviceName (keys %$device) {
149 0           my $subdevice = $device->{$subdeviceName};
150             next unless
151 0 0 0       $subdevice->{'Device Parameters/'} &&
      0        
152             $subdevice->{'Device Parameters/'}->{'/PortName'} &&
153             $subdevice->{'Device Parameters/'}->{'/PortName'} eq $portName;
154             # got it
155 0           return $subdevice->{'/ContainerID'};
156             };
157             }
158              
159 0           return;
160             }
161              
162             sub _getUSBPrefix {
163 0     0     my ($print, $portName) = @_;
164              
165             # registry data structure:
166             # USBPRINT
167             # └── device
168             # └── subdevice
169             # └── Device Parameters
170             # └── PortName:value
171              
172 0           foreach my $device (values %$print) {
173 0           foreach my $subdeviceName (keys %$device) {
174 0           my $subdevice = $device->{$subdeviceName};
175             next unless
176 0 0 0       $subdevice->{'Device Parameters/'} &&
      0        
177             $subdevice->{'Device Parameters/'}->{'/PortName'} &&
178             $subdevice->{'Device Parameters/'}->{'/PortName'} eq $portName;
179             # got it
180 0           my $prefix = $subdeviceName;
181 0           $prefix =~ s{&$portName/$}{};
182 0           return $prefix;
183             };
184             }
185              
186 0           return;
187             }
188              
189             sub _getUSBSerialFromPrefix {
190 0     0     my ($usb, $prefix) = @_;
191              
192             # registry data structure:
193             # USB
194             # └── device
195             # └── subdevice
196             # └── ParentIdPrefix:value
197              
198 0           foreach my $device (values %$usb) {
199 0           foreach my $subdeviceName (keys %$device) {
200 0           my $subdevice = $device->{$subdeviceName};
201             next unless
202 0 0 0       $subdevice->{'/ParentIdPrefix'} &&
203             $subdevice->{'/ParentIdPrefix'} eq $prefix;
204             # got it
205 0           my $serial = $subdeviceName;
206             # pseudo serial generated by windows
207 0 0         return if $serial =~ /&/;
208 0           $serial =~ s{/$}{};
209 0           return $serial;
210             }
211             }
212              
213 0           return;
214             }
215              
216             sub _getUSBSerialFromContainerID {
217 0     0     my ($usb, $containerId) = @_;
218              
219             # registry data structure:
220             # USB
221             # └── device
222             # └── subdevice
223             # └── ContainerId:value
224              
225 0           foreach my $device (values %$usb) {
226 0           foreach my $subdeviceName (keys %$device) {
227 0           my $subdevice = $device->{$subdeviceName};
228             next unless
229 0 0 0       $subdevice->{'/ContainerID'} &&
230             $subdevice->{'/ContainerID'} eq $containerId;
231             # pseudo serial generated by windows
232 0 0         next if $subdeviceName =~ /&/;
233             # got it
234 0           my $serial = $subdeviceName;
235 0           $serial =~ s{/$}{};
236 0           return $serial;
237             }
238             }
239              
240 0           return;
241             }
242              
243             1;