#!/usr/bin/perl

use strict;
use warnings;
use Getopt::Long;
use Pod::Usage;
use Config::IniFiles;
use LATMOS::Accounts;
use LATMOS::Accounts::SyncManager;
use LATMOS::Accounts::Log;
use LATMOS::Accounts::Task;

=head1 NAME

    la-sync-manager - Daemon performing synchronisation and various tasks

=head1 SYNOPSIS

    la-sync-manager [options...]

=cut

GetOptions(
    'nodaemon' => \my $nodaemon,
    'c|config=s'   => \my $config,
    'help'         => sub { pod2usage(0) },
    'wait=i'       => \my $wait,
) or pod2usage();

=head1 OPTIONS

=over 4

=item --nodaemon

Don't go into background

=item -c|--config configdir

Use this configuration instead default one

=item --help

Display this help

=item --wait minutes

Wait this number of minutes before process synchronisation (default is 5
minutes)

=back

=head1 CONFIUGRATION

=head2 CONFIGURATION FILE

See L<la-sync-manager.ini>

=head2 AVAILABLE TASK MODULE

=head3 L<LATMOS::Accounts::Task::Basessynchro>

This module is always laod and run. It synchronize base given in
L<latmos-accounts.ini>

=head3 L<LATMOS::Accounts::Task::Dummy>

A fake module for testing

=head3 L<LATMOS::Accounts::Task::Buildlistes>

This use L<la-sync-list.ini> config file to build mailing list file
typically usuable by C<sync_members> mailman program.

=head3 L<LATMOS::Accounts::Task::Buildnet>

Generate DNS and DHCP files from C<netzone> objects

=head3 L<LATMOS::Accounts::Task::Employment>

This module update user's information according the status matching current
date.

=head3 L<LATMOS::Accounts::Task::Refreshexpired>

Increasing revision number for user to force update in othere base not supporting
properly expiration date.

=head3 L<LATMOS::Accounts::Task::Updatedyndata>

Force automatic object (such as group with filter) to be rebuilt in case it depend
on external base event like date.

=head3 L<LATMOS::Accounts::Task::Delexpiredusers>

Make user's account unexported after expiration delay.

=head3 L<LATMOS::Accounts::Task::Expiredaliases>

Allow to automatically add an alias to user when account get expired.
The basis idea is to redirect mail to an automatic responder claiming account is
expired.

=head3 L<LATMOS::Accounts::Task::Stats>

Collect current data according C<Stat> objects definition.

=head3 L<LATMOS::Accounts::Task::Unexportexpired>

For C<Aliases> and <Nethost>, unexport object when expiration date is reached.

=head3 L<LATMOS::Accounts::Task::Unusedhosts>

Unexport C<Nethost> when owner/user is expired or unexported

=head3 L<LATMOS::Accounts::Task::Iprecover>

Delete IP set on nethost unexported and not midified for the specified delay.

=cut

my $needsync = 0;
my $pidfile = undef;
$wait ||= 5; # default in minutes

my $syncm = LATMOS::Accounts::SyncManager->new($config) or do {
    la_log LA_ERR, "Cannot instanciate Sync Manager";
    exit(1);
};

la_set_log(
    syslog => [],
    console => ($nodaemon ? LA_NOTICE : undef),
);

# Trap perl message, send it to log
$SIG{__DIE__} = sub {
    la_log LA_ERR, "Die: %s", $_[0] unless($_[0] =~ /^Can't locate/);
    die $_[0];
};
$SIG{__WARN__} = sub {
    la_log LA_WARN, "Warn: %s", $_[0];
    warn $_[0];
};

{
    my $LA = LATMOS::Accounts->new($config, noacl => 1);
    if ($LA->val('_default_', 'state_dir')) {
        $pidfile = $LA->val('_default_', 'state_dir') . '/sync-manager.pid';
    }
    if (my $mail = $LA->val('_network_', 'maillog')) {
            la_set_log(mail => $mail);
    }
}

# Daemonize
if (!$nodaemon) {
    my $pid = fork;
    if ($pid) {
        exit 0;
    }
}

if ($pidfile) {
    # maybe we want to lock here !!
    open(my $fh, '>', $pidfile) or die "Cannot open pidfile $pidfile\n";
    print $fh "$$\n";
    close($fh);
}

$SIG{INT} = sub {
    unlink($pidfile) if ($pidfile);
    exit 0;
};

$SIG{'HUP'} = sub {
    $needsync = 1;
    la_log LA_NOTICE, "SigHup received, synchronise now";
};

sub process {
    
    la_log LA_NOTICE, "Start processing modules";
    my $pid = fork();
    
    if ($pid == 0) {
        $SIG{INT} = 'DEFAULT';
        my $res = 0;
        foreach my $module ($syncm->listSortedModules()) {
            $res = 1 if (!$syncm->process_module($module));
        }
        exit($res);
    }

    my $retpid;
    while(($retpid = waitpid(-1, 0)) <= 0) {}
    local $SIG{HUP} = 'IGNORE';
    if ($retpid) {
        my $res = $? >> 8;
        if ($res) {
            la_log LA_ERR, "Sync process exit with $res";
            return;
        }
    }
    la_log LA_NOTICE, "End processing modules";
    return 1;
}

while (1) {
    $needsync = 0;

    process(); 

    # waiting, to perform next sync
    if ($needsync) {
        la_log(LA_DEBUG, "NeedSync received");
        next;
    }

    la_log(LA_DEBUG, "Sleeping $wait minutes");
    sleep($wait * 60);

}

__END__

=head1 SEE ALSO

L<la-sync-manager.ini>, L<latmos-accounts.ini>

=head1 AUTHOR

Olivier Thauvin, E<lt>olivier.thauvin@latmos.ipsl.frE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2008, 2009, 2010, 2011, 2012 CNRS SA/CETP/LATMOS

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.

=cut
