1 package Bcd
::Commands
::InputCommandParser
;
3 # This file is part of the breadcrumbs daemon (bcd).
4 # Copyright (C) 2007 Pasqualino Ferrentino
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 # Contact: lino.ferrentino@yahoo.it (in Italian, English or German).
26 use Bcd
::Errors
::ErrorCodes
;
30 use Storable
qw(thaw);
31 use Bcd
::Data
::PostCode
;
32 use POSIX
qw(strftime);
34 use constant PARAM_CHECK_TABLE
=> {
35 nick_type
=> \
&_check_nick
,
36 post_code_with_sub_or_not_type
=> \
&_check_post_code_with_sub_or_not
,
37 string_type
=> \
&_check_string
,
41 ##These are the functions which check the validity of the parameter.
45 #the nicks which start with "bc-" are reserved
46 if ($value =~ /^bc-/){
47 return Bcd
::Errors
::ErrorCodes
::BEC_RESERVED_ID
;
50 if ($value !~ /^[\w-]{3,20}$/){
51 return Bcd
::Errors
::ErrorCodes
::BEC_LENGTH_OR_CHAR_NOT_VALID_IN_ID
;
57 sub _check_post_code_with_sub_or_not
{
62 #let's check the post code. It can be generic, so with or without suffix
63 if (! Bcd
::Data
::PostCode
::is_valid_post_code_with_sub
($value)){
64 if ( ! Bcd
::Data
::PostCode
::is_valid_post_code
($value)){
65 return Bcd
::Errors
::ErrorCodes
::BEC_INVALID_POST_CODE
;
75 #no controls, for now... maybe length or other... a regex?
82 my ($class, $mode, $script) = @_;
85 $self->{mode
} = $mode;
86 $self->{script
} = $script;
88 #ok, I can open the file for scripting
89 my @time = localtime();
90 my $year = $time[5] + 1900;
91 my $month = $time[4] + 1;
92 my $name = "/tmp/${year}_${month}_$time[3]_$time[2]_$time[1]_$time[0]_bc_script";
94 open $file, "> $name" or die "cannot open file $name";
95 $self->{script_file
} = $file;
98 bless ($self, $class);
104 if ($self->{script
} == 1){
105 close $self->{script_file
};
110 my ($self, $mode) = @_;
111 $self->{mode
} = $mode;
114 sub start_parsing_command
{
115 my ($self, $param_table) = @_;
117 $self->{param_table
} = $param_table;
118 $self->{parsing_result
}= Bcd
::Errors
::ErrorCodes
::BEC_OK
;
119 $self->{parsing_index
} = 0;
120 #$self->{err_flag} = 0;
121 $self->{parsed_result
} = {};
126 #this method selects a particular input stream from which
127 #we can extract the parameters.
128 sub new_command_from_input
{
129 my ($self, $command, $input_stream) = @_;
130 if ($self->{script
} == 1){
131 #ok, I write the command name in the file
132 $self->{script_file
}->flush() if ($command eq "an_get_summary");
133 my $now_string = strftime
"%a %b %e %H:%M:%S %Y", localtime;
134 my $file = $self->{script_file
};
135 print $file "\n#### new command at $now_string\n";
136 print $file $command . "\n";
138 $self->{_input
} = $input_stream;
142 my ($self, $command) = @_;
143 $self->{_command
} = $command;
146 sub _validate_params
{
149 $self->{parsing_result
} = Bcd
::Errors
::ErrorCodes
::BEC_OK
;
151 my $param_list = $self->{param_table
}->[0];
152 my $param_hash = $self->{param_table
}->[1];
153 foreach(@
{$param_list}){
154 if ($self->_validate_param($param_hash->{$_}, $self->{parsed_result
}->{$_})){
163 my ($self, $param_desc, $param_value) = @_;
165 #first of all I check the existence of the parameter
166 if (!defined($param_value)){
167 if ($param_desc->[1] eq "required"){
168 $self->{parsing_result
} = Bcd
::Errors
::ErrorCodes
::BEC_REQUIRED_PARAMETER_MISSING
;
169 return 1; #this parameter is required
175 #ok, the parameter has a value, let's check it
176 my $param_type = $param_desc->[0];
178 if (!exists(PARAM_CHECK_TABLE
->{$param_type})){
179 die "unknown parameter type $param_type";
182 if ($res = &PARAM_CHECK_TABLE
->{$param_type}($param_value)){
184 $self->{parsing_result
} = $res;
194 sub parse_binary_input
{
196 my $command = $self->{_command
};
197 my $input = $self->{_input
};
199 my $stream_mode = <$input>;
202 if ($stream_mode =~ /c/){
212 #the dot at the start of the string should be avoided
219 my $decoded = decode_base64
($blob);
222 if ($compressed == 1){
223 #ok, I should decompress it!
224 $stream = Compress
::Zlib
::memGunzip
($decoded);
229 my $res = thaw
$stream;
231 #ok, now I make the script, if it is needed
232 if ($self->{script
} == 1){
233 if (ref $res eq "ARRAY"){
237 $tmp =~ s/^(\.?)/$1$1/sg;
238 $tmp =~ s/\012(\.?)/\012$1$1/sg;
239 $tmp =~ s/\012(.)/\\\012$1/sg;
240 print {$self->{script_file
}} $tmp . "\n";
242 #at the end a print a single dot
243 print {$self->{script_file
}} ".\n#END OF COMMAND\n";
247 #ok, I have the input...
249 if (defined($command)){
250 $self->_inject_the_old_parameters($res);
252 $self->fill_params($self->{param_table
}, $res);
256 #this is a function used only to inject the parameters in the old commands
257 sub _inject_the_old_parameters
{
258 my ($self, $params) = @_;
260 my $command = $self->{_command
};
262 my $param_list = $command->{parameters
};
265 #if I have the command I inject the parameters
266 #inside the command, this is a hack for the legacy commands
269 my $param = $param_list->[$i];
271 if (ref($param) eq "HASH"){
272 if ($param->{type
} eq "multi_line"){
273 $name = $param->{name
};
274 } elsif ($param->{type
} eq "ellipsis"){
276 #ok... I should inject the ellipsis
277 if (! exists($command->{ellipsis
})){
278 $command->{ellipsis
} = []; #empty array
280 push(@
{$command->{ellipsis
}}, $_);
281 #print Dumper($command->{ellipsis});
282 next; #I do not advance in the counter...
285 $name = $param_list->[$i];
288 $command->{$name} = $_;
292 #ok, now I should check the number of parameters
294 #no ellipsis, the number of parameters should be the same
295 if (scalar(@
{$params}) > scalar(@
{$param_list})){
296 $self->{parsing_result
} = Bcd
::Errors
::ErrorCodes
::BEC_TOO_MANY_PARAMETERS
;
297 } elsif (scalar(@
{$params}) < scalar(@
{$param_list})){
298 $self->{parsing_result
} = Bcd
::Errors
::ErrorCodes
::BEC_TOO_FEW_PARAMETERS
;
301 #there is an ellipsis, the number of parameters should be greater
302 if (scalar(@
{$params}) < scalar(@
{$param_list})){
303 $self->{parsing_result
} = Bcd
::Errors
::ErrorCodes
::BEC_TOO_FEW_PARAMETERS
;
308 $command->{state} = Bcd
::Commands
::SimpleCommand
::READY_TO_EXECUTE
;
311 #this is a recursive function, I fill the params in the tables walking the tree
314 my ($self, $param_table, $params) = @_;
316 my $children = $param_table->[2];
318 if (defined($children)) {
319 #recurse inside the children
320 foreach(@
{$children}){
321 $self->fill_params($_, $params);
325 #ok, then I fill this part of the table and return one level up
326 my $list = $param_table->[0];
328 $self->{parsed_result
}->{$_} = shift(@
{$params}); #they are in order
336 my $command = $self->{_command
};
337 my $input = $self->{_input
};
339 $command->start_parsing_command() if (defined($command));
341 if ($self->{mode
} == Bcd
::Common
::CommonConstants
::BINARY_MODE
){
342 $self->parse_binary_input();
343 $self->eot() if (!defined($command));
362 #if it has remained a single slash before the end simply continues on the same line
364 chop; #eliminate the single slash...
365 if ($multi_line == 0){
377 if ($multi_line == 1){
380 #I return normally for the next part
382 $cur_line = $back_line;
387 #if (defined($command)){
388 #$command->parse_line($cur_line);
390 push(@input_params, $cur_line);
395 if (defined($command)){
396 $self->_inject_the_old_parameters(\
@input_params);
398 $self->fill_params($self->{param_table
}, \
@input_params);
408 # if ($self->{parsing_index} < scalar(@{$self->{param_table}->[0]})){
409 # $self->{parsing_result} = Bcd::Errors::ErrorCodes::BEC_TOO_FEW_PARAMETERS;
412 #ok, I have all the parameters... let's validate them
413 $self->_validate_params();
416 #this is called for the tests
420 #I have to fill the parameters
421 $self->fill_params($self->{param_table
}, $self->{_args
});
422 $self->_validate_params();
424 #print "eot_from_test\n";
425 #print Dumper($self);
426 #print "eot_from_test end \n";
430 my ($self, $line) = @_;
432 # if ($self->{err_flag} != 0){
437 # if ($self->{parsing_index} >= scalar(@{$self->{param_table}->[0]})){
438 # #too many parameters...
439 # $self->{err_flag} = 1;
440 # $self->{parsing_result} = Bcd::Errors::ErrorCodes::BEC_TOO_MANY_PARAMETERS;
443 # #check the validity of the parameter... ?
444 # $self->{parsed_result}->{$self->{param_table}->[0]->[$self->{parsing_index}]} =
446 # $self->{parsing_index} ++;
450 push(@
{$self->{_args
}}, $line);
453 sub parse_input_blob
{
456 sub get_parsing_result
{
458 return $self->{parsing_result
};
461 sub get_parsed_result
{
463 return $self->{parsed_result
};
469 return $self->{parsed_result
};