#!/usr/bin/perl

# This is a program that aggregates and outputs network traffic
# information (usually as a graph).

# Copyright 2009 Corey Hickey


# This file is part of Captrap.
#
# Captrap is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Captrap is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Captrap.  If not, see <http://www.gnu.org/licenses/>.


=head1 NAME

captrap_graph - a command-line program for generating Captrap graphs

=head1 SYNOPSIS

captrap_graph [OPTION] [OPTION-PARAMETERS]

=head1 DESCRIPTION

This program will generate a single graph from Captrap's database, and is
primarily useful for testing. For general use, captrap_recurse or Captrap's CGI
programs may be better suited.

=head1 OPTIONS

=over

=item -help

Print brief usage text.

=item -list-parameters

Print a list of valid parameters.

=item -write FILE PARAMETERS

Write a graph to a file, unless the file already exists. To write to stdout,
specify the file as '-' (if you really want to create a file named '-', specify
'./-'). The filename must be followed by a list of parameters in the usual URL
form (as in param1=value1&param2=value2). Be sure to surround the parameters
with single-quotes if necessary, to avoid having the shell interpret the
ampersands.

=back

=head1 EXIT STATUS

=over

=item 0Z<>

Everything is ok.

=item 1Z<>

No arguments given; usage information was shown.

=item 2Z<>

Invalid argument.

=item 3Z<>

There was a problem executing an action.

=back

=head1 FILES

=over

=item /etc/captrap/captrap.conf

The main Captrap configuration file.

=back

=head1 EXAMPLES

=over

=item Write a monthly graph to a file:

captrap_graph -write monthly.png 
'graph=per&per=month&start=2008-08-01T00:00:00&end=2009-08-01T00:00:00'

=item Display an hourly graph (requires 'display' from imagemagick):

captrap_graph -write -
'graph=per&per=hour&start=2009-08-12T00:00:00&end=2009-08-13T00:00:00'

=back

=head1 AUTHOR

Corey Hickey <bugfood-c@fatooh.org>

This program is free software; you may redistribute and/or modify it under the
terms of the GNU General Public License, version 3. See the source file for the
usual GPL preamble and the COPYING file for a copy of the GPL.

=head1 SEE ALSO

captrap_view, captrap_main, captrap_recurse

The documentation included in the Captrap source archive has more information
on setup and general usage.

=cut


use strict;
use warnings FATAL => 'all';

# for development using a different Captrap module
use lib "lib";
use Captrap qw(:cgi :misc :actions :args :config :db);
use Captrap::Graph qw(:graph :param);

# -----------------------------------------------------------------------------
# printing
# -----------------------------------------------------------------------------

# print main help info
sub usage {
  my $common = shift; # unused
  my $actions = mk_actions();
  my $actions_text = describe_actions($actions);
  print "
This is a script for generating Captrap graphs. For full usage information, see
the man page and/or documentation provided in the Captrap source archive.

captrap_graph [ACTION] [[ACTION-PARAMETERS]] ...

ACTIONS

$actions_text
"

}


# list all parameters
sub list_params {
  my $common = shift;
  my $param_info = mk_param_info($common->{config});
  arg_list_params($param_info);
}
 

# -----------------------------------------------------------------------------
# graph writing
# -----------------------------------------------------------------------------

# open a file and write a graph to it
sub do_write {
  my $common = shift;
  my $file = shift;
  my $params = shift;
  my $param_info = mk_param_info($common->{config});
  arg_handle_params($common, $param_info, \&arg_mk_graph, $params, $file);
  # If we get here, it worked; otherwise, we've already exited.
  # So, return 0 to signify an action that ran ok.
  return 0;
}


# use provided cgi parameters to call the graphing subroutine
sub arg_mk_graph {
  my $common = shift; # hash ref
  my $params = shift; # hash ref
  my $file = shift;
  # do some additional parameter validation
  my $err = params_ok($common, $params);
  if (@$err) {
    # problems!
    arg_print_errors($common, $err);
    return undef;
  }
  return write_output_to_file($common, $params, $file, \&mk_graph, undef);
}

# print errors found by params_ok();
sub arg_print_errors {
  my $common = shift; # hash ref
  my $err = shift; # array ref
  my $config = $common->{config};
  print STDERR "Sorry--your parameters parsed ok, but they cannot be used:\n\n";
  foreach my $item (@$err) {
    print STDERR "$item\n\n";
  }
}


# -----------------------------------------------------------------------------
# actions info
# -----------------------------------------------------------------------------

# return a hash of action info
sub mk_actions {
  my $actions = mk_ixhash();
  %$actions = (
    "-help" => {
      func => \&usage,
      args => [],
      desc => "
          Print this usage text.
      ",
    },
    "-list-parameters" => {
      func => \&list_params,
      args => [],
      desc => "
          Print a list of valid parameters.
      ",
    },
    "-write" => {
      func => \&do_write,
      args => [ qw(FILE PARAMETERS) ],
      desc => "
          Write a graph to a file, unless the file already exists.
      ",
    }
  );
  return $actions;
}

# ----------------------------------------------------------------------------
# parse the arguments and take actions
if (! @ARGV) {
  usage();
  exit(1);
}
my $actions = mk_actions();
check_args(\@ARGV, $actions);

my $config = parse_config();
my $common = {
  cgi    => mk_cgi(),
  config => $config,
  dbh    => mk_dbh($config),
};

do_args($common, \@ARGV, $actions);

$common->{dbh}->disconnect();
exit(0);
