#!/usr/bin/perl

use warnings;
use strict;
use POSIX;
use Getopt::Long qw(:config pass_through);
use Pod::Usage;
use constant booleanOptions => qr/^(?:json)$/;

our $opt_user  = '__APACHEUSER__';
our $opt_group = '__APACHEGROUP__';
our $opt_json;
GetOptions(
    "user=s"  => \$opt_user,
    "group=s" => \$opt_group,
) or pod2usage("Error in command line arguments");

my $action;

eval {
    POSIX::setgid( scalar( getgrnam($opt_group) ) ) if getgrnam($opt_group);
    POSIX::setuid( scalar( getpwnam($opt_user) ) )  if getpwnam($opt_user);
    my ( undef, undef, undef, undef, undef, undef, undef, $homedir, undef ) =
      getpwnam($opt_user);
    $ENV{HOME} = $homedir if $homedir;
};

for ( my $i = 0 ; $i < @ARGV ; $i++ ) {
    my $arg = $ARGV[$i];
    if ( $arg =~ s/^-+// ) {
        $i++ unless $arg =~ booleanOptions;
        next;
    }
    $action = $ARGV[$i];
    last;
}

$action ||= "usage";

if ( $action =~
/^(?:[gs]et|del|(?:add|del)Key|(?:add|del)PostVars|merge|save|restore|rollback|purge)$/
  )
{
    eval { require Lemonldap::NG::Manager::Cli; };
    die "Manager libraries not available, aborting ($@)" if ($@);
    Lemonldap::NG::Manager::Cli->run(@ARGV);
}
elsif ( $action =~ /^(?:info|update-cache|test-email)$/ ) {
    eval { require Lemonldap::NG::Common::Cli; };
    die "Lemonldap::NG common libraries not available, aborting ($@)" if ($@);
    Lemonldap::NG::Common::Cli->run(@ARGV);
}
else {
    pod2usage(1) if $action eq "help";
    pod2usage(2) if $action eq "usage";
    pod2usage( -exitval => 2, -message => "Unknown action: $action" );
}

__END__

=head1 NAME

=encoding utf8

lemonldap-ng-cli - Command-line manager for Lemonldap::NG web-SSO system.

=head1 DESCRIPTION

lemonldap-ng-cli is a command line interface to interact with Lemonldap::NG
configuration. It can be used to read or update configuration variables
programmatically, or perform global operations on the configuration.

=head1 SYNOPSIS

Usage: lemonldap-ng-cli [options] ACTION [parameters ...]

Available actions:

 help                            : print the full documentation
 info                            : get currentconfiguration info
 update-cache                    : force configuration cache to be updated
 test-email DESTINATION          : send a test email
 get KEY                         : get values of parameters
 set KEY VALUE                   : set parameter(s) value(s)
 del KEY                         : delete parameters
 addKey KEY SUBKEY VALUE         : add or set a subkey in a parameter
 delKey KEY SUBKEY               : delete subkey of a parameter
 addPostVars HOST URI KEY VALUE  : add post vars for form replay
 delPostVars HOST URI KEY        : delete post vars for form replay
 merge FILE [FILE ...]           : merge JSON/YAML files with existing configuration
 purge [PURGE OPTIONS]           : delete old configurations
 save                            : export configuration to STDOUT
 restore -                       : import configuration from STDIN
 restore FILE                    : import configuration from file
 rollback                        : restore previous configuration

Options:

 -yes 0|1                     : accept confirmation prompt automatically
 -log msg                     : set configuration log message
 -safe 1|0                    : fail in case the requested configuration is invalid (default)
 -unsafe 0|1                  : don't fail in case the requested configuration is invalid
 -force 0|1                   : allow overwrite of existing config number
 -cfgNum NUM                  : set new configuration number (requires -force 1)
 -sep CHAR                    : separator of hierarchical values (by default: /)
 -iniFile FILE                : path to an alternate lemonldap-ng.ini file
 -json                        : print result in JSON format

Additional options:

 --user=USER    : change user running the script
 --group=GROUP  : change group running the script

=head1 EXAMPLES

Get information about current configuration

  $ lemonldap-ng-cli info

Update local configuration cache

  $ lemonldap-ng-cli update-cache

Send a test email

  $ lemonldap-ng-cli test-email dwho@badwolf.org

Save configuration

  $ lemonldap-ng-cli save >conf.json
  $ lemonldap-ng-cli -cfgNum 19 save >conf-19.json

Restore configuration

  $ lemonldap-ng-cli restore conf.json
  # OR
  $ lemonldap-ng-cli restore - <conf.json

Cancel the last configuration change

  $ lemonldap-ng-cli rollback

Get a configuration parameter value

  $ lemonldap-ng-cli get portal domain cookieName

Set some values

  $ lemonldap-ng-cli set portal http://auth.e.com/ domain e.com
  # add or set a key
  $ lemonldap-ng-cli addKey macro fullname '$givenName." ".$lastName'

  # without changing the version number
  $ lemonldap-ng-cli -force 1 -cfgNum 1 set portal http://auth.e.com/ domain e.com

  # without asking for confirmation
  $ lemonldap-ng-cli -yes 1 set portal http://auth.e.com/ domain e.com


=head1 ARGUMENTS

=over

=item B<info>

Print configuration metadata, such as number, author, date and log

=item B<update-cache>

Update the local configuration cache, this command only affects the server on which it is run

=item B<test-email I<DESTINATION>>

Sends a test email to the specified I<DESTINATION>, this lets you check your SMTP settings

=item B<get I<KEY> [ I<KEY> ... ]>

Print the specified I<KEY> from configuration. Multiple keys may be given

=item B<set I<KEY> I<VALUE> [I<KEY> I<VALUE> ...]>

Set the specified I<KEY> to the specified I<VALUE>. Multiple key-value pairs may be given.

The configuration number is increased once all given key-value pairs have been processesed.

=item B<delete I<KEY> [ I<KEY> ... ]>

Delete the specified I<KEY> from configuration. Multiple keys can be given.

The configuration number is increased once all keys have been deleted.

=item B<addKey I<KEY> I<SUBKEY> I<VALUE> [I<KEY> I<SUBKEY> I<VALUE> ...]>

This action can be used to set a sub-key inside a composite configuration key
(such as globalStorageOptions, locationRules, etc.)

Multiple key-subkey-value triplets may be given.

The configuration number is increased once all given triplets have been processesed.

=item B<delKey I<KEY> I<SUBKEY> [I<KEY> I<SUBKEY> ...]>

This action can be used to delete a sub-key from a composite configuration key
(such as globalStorageOptions, locationRules, etc.)

Multiple key-subkey pairs may be given.

The configuration number is increased once all given pairs have been processesed.

=item B<addPostVars I<HOST> I<URI> I<KEY> I<VALUE>>

This action lets you add a new POST var in a form replay configuration.

=item B<delPostVars I<HOST> I<URI> I<KEY>>

This action lets you delete a new POST var in a form replay configuration.

=item B<merge I<FILE> [I<FILE> ...]>

This action iterates through the given JSON or YAML files and merges the
existing configuration with the keys contained in those files

=item B<save>

Dump the entire LemonLDAP::NG configuration to standard output, in JSON format.

The resulting dump can be imported into the manager's interface, or restored
with the B<restore> command.

=item B<restore I<FILE>>

Replace the existing configuration with the content of the provided
JSON-formatted I<FILE>. If I<FILE> is the I<-> string, configuration will be
read from standard input.

=item B<rollback>

This command can be used to cancel the latest configuration change. The
previous configuration is fetched from configuration history and saved under a
new configuration number.

This action is meant to be a convenient wrapper around B<save> and B<restore>,
and does not handle rolling back to an arbitrary version. Rolling back to an
arbitrary version can be done manually with B<save> and B<restore>

=back

=head1 OPTIONS

=over

=item B<-yes I<0|1>>

Skip confirmation prompt (default: 0)

=item B<-log I<MESSAGE>>

Allows you to set the log message that will be displayed in the manager

=item B<--safe>, B<-unsafe> I<(0|1)>

With B<--unsafe> the configuration change will be stored even if it contains
errors. By default I<(B<--safe>)>, invalid configuration are rejected.

=item B<-force I<0|1>>

Allows you to force overwriting an existing configuration number (default: 0)

=item B<-cfgNum I<NUMBER>>

Choose a particular configuration number (default: latest)

=item B<-sep I<CHARACTER>>

Allows you to define hierarchical separator

=item B<-iniFile I<FILE>>

Allows you to set an alternative ini file

=item B<-u I<USER>, --user=I<USER>>

Run the script under the I<USER> system user identity

=item B<-g I<GROUP>, --group=I<GROUP>>

Run the script under the I<GROUP> system group identity

=item B<-json>

Display result in JSON format

=back

=head1 SEE ALSO

L<Lemonldap::NG::Manager::Cli>, L<Lemonldap::NG::Common::Cli>
L<http://lemonldap-ng.org/>

=head1 AUTHORS

=over

=item Clement Oudot, E<lt>clement@oodo.netE<gt>

=item Xavier Guimard, E<lt>yadd@debian.orgE<gt>

=item Maxime Besson, E<lt>maxime.besson@worteks.comE<gt>

=item Christophe Maudoux, E<lt>chrmdx@gmail.comE<gt>

=back

=head1 BUG REPORT

Use OW2 system to report bug or ask for features:
L<https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/issues>

=head1 DOWNLOAD

Lemonldap::NG is available at
L<https://release.ow2.org/lemonldap/>

=head1 COPYRIGHT AND LICENSE

=over

=item Copyright (C) 2016 by Xavier Guimard, E<lt>x.guimard@free.frE<gt>

=item Copyright (C) 2016 by Clément Oudot, E<lt>clem.oudot@gmail.comE<gt>

=back

This library 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 2, or (at your option)
any later version.

This program 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 this program.  If not, see L<http://www.gnu.org/licenses/>.

=cut
