File Coverage

blib/lib/FusionInventory/Agent/Task/Inventory/Generic/Screen.pm
Criterion Covered Total %
statement 27 117 23.0
branch 0 54 0.0
condition 0 11 0.0
subroutine 9 16 56.2
pod 0 2 0.0
total 36 200 18.0


line stmt bran cond sub pod time code
1             package FusionInventory::Agent::Task::Inventory::Generic::Screen;
2              
3 1     1   98514598 use strict;
  1         16  
  1         105  
4 1     1   12 use warnings;
  1         1  
  1         96  
5              
6 1     1   6 use English qw(-no_match_vars);
  1         50  
  1         30  
7 1     1   1938 use MIME::Base64;
  1         1413  
  1         110  
8 1     1   9 use UNIVERSAL::require;
  1         2  
  1         40  
9              
10 1     1   36 use File::Find;
  1         1  
  1         130  
11 1     1   609 use FusionInventory::Agent::Tools;
  1         3  
  1         226  
12 1     1   698 use FusionInventory::Agent::Tools::Generic;
  1         9  
  1         1289  
13              
14             sub isEnabled {
15 0     0 0   my (%params) = @_;
16 0 0         return 0 if $params{no_category}->{monitor};
17 0           return 1;
18             }
19              
20             sub doInventory {
21 0     0 0   my (%params) = @_;
22              
23 0           my $inventory = $params{inventory};
24 0           my $logger = $params{logger};
25 0           my $datadir = $params{datadir};
26              
27 0           foreach my $screen (_getScreens(logger => $logger, datadir => $datadir)) {
28 0           $inventory->addEntry(
29             section => 'MONITORS',
30             entry => $screen
31             );
32             }
33             }
34              
35             sub _getEdidInfo {
36 0     0     my (%params) = @_;
37              
38 0           Parse::EDID->require();
39 0 0         if ($EVAL_ERROR) {
40 0 0         $params{logger}->debug(
41             "Parse::EDID Perl module not available, unable to parse EDID data"
42             ) if $params{logger};
43 0           return;
44             }
45              
46 0           my $edid = Parse::EDID::parse_edid($params{edid});
47 0 0         if (my $error = Parse::EDID::check_parsed_edid($edid)) {
48 0 0         $params{logger}->debug("bad edid: $error") if $params{logger};
49 0           return;
50             }
51              
52 0   0       my $info = {
53             CAPTION => $edid->{monitor_name},
54             DESCRIPTION => $edid->{week} . "/" . $edid->{year},
55             MANUFACTURER => getEDIDVendor(
56             id => $edid->{manufacturer_name},
57             datadir => $params{datadir}
58             ) || $edid->{manufacturer_name}
59             };
60              
61             # they are two different serial numbers in EDID
62             # - a mandatory 4 bytes numeric value
63             # - an optional 13 bytes ASCII value
64             # we use the ASCII value if present, the numeric value as an hex string
65             # unless for a few list of known exceptions deserving specific handling
66             # References:
67             # http://forge.fusioninventory.org/issues/1607
68             # http://forge.fusioninventory.org/issues/1614
69 0 0 0       if (
    0 0        
70             $edid->{EISA_ID} &&
71             $edid->{EISA_ID} =~ /^ACR(0018|0020|0024|00A8|7883|ad49|adaf)$/
72             ) {
73 0           $info->{SERIAL} =
74             substr($edid->{serial_number2}->[0], 0, 8) .
75             sprintf("%08x", $edid->{serial_number}) .
76             substr($edid->{serial_number2}->[0], 8, 4) ;
77             } elsif (
78             $edid->{EISA_ID} &&
79             $edid->{EISA_ID} eq 'GSM4b21'
80             ) {
81             # split serial in two parts
82 0           my ($high, $low) = $edid->{serial_number} =~ /(\d+) (\d\d\d)$/x;
83              
84             # translate the first part using a custom alphabet
85 0           my @alphabet = split(//, "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ");
86 0           my $base = scalar @alphabet;
87              
88 0           $info->{SERIAL} =
89             $alphabet[$high / $base] . $alphabet[$high % $base] .
90             $low;
91             } else {
92 0 0         $info->{SERIAL} = $edid->{serial_number2} ?
93             $edid->{serial_number2}->[0] :
94             sprintf("%08x", $edid->{serial_number});
95             }
96              
97 0           return $info;
98             }
99              
100             sub _getScreensFromWindows {
101 0     0     my (%params) = @_;
102              
103 0           FusionInventory::Agent::Tools::Win32->use();
104              
105 0           my @screens;
106              
107             # Vista and upper, able to get the second screen
108 0           foreach my $object (getWMIObjects(
109             moniker => 'winmgmts:{impersonationLevel=impersonate,authenticationLevel=Pkt}!//./root/wmi',
110             class => 'WMIMonitorID',
111             properties => [ qw/InstanceName/ ]
112             )) {
113 0 0         next unless $object->{InstanceName};
114              
115 0           $object->{InstanceName} =~ s/_\d+//;
116 0           push @screens, {
117             id => $object->{InstanceName}
118             };
119             }
120              
121             # The generic Win32_DesktopMonitor class, the second screen will be missing
122 0           foreach my $object (getWMIObjects(
123             class => 'Win32_DesktopMonitor',
124             properties => [ qw/
125             Caption MonitorManufacturer MonitorType PNPDeviceID Availability
126             / ]
127             )) {
128 0 0         next unless $object->{Availability};
129 0 0         next unless $object->{PNPDeviceID};
130 0 0         next unless $object->{Availability} == 3;
131              
132 0           push @screens, {
133             id => $object->{PNPDeviceID},
134             NAME => $object->{Caption},
135             TYPE => $object->{MonitorType},
136             MANUFACTURER => $object->{MonitorManufacturer},
137             CAPTION => $object->{Caption}
138             };
139             }
140              
141 0           foreach my $screen (@screens) {
142 0 0         next unless $screen->{id};
143 0   0       $screen->{edid} = getRegistryValue(
144             path => "HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Enum/$screen->{id}/Device Parameters/EDID",
145             logger => $params{logger}
146             ) || '';
147 0           $screen->{edid} =~ s/^\s+$//;
148 0           delete $screen->{id};
149             }
150              
151 0           return @screens;
152             }
153              
154             sub _getScreensFromUnix {
155 0     0     my (%params) = @_;
156              
157 0           my $logger = $params{logger};
158 0           $logger->debug("retrieving EDID data:");
159              
160 0 0         if (-d '/sys/devices') {
161 0           my @screens;
162             my $wanted = sub {
163 0 0   0     return unless $_ eq 'edid';
164 0 0         return unless -e $File::Find::name;
165 0           my $edid = getAllLines(file => $File::Find::name);
166 0 0         push @screens, { edid => $edid } if $edid;
167 0           };
168              
169 1     1   11 no warnings 'File::Find';
  1         2  
  1         582  
170 0           File::Find::find($wanted, '/sys/devices');
171              
172 0           $logger->debug_result(
173             action => 'reading /sys/devices content',
174             data => scalar @screens
175             );
176              
177 0 0         return @screens if @screens;
178             } else {
179 0           $logger->debug_result(
180             action => 'reading /sys/devices content',
181             status => 'directory not available'
182             );
183             }
184              
185 0 0         if (canRun('monitor-get-edid-using-vbe')) {
186 0           my $edid = getAllLines(command => 'monitor-get-edid-using-vbe');
187 0           $logger->debug_result(
188             action => 'running monitor-get-edid-using-vbe command',
189             data => $edid
190             );
191 0 0         return { edid => $edid } if $edid;
192             } else {
193 0           $logger->debug_result(
194             action => 'running monitor-get-edid-using-vbe command',
195             status => 'command not available'
196             );
197             }
198              
199 0 0         if (canRun('monitor-get-edid')) {
200 0           my $edid = getAllLines(command => 'monitor-get-edid');
201 0           $logger->debug_result(
202             action => 'running monitor-get-edid command',
203             data => $edid
204             );
205 0 0         return { edid => $edid } if $edid;
206             } else {
207 0           $logger->debug_result(
208             action => 'running monitor-get-edid command',
209             status => 'command not available'
210             );
211             }
212              
213 0 0         if (canRun('get-edid')) {
214 0           my $edid;
215 0           foreach (1..5) { # Sometime get-edid return an empty string...
216 0           $edid = getFirstLine(command => 'get-edid');
217 0 0         last if $edid;
218             }
219             $logger->debug_result(
220 0           action => 'running get-edid command',
221             data => $edid
222             );
223 0 0         return { edid => $edid } if $edid;
224             } else {
225 0           $logger->debug_result(
226             action => 'running get-edid command',
227             status => 'command not available'
228             );
229             }
230              
231 0           return;
232             }
233              
234             sub _getScreens {
235 0     0     my (%params) = @_;
236              
237 0 0         my @screens = $OSNAME eq 'MSWin32' ?
238             _getScreensFromWindows(%params) :
239             _getScreensFromUnix(%params);
240              
241 0           foreach my $screen (@screens) {
242 0 0         next unless $screen->{edid};
243              
244 0           my $info = _getEdidInfo(
245             edid => $screen->{edid},
246             logger => $params{logger},
247             datadir => $params{datadir},
248             );
249 0           $screen->{CAPTION} = $info->{CAPTION};
250 0           $screen->{DESCRIPTION} = $info->{DESCRIPTION};
251 0           $screen->{MANUFACTURER} = $info->{MANUFACTURER};
252 0           $screen->{SERIAL} = $info->{SERIAL};
253              
254 0           $screen->{BASE64} = encode_base64($screen->{edid});
255              
256 0           delete $screen->{edid};
257             }
258              
259 0           return @screens;
260             }
261              
262             1;