1#!/usr/bin/perl
2#
3# odlaw - the waldo file viewer and manipulator
4#
5
6use strict;
7use warnings;
8#use 5.010;
9
10#
11# PERL INCLUDES
12#
13use Data::Dumper;
14use Getopt::Long;
15
16use constant { MAX_FILEPATH_BUF => 1024 };
17
18my $options = {
19    file_read => '',
20    file_edit => '',
21    help => 0,
22    spooler_dir => '',
23    spooler_filebase => '',
24    record => 0,
25    timestamp => 0,
26    verbose => 0,
27    force => 0,
28};
29
30
31#
32#
33#
34sub usage
35{
36    print "\n";
37    print "USAGE: $0 [-options]\n";
38    print "\n";
39    print " General Options:\n";
40    print "  -h            You're reading it.\n";
41    print "  -v            Verbose output.\n";
42    print "  -f            Force (skip validation).\n";
43    print "  -r <file>     File to read.\n";
44    print "  -e <file>     File to edit.\n";
45    print "\n";
46    print " Long Options:\n";
47    print "  --help        Same as '?'\n";
48    print "  --verbose     Same as 'v'\n";
49    print "  --force       Same as 'f'\n";
50    print "  --read        Same as 'r'\n";
51    print "  --edit        Same as 'e'\n";
52    print "  --filebase    Filebase to filter files on.\n";
53    print "  --directory   Directory to spool for files.\n";
54    print "  --timestamp   Timestamp of file being processed (default: 0).\n";
55    print "  --record      Record index of file being processed (default: 0).\n";
56    print "\n";
57}
58
59sub waldo_read
60{
61    my ($file) = @_;
62
63    my @fields = ('spooler_dir', 'spooler_filebase', 'timestamp', 'record');
64    my %values;
65    @values{@fields} = ('', '', 0, 0);
66
67    # read the data
68    if ( open (FD, "<$file") )
69    {
70        my $waldo_raw = <FD>;
71        # unpack
72        @values{@fields} = unpack("Z[".MAX_FILEPATH_BUF."] Z[".MAX_FILEPATH_BUF."] L L", $waldo_raw);
73
74        close(FD);
75    }
76
77    # return as hash reference
78    return \%values;
79}
80
81sub waldo_validate
82{
83    my ($data) = @_;
84
85    return ( $options->{force} || (
86               defined($data->{spooler_dir}) && ( -e $data->{spooler_dir} ) &&
87               defined($data->{spooler_filebase}) &&
88               defined($data->{timestamp}) &&
89               defined($data->{record})
90             )
91           );
92}
93
94sub waldo_print
95{
96    my ($data) = @_;
97
98    print "{\n";
99    print "  directory = " . $data->{spooler_dir} . "\n";
100    print "  filebase  = " . $data->{spooler_filebase} . "\n";
101    print "  timestamp = " . $data->{timestamp} . "\n";
102    print "  record    = " . $data->{record} . "\n";
103    print "}\n";
104}
105
106sub waldo_write
107{
108    my ($file, $data) = @_;
109
110    # validate input
111    if ( ! waldo_validate($data) )
112    {
113        print "[!] Provided waldo data is incomplete or corrupted.";
114        return;
115    }
116
117    # open and write
118    open (FD, ">$file") or die ('Unable to read file');
119
120    my $packed = pack("Z[".MAX_FILEPATH_BUF."] Z[".MAX_FILEPATH_BUF."] L L", $data->{spooler_dir}, $data->{spooler_filebase}, $data->{timestamp}, $data->{record});
121    print FD $packed;
122
123    close(FD);
124}
125
126
127#
128# MAIN
129#
130my $res = GetOptions(
131    'r|read=s'    => \$options->{file_read},
132    'e|edit=s'    => \$options->{file_edit},
133    'directory=s' => \$options->{spooler_dir},
134    'filebase=s'  => \$options->{spooler_filebase},
135    'record=s'    => \$options->{record},
136    'timestamp=s' => \$options->{timestamp},
137    'v|verbose'   => \$options->{verbose},
138    'f|force'     => \$options->{force},
139    'help|?'      => \$options->{help},
140);
141
142if( $options->{help} > 0 )
143{
144    usage();
145    exit(0);
146}
147elsif( $options->{file_read} )
148{
149    my $data = waldo_read($options->{file_read});
150    print 'waldo: ' . $options->{file_read} . "\n";
151    waldo_print($data);
152
153    if ( ! waldo_validate($data) )
154    {
155        print "[!] Read waldo data is incomplete or corrupted.\n";
156    }
157}
158elsif( $options->{file_edit} )
159{
160    my $data = waldo_read($options->{file_edit});
161
162    $data->{spooler_dir} = defined($options->{spooler_dir}) ? $options->{spooler_dir} : $data->{spooler_dir};
163    $data->{spooler_filebase} = defined($options->{spooler_filebase}) ? $options->{spooler_filebase} : $data->{spooler_filebase};
164    $data->{timestamp} = (defined($options->{timestamp}) ? $options->{timestamp} : $data->{timestamp}) + 0;
165    $data->{record} = (defined($options->{record}) ? $options->{record} : $data->{record}) + 0;
166
167    print "Preparing to write:\n";
168    waldo_print($data);
169
170    waldo_write($options->{file_edit}, $data);
171}
172else
173{
174    usage();
175    exit(1);
176}
177
178