File Coverage

blib/lib/Net/Peep/Parser.pm
Criterion Covered Total %
statement 199 236 84.3
branch 76 96 79.1
condition 20 62 32.2
subroutine 21 22 95.4
pod 0 15 0.0
total 316 431 73.3


line stmt bran cond sub pod time code
1             package Net::Peep::Parser;
2              
3             require 5.00503;
4 3     3   797 use strict;
  3         7  
  3         125  
5             # use warnings; # commented out for 5.005 compatibility
6 3     3   19 use Carp;
  3         15  
  3         192  
7 3     3   17 use Data::Dumper;
  3         7  
  3         244  
8 3     3   19 use Net::Peep::Log;
  3         5  
  3         117  
9 3     3   1568 use Net::Peep::Conf;
  3         9  
  3         174  
10 3     3   1961 use Net::Peep::Notifier;
  3         13  
  3         180  
11              
12             require Exporter;
13              
14 3     3   17 use vars qw{ @ISA %EXPORT_TAGS @EXPORT_OK @EXPORT $VERSION };
  3         6  
  3         21831  
15              
16             @ISA = qw(Exporter);
17             %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
18             @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
19             @EXPORT = qw( );
20             $VERSION = do { my @r = (q$Revision: 1.6 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r };
21              
22             sub new {
23              
24 5     5 0 19 my $self = shift;
25 5   33     30 my $class = ref($self) || $self;
26 5         12 my $this = {};
27 5         31 bless $this, $class;
28              
29             } # end sub new
30              
31             # On spawning a new configuration file parser, we expect to get
32             # a reference to a hash that contains:
33             # 'config' => Which is a pointer to the configuration file
34             # 'app' => The application for which to get the configuration
35             sub load {
36 4     4 0 8 my $self = shift;
37 4   33     16 my $conf = shift || confess "Cannot parse configuration file: No configuration object found.";
38 4         504 $self->conf($conf);
39 4 50       21 confess "Peep couldn't find the configuration file [", $conf->getOption('config'), "]: $!"
40             unless -e $conf->getOption('config');
41 4         26 $self->parseConfig();
42              
43             } # end sub load
44              
45             sub conf {
46              
47 200     200 0 275 my $self = shift;
48 200 100       413 if (@_) { $self->{'CONF'} = shift; }
  4         101  
49 200         1236 return $self->{'CONF'};
50              
51             } # end sub conf
52              
53             sub parseConfig {
54              
55 4     4 0 8 my $self = shift;
56 4         17 my $conf = $self->conf()->getOption('config');
57              
58 4   33     167 open FILE, "<$conf" || confess "Could not open [$conf]: $!";
59 4         140 while (my $line = ) {
60 116         168 my $msg = $line;
61 116         192 chomp $msg;
62 116         192 $msg = substr $msg, 0, 40;
63 116         255 $self->logger()->debug(9,"Parsing [$conf] line [$msg ...]");
64 116 100       462 next if $line =~ /^\s*#/;
65             # version 0.4.3 had a standalone version tag
66 76 50       161 $self->parseVersion(\*FILE, $1) if $line =~ /^\s*version (.*)/;
67 76 100       198 $self->parseGeneral(\*FILE, $1) if $line =~ /^\s*general/;
68 76 100       182 $self->parseNotification(\*FILE, $1) if $line =~ /^\s*notification/;
69 76 100       180 $self->parseClass(\*FILE, $1) if $line =~ /^\s*class (.*)/;
70 76 100       235 $self->parseClient(\*FILE, $1) if $line =~ /^\s*client (.*)/;
71 76 100       203 $self->parseEvents(\*FILE, $1) if $line =~ /^\s*events/;
72 76 100       337 $self->parseStates(\*FILE, $1) if $line =~ /^\s*states/;
73             # $self->parseHosts(\*FILE, $1) if $line =~ /^\s*hosts/;
74             }
75 4         90 close FILE;
76              
77             } # end sub parseConfig
78              
79             sub parseGeneral {
80              
81 4     4 0 10 my $self = shift;
82 4   33     17 my $file = shift || confess "file not found";
83              
84 4         11 $self->logger()->debug(1,"Parsing general configuration information ...");
85              
86 4         67 while (my $line = <$file>) {
87 12 50       41 next if $line =~ /^\s*#/;
88 12 100       42 if ($line =~ /^\s*end/) {
89 4         11 return;
90             } else {
91 8         41 $line =~ /^\s*([\w-]+)\s+(.*)$/;
92 8         28 my ($key, $value) = ($1,$2);
93             # Remove any leading or trailing whitespace
94 8         19 for ($key,$value) { s/^\s+//g; s/\s+$//g; }
  16         33  
  16         40  
95 8 100       38 if ($key eq 'version') {
    50          
96 4         14 $self->conf()->setVersion($value);
97             } elsif ($key eq 'sound-path') {
98 4         22 $self->conf()->setSoundPath($value);
99             } else {
100 0         0 $self->logger()->log("Configuration option [$key] not recognized.");
101             }
102             }
103              
104             }
105              
106             } # end sub parseGeneral
107              
108             sub parseNotification {
109              
110 4     4 0 16 my $self = shift;
111 4   33     16 my $file = shift || confess "file not found";
112              
113 4         14 $self->logger()->debug(1,"Parsing notification configuration information ...");
114              
115 4         32 while (my $line = <$file>) {
116 28 100       143 next if $line =~ /^\s*#/;
117 12 100       271 if ($line =~ /^\s*end/) {
118 4         19 return;
119             } else {
120 8         37 $line =~ /^\s*([\w-]+)\s+(.*)$/;
121 8         31 my ($key, $value) = ($1,$2);
122             # Remove any leading or trailing whitespace
123 8         17 for ($key,$value) { s/^\s+//; s/\s+$//; }
  16         32  
  16         37  
124 8 100       34 if ($key eq 'smtp-relays') {
    50          
125 4         22 my (@relays) = split /[\s,]+/, $value;
126 4         15 $self->logger()->debug(1,"\tFound SMTP relays [@relays]");
127 4         29 @Net::Peep::Notifier::SMTP_RELAYS = @relays;
128             } elsif ($key eq 'notification-interval') {
129 4 50       22 confess "The notification interval must be an integer value!"
130             unless $value =~ /^\d+$/;
131 4         17 $self->logger()->debug(1,"\tFound notification interval [$value]");
132 4         22 $Net::Peep::Notifier::NOTIFICATION_INTERVAL = $value;
133             } else {
134 0         0 $self->logger()->log("\tNotification option [$key] not recognized.");
135             }
136             }
137              
138             }
139              
140 0         0 $self->logger()->debug(1,"\tNotification configuration information parsed.");
141              
142             } # end sub parseNotification
143              
144             sub parseVersion {
145              
146 0     0 0 0 my $self = shift;
147              
148 0   0     0 my $file = shift || confess "file not found";
149 0   0     0 my $version = shift || confess "version not found";
150              
151 0         0 $self->logger()->debug(1,"Parsing version [$version] ...");
152              
153 0         0 $self->conf()->setVersion($version);
154              
155 0         0 $self->logger()->debug(1,"\tVersion parsed.");
156              
157             } # end sub parseVersion
158              
159             sub parseClass {
160 4     4 0 9 my $self = shift;
161 4   33     18 my $file = shift || confess "file not found";
162 4   33     21 my $classname = shift || confess "classname not found";
163 4         8 my (@broadcast, @servers, $newbroadcast);
164 0         0 my %servports;
165              
166 4         20 $self->logger()->debug(1,"Parsing class [$classname] ...");
167              
168 4         42 while (my $line = <$file>) {
169 12 100       60 if ($line =~ /^\s*end/) {
170             #Then check if we should make an entry
171 4 50 33     34 if (@broadcast && @servers) {
172 4         13 $self->conf()->addClass($classname,\@servers);
173              
174             #We need the same broadcast zones as the servers but
175             #We need the different server ports.
176 4         10 foreach my $server (@servers) {
177 4         22 my ($name, $port) = split /:/, $server;
178 4         18 $self->conf()->addServer($classname,{ name => $name, port => $port });
179 4         17 $self->logger()->debug(1,"\tServer [$name:$port] added.");
180 4         22 $servports{$port} = 1; #define the key
181             }
182 4         20 foreach my $zone (@broadcast) {
183 4         23 my ($ip, $port) = split /:/, $zone;
184 4         17 $self->logger()->debug(1,"\tBroadcast [$ip:$port] added.");
185 4         15 $self->conf()->addBroadcast($classname,{ ip => $ip, port => $port });
186             }
187             }
188 4         15 $self->logger()->debug(1,"\tClass [$classname] parsed.");
189 4         18 return;
190             } else {
191              
192 8 100       56 push (@broadcast, split(/\s+/, $1) ) if $line =~ /^\s*broadcast (.*)/;
193 8 100       64 push (@servers, split (/\s+/, $1) ) if $line =~ /^\s*server (.*)/;
194              
195             }
196              
197              
198             }
199              
200             } # end sub parseClass
201              
202             sub parseClient {
203              
204 16     16 0 25 my $self = shift;
205              
206 16   33     55 my $file = shift || confess "Cannot parse client: File not found";
207 16   33     65 my $client = shift || confess "Cannot parse client: Client not found";
208 16         23 my %classes;
209              
210 16         37 $self->logger()->debug(1,"Parsing client [$client] ...");
211              
212             # Let's figure out which classes we're part of and grab the
213             # program's configuration
214 16         60 while (my $line = <$file>) {
215              
216 112 100 50     788 $self->logger()->debug(1,"\tClient [$client] parsed.") and return if $line =~ /^\s*end client $client/;
217 96 100 66     596 next if $line =~ /^\s*#/ or $line =~ /^\s*$/;
218              
219 72 100       203 if ($line =~ /^\s*class(.*)/) {
220 16         32 my $class = $1;
221 16         210 $class =~ s/\s+//g;
222 16         46 my @classes = split /\s+/, $class;
223 16         45 foreach my $one (@classes) {
224 16         38 $classes{$one} = $self->conf()->getClass($one);
225             }
226             }
227              
228 72 100       208 if ($line =~ /^\s*port (\d+)/) {
229 16         33 my $port = $1;
230 16         34 $port =~ s/\s+//g;
231 16         43 $self->conf()->setClientPort($client,$port);
232 16         40 $self->logger()->debug(1,"\tPort [$port] set for client [$client].");
233             }
234              
235 72 100       187 if ($line =~ /^\s*default/) {
236 8         12 my @default;
237              
238 8         33 while (my $line = <$file>) {
239 20 100       75 last if $line =~ /^\s*end default/;
240 12         43 push @default, $line;
241             }
242              
243 8         35 $self->parseClientDefault($client,@default);
244             }
245              
246             # Note that config specifically looks for "end config" because
247             # it may contain several starts and ends
248 72 100       186 if ($line =~ /^\s*config/) {
249 16         29 my @config;
250              
251 16         61 while (my $line = <$file>) {
252 424 100       883 last if $line =~ /^\s*end config/;
253 408         1300 push @config, $line;
254             }
255              
256 16         62 $self->parseClientConfig($client,@config);
257             # I believe the parseClientEvents makes this redundant
258 16         40 $self->conf()->setConfigurationText($client,join '', @config);
259             }
260              
261             # Note that notification specifically looks for "end
262             # notification" because it may contain several starts
263             # and ends
264 72 100       380 if ($line =~ /^\s*notification/) {
265 16         24 my @notification;
266              
267 16         52 while (my $line = <$file>) {
268 84 100       215 last if $line =~ /^\s*end notification/;
269 68         215 push @notification, $line;
270             }
271              
272 16         58 $self->parseClientNotification($client,@notification);
273             # I believe the parseClientEvents makes this redundant
274 16         38 $self->conf()->setNotificationText($client,join '', @notification);
275             }
276              
277             }
278              
279             # Now let's swap in the valid classes
280 0         0 for my $class (keys %classes) { $self->conf()->addClientClass($client,$class); }
  0         0  
281              
282             } # end sub parseClient
283              
284             sub parseEvents {
285              
286 4     4 0 9 my $self = shift;
287 4   33     17 my $file = shift || confess "Cannot parse events: File not found.";
288              
289 4         14 $self->logger()->debug(1,"Parsing events ...");
290              
291 4         21 my $i = 0;
292             # Skip right to the end
293 4         26 while (my $line = <$file>) {
294 84 100       233 last if $line =~ /^\s*end/;
295 80 100       214 next if $line =~ /^\s*#/;
296 72         257 my ($eventname, $file, $nsounds) = split /\s+/, $line;
297              
298 72         1883 $self->conf()->addEvent($eventname,{
299             file => $file,
300             sounds => $nsounds,
301             index => $i++
302             });
303              
304 72         157 $self->logger()->debug(1,"\tEvent [$eventname] added.");
305             }
306              
307             } # end sub parseEvents
308              
309             sub parseClientConfig {
310              
311 16     16 0 23 my $self = shift;
312 16   33     53 my $who = shift || confess "Cannot parse client configuration: Client not identified.";
313 16         119 my @text = @_;
314              
315 16         53 my $client = $self->conf()->client();
316 16         56 my $name = $client->name();
317            
318 16 100       81 if ($who eq $name) {
319              
320 1         4 $self->logger()->debug(1,"\tParsing configuration text for client [$name] ...");
321 1         14 $client->runParser(@text);
322 1         5 $self->logger()->debug(1,"\tDone parsing configuration for client [$name].");
323              
324             }
325              
326             # while (my $line = shift @text) {
327             # next if $line =~ /^\s*#/;
328             # next if $line =~ /^\s*$/;
329             # if ($line =~ /^\s*default/) {
330             # @text = $self->parseClientDefault($client,@text);
331             # } elsif ($line =~ /^\s*events/) {
332             # @text = $self->parseClientEvents($client,@text);
333             # } elsif ($line =~ /^\s*hosts/) {
334             # @text = $self->parseClientHosts($client,@text);
335             # } elsif ($line =~ /^\s*uptime/) {
336             # @text = $self->parseClientUptime($client,@text);
337             # } elsif ($line =~ /^\s*procs/) {
338             # @text = $self->parseClientProcs($client,@text);
339             # } elsif ($line =~ /^\s*disk/) {
340             # @text = $self->parseClientDisk($client,@text);
341             # } else {
342             # $line =~ /^\s*(\w+)\s+(\S+)/;
343             # $self->logger()->debug(1,"\t\tClient option [$1] has been set to value [$2].");
344             # $self->conf()->setOption($client,$1,$2);
345             # }
346             # }
347              
348             } # end sub parseClientConfig
349              
350             sub parseClientNotification {
351              
352 16     16 0 24 my $self = shift;
353 16   33     44 my $client = shift || confess "Cannot parse client notification: Client not identified.";
354 16         40 my @text = @_;
355              
356 16         39 $self->logger()->debug(1,"\tParsing notification for client [$client] ...");
357              
358 16         59 while (my $line = shift @text) {
359 68 50       340 next if $line =~ /^\s*#/;
360 0 0       0 next if $line =~ /^\s*$/;
361              
362 0 0       0 if ($line =~ /^\s*(notification-hosts)\s+(.*)$/) {
    0          
    0          
363 0         0 my ($key,$value) = ($1,$2);
364 0         0 for ($key,$value) { s/^\s+//g; s/\s+$//g; }
  0         0  
  0         0  
365 0         0 my (@hosts) = split /[\s,]+/, $value;
366 0         0 $self->logger()->debug(1,"\t\tFound notification hosts [@hosts].");
367 0         0 $Net::Peep::Notifier::NOTIFICATION_HOSTS{$client} = [ @hosts ];
368             } elsif ($line =~ /^\s*(notification-recipients)\s+(.*)$/) {
369 0         0 my ($key,$value) = ($1,$2);
370 0         0 for ($key,$value) { s/^\s+//g; s/\s+$//g; }
  0         0  
  0         0  
371 0         0 my (@recipients) = split /[\s,]+/, $value;
372 0         0 $self->logger()->debug(1,"\t\tFound notification recipients [@recipients].");
373 0         0 $Net::Peep::Notifier::NOTIFICATION_RECIPIENTS{$client} = [ @recipients ];
374             } elsif ($line =~ /^\s*(notification-level)\s+(\S+)/) {
375 0         0 my ($key,$value) = ($1,$2);
376 0         0 for ($key,$value) { s/^\s+//g; s/\s+$//g; }
  0         0  
  0         0  
377 0         0 $self->logger()->debug(1,"\t\tFound notification level [$value].");
378 0         0 $Net::Peep::Notifier::NOTIFICATION_LEVEL{$client} = $value;
379             } else {
380 0         0 $line =~ /^\s*(\w+)\s+(\S+)/;
381 0         0 $self->logger()->debug(1,"\t\tClient notification option [$1] not recognized.");
382             }
383             }
384              
385             } # end sub parseClientNotification
386              
387             # this method was deprecated with the move of client config parsing
388             # into the client objects
389              
390             #sub parseClientEvents {
391             #
392             # my $self = shift;
393             # my $client = shift || confess "Cannot parse client events: Client not identified.";
394             # my @text = @_;
395             #
396             # $self->logger()->debug(1,"\t\tParsing events for client [$client] ...");
397             #
398             # my @version = $self->conf()->versionExists()
399             # ? split /\./, $self->conf()->getVersion()
400             # : ();
401             #
402             # if (@version && $version[0] >= 0 && $version[1] >= 4 && $version[2] > 3) {
403             #
404             # while (my $line = shift @text) {
405             # next if $line =~ /^\s*#/;
406             # last if $line =~ /^\s*end/;
407             #
408             # my $name;
409             # $line =~ /^\s*([\w-]+)\s+([\w-]+)\s+([a-zA-Z])\s+(\d+)\s+(\d+)\s+(\w+)\s+"(.*)"/;
410             #
411             # my $clientEvent = {
412             # 'name' => $1,
413             # 'group' => $2,
414             # 'option-letter' => $3,
415             # 'location' => $4,
416             # 'priority' => $5,
417             # 'status' => $6,
418             # 'regex' => $7
419             # };
420             #
421             # $self->conf()->addClientEvent($client,$clientEvent);
422             # $self->logger()->debug(1,"\t\t\tClient event [$1] added.");
423             #
424             # }
425             #
426             # } elsif (@version && $version[0] >= 0 && $version[1] >= 4 && $version[2] > 1) {
427             #
428             # while (my $line = shift @text) {
429             # next if $line =~ /^\s*#/;
430             # last if $line =~ /^\s*end/;
431             #
432             # my $name;
433             # $line =~ /^\s*([\w-]+)\s+([\w-]+)\s+([a-zA-Z])\s+(\d+)\s+(\d+)\s+"(.*)"/;
434             #
435             # my $clientEvent = {
436             # 'name' => $1,
437             # 'group' => $2,
438             # 'option-letter' => $3,
439             # 'location' => $4,
440             # 'priority' => $5,
441             # 'regex' => $6
442             # };
443             #
444             # $self->conf()->addClientEvent($client,$clientEvent);
445             # $self->logger()->debug(1,"\t\t\tClient event [$1] added.");
446             #
447             # }
448             #
449             # } else {
450             #
451             # while (my $line = shift @text) {
452             # next if $line =~ /^\s*#/;
453             # last if $line =~ /^\s*end/;
454             #
455             # my $name;
456             # $line =~ /([\w-]+)\s+([a-zA-Z])\s+(\d+)\s+(\d+)\s+"(.*)"/;
457             #
458             # my $clientEvent = {
459             # 'name' => $1,
460             # 'option-letter' => $2,
461             # 'location' => $3,
462             # 'priority' => $4,
463             # 'regex' => $5
464             # };
465             #
466             # $self->conf()->addClientEvent($client,$clientEvent);
467             # $self->logger()->debug(1,"\t\t\tClient event [$1] added.");
468             #
469             # }
470             #
471             # }
472             #
473             # return @text;
474             #
475             #} # end sub parseClientEvents
476              
477             # this method was deprecated with the move of client config parsing
478             # into the client objects
479              
480             #sub parseClientHosts {
481             #
482             # my $self = shift;
483             # my $client = shift || confess "Cannot parse client hosts: Client not identified.";
484             # my @text = @_;
485             #
486             # $self->logger()->debug(1,"\t\tParsing hosts for client [$client] ...");
487             #
488             # while (my $line = shift @text) {
489             # next if $line =~ /^\s*$/;
490             # next if $line =~ /^\s*#/;
491             # last if $line =~ /^\s*end/;
492             #
493             # $line =~ /^\s*([\w\-\.]+)\s+([\w\-]+)\s+([\w\-]+)\s+([a-zA-Z])\s+(\d+)\s+(\d+)\s+(\w+)/;
494             #
495             # my ($host,$name,$group,$letter,$location,$priority,$status) =
496             # ($1,$2,$3,$4,$5,$6,$7);
497             #
498             # my $clientHost = {
499             # host => $host,
500             # name => $name,
501             # group => $group,
502             # 'option-letter' => $letter,
503             # location => $location,
504             # priority => $priority,
505             # status => $status
506             # };
507             #
508             # $self->logger()->debug(1,"\t\t\tClient host [$host] added.") if
509             # $self->conf()->addClientHost($client,$clientHost);
510             #
511             # }
512             #
513             # return @text;
514             #
515             #} # end sub parseClientHosts
516              
517             sub parseClientDefault {
518              
519 8     8 0 18 my $self = shift;
520 8   33     23 my $client = shift || confess "Cannot parse client defaults: Client not identified.";
521 8         20 my @text = @_;
522              
523 8         25 $self->logger()->debug(1,"\tParsing defaults for client [$client] ...");
524              
525 8   33     28 my $conf = $self->conf() || confess "Defaults cannot be parsed: No configuration object found.";
526              
527 8         28 while (my $line = shift @text) {
528 12 50 33     109 next if $line =~ /^\s*#/ || $line =~ /^\s*$/;
529 12 50       68 if ($line =~ /^\s*([\w\-]+)\s+(\S+)/) {
530 12         41 my ($option,$value) = ($1,$2);
531 12 50       43 if ($conf->optionExists($option)) {
532 0         0 $self->logger()->debug(6,"Not setting option [$option]: It has already been set (possibly from the command-line).");
533             } else {
534 12         30 $self->logger()->debug(6,"Setting option [$option] to value [$value].");
535 12 50       39 $conf->setOption($option,$value) unless $conf->optionExists($option);
536             }
537             }
538             }
539              
540 8         25 $self->logger()->debug(1,"\t\tDone.");
541              
542 8         26 return @text;
543              
544             } # end sub parseClientDefault
545              
546             sub parseStates {
547              
548 4     4 0 7 my $self = shift;
549              
550 4   33     17 my $file = shift || confess "Cannot parse states: File not found.";
551              
552 4         16 $self->logger()->debug(1,"Parsing states ...");
553              
554 4         9 my $i = 0;
555             # Skip right to the end
556 4         23 while (my $line = <$file>) {
557 20 100       104 last if $line =~ /^\s*end/;
558 16 100       659 next if $line =~ /^\s*#/;
559 12         57 my ($statename, $file, $sounds, $fade) = split /\s+/, $line;
560              
561 12         36 $self->conf()->addState($statename,{
562             file => $file,
563             sounds => $sounds,
564             fade => $fade,
565             index => $i++
566             });
567              
568 12         39 $self->logger()->debug(1,"\tState [$statename] added.");
569             }
570              
571             } # end sub parseStates
572              
573             # returns a logging object
574             sub logger {
575 334     334 0 437 my $self = shift;
576 334 100       793 if ( ! exists $self->{'__LOGGER'} ) { $self->{'__LOGGER'} = new Net::Peep::Log }
  4         20  
577 334         1575 return $self->{'__LOGGER'};
578             } # end sub logger
579              
580             1;
581              
582             __END__