File Coverage

blib/lib/FusionInventory/Agent/Task/Inventory/Generic/Screen.pm
Criterion Covered Total %
statement 41 117 35.0
branch 8 54 14.8
condition 8 11 72.7
subroutine 10 16 62.5
pod 0 2 0.0
total 67 200 33.5


line stmt bran cond sub pod time code
1             package FusionInventory::Agent::Task::Inventory::Generic::Screen;
2              
3 2     2   107418486 use strict;
  2         9  
  2         72  
4 2     2   7 use warnings;
  2         7  
  2         87  
5              
6 2     2   8 use English qw(-no_match_vars);
  2         39  
  2         23  
7 2     2   1792 use MIME::Base64;
  2         1265  
  2         98  
8 2     2   10 use UNIVERSAL::require;
  2         6  
  2         21  
9              
10 2     2   82 use File::Find;
  2         2  
  2         116  
11 2     2   399 use FusionInventory::Agent::Tools;
  2         4  
  2         264  
12 2     2   718 use FusionInventory::Agent::Tools::Generic;
  2         5  
  2         1382  
13              
14             sub isEnabled {
15 0     0 0 0 my (%params) = @_;
16 0 0       0 return 0 if $params{no_category}->{monitor};
17 0         0 return 1;
18             }
19              
20             sub doInventory {
21 0     0 0 0 my (%params) = @_;
22              
23 0         0 my $inventory = $params{inventory};
24 0         0 my $logger = $params{logger};
25 0         0 my $datadir = $params{datadir};
26              
27 0         0 foreach my $screen (_getScreens(logger => $logger, datadir => $datadir)) {
28 0         0 $inventory->addEntry(
29             section => 'MONITORS',
30             entry => $screen
31             );
32             }
33             }
34              
35             sub _getEdidInfo {
36 61     61   262 my (%params) = @_;
37              
38 61         240 Parse::EDID->require();
39 61 50       1332 if ($EVAL_ERROR) {
40             $params{logger}->debug(
41             "Parse::EDID Perl module not available, unable to parse EDID data"
42 0 0       0 ) if $params{logger};
43 0         0 return;
44             }
45              
46 61         136 my $edid = Parse::EDID::parse_edid($params{edid});
47 61 50       125274 if (my $error = Parse::EDID::check_parsed_edid($edid)) {
48 0 0       0 $params{logger}->debug("bad edid: $error") if $params{logger};
49 0         0 return;
50             }
51              
52             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 61   66     737 };
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 61 100 100     404 if (
    100 100        
70             $edid->{EISA_ID} &&
71             $edid->{EISA_ID} =~ /^ACR(0018|0020|0024|00A8|7883|ad49|adaf)$/
72             ) {
73             $info->{SERIAL} =
74             substr($edid->{serial_number2}->[0], 0, 8) .
75             sprintf("%08x", $edid->{serial_number}) .
76 6         25 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 2         10 my ($high, $low) = $edid->{serial_number} =~ /(\d+) (\d\d\d)$/x;
83              
84             # translate the first part using a custom alphabet
85 2         11 my @alphabet = split(//, "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ");
86 2         3 my $base = scalar @alphabet;
87              
88             $info->{SERIAL} =
89 2         9 $alphabet[$high / $base] . $alphabet[$high % $base] .
90             $low;
91             } else {
92             $info->{SERIAL} = $edid->{serial_number2} ?
93             $edid->{serial_number2}->[0] :
94 53 100       137 sprintf("%08x", $edid->{serial_number});
95             }
96              
97 61         808 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             push @screens, {
117             id => $object->{InstanceName}
118 0           };
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             push @screens, {
133             id => $object->{PNPDeviceID},
134             NAME => $object->{Caption},
135             TYPE => $object->{MonitorType},
136             MANUFACTURER => $object->{MonitorManufacturer},
137             CAPTION => $object->{Caption}
138 0           };
139             }
140              
141 0           foreach my $screen (@screens) {
142 0 0         next unless $screen->{id};
143             $screen->{edid} = getRegistryValue(
144             path => "HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Enum/$screen->{id}/Device Parameters/EDID",
145             logger => $params{logger}
146 0   0       ) || '';
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 2     2   9 no warnings 'File::Find';
  2         2  
  2         646  
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             my $info = _getEdidInfo(
245             edid => $screen->{edid},
246             logger => $params{logger},
247             datadir => $params{datadir},
248 0           );
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;