#!/usr/bin/perl

###############################################################################
## Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
###############################################################################

use strict;
use warnings;
use FindBin;
BEGIN { unshift @INC, "$FindBin::Bin/../www/perl-lib" }

use SMT::CLI;
use SMT::Utils;
use SMT::SCCSync;
use File::Basename;
use File::Temp;
use Config::IniFiles;
use Locale::gettext ();
use POSIX ();     # Needed for setlocale()

POSIX::setlocale(&POSIX::LC_MESSAGES, "");

#
# FIXME: what about /root/.curlrc for proxy settings?
#
if(!SMT::Utils::dropPrivileges())
{
    print STDERR __("Unable to drop privileges. Abort!\n");
    exit 1;
}

my $mirrorable;
my $domirror;

my $debug   = 0;
my $vblevel  = LOG_ERROR|LOG_WARN|LOG_INFO1|LOG_INFO2;
my $logfile = "/dev/null";
my $help    = 0;
my $fromdir = "";
my $todir   = "";
my $createdbreplfile = "";
my $mail     = 0;
my $mailtempfile = undef;

my $exitcode = 0;

use Getopt::Long;
Getopt::Long::Configure( 'no_auto_abbrev');
my $optres = Getopt::Long::GetOptions(
                                      'fromdir=s'   => \$fromdir,
                                      'todir=s'     => \$todir,
                                      'createdbreplacementfile=s' => \$createdbreplfile,
                                      "logfile|L=s" => \$logfile,
                                      'debug|d'     => \$debug,
                                      "verboselevel|v=i" => \$vblevel,
                                      "mail|m"      => \$mail,
                                      'help|h'      => \$help
                                     );

if ( (defined $help && $help == 1 ) || !$optres )
{
    print basename($0) . " : " . __("Get data from SCC and update the local database.\n\n");
    print __("Usage:\n");
    print basename($0) . " [options]";
    print "\n\n";
    print __("Options:\n");
    print "--fromdir                 ".__("read SCC informations from directory instead of downloading it from SCC\n");
    print "                          ".__("and update the database.\n");
    print "--todir                   ".__("write SCC informations to directory without updating the database.\n");
    print "--createdbreplacementfile ".__("create a database replacement file for using smt-mirror without database.\n");
    print "--logfile -L file         ".__("Path to logfile\n");
    print "--debug                   ".__("Enable debug mode\n");
    print "--verboselevel -v level   ".__("set the verbose level\n");
    print "--mail -m                 ".__("Send output as e-mail to the administrators defined in reportEmail in smt.conf.\n");
    print "                          ".__("The output on stdout and stderr will be suppressed.\n");
  exit 0;
}

$vblevel = LOG_ERROR|LOG_WARN|LOG_INFO1|LOG_INFO2|LOG_DEBUG|LOG_DEBUG2 if($debug);

if($mail)
{
    my $dir = File::Temp::tempdir("smt-XXXXXXXX", CLEANUP => 1, TMPDIR => 1);
    $mailtempfile = "$dir/mail";
    open(MAILTEMPFILE, "> $mailtempfile") or die "Cannot open file:$!";
    open(STDOUT, ">& MAILTEMPFILE") or die "Cannot dup:$!";
    open(STDERR, ">& MAILTEMPFILE") or die "Cannot dup:$!";
    select STDERR; $| = 1;      # make unbuffered
    select STDOUT; $| = 1;      # make unbuffered
    select MAILTEMPFILE; $| = 1;        # make unbuffered
    $vblevel  = LOG_ERROR|LOG_WARN|LOG_INFO1 if(!$debug);
}

if($createdbreplfile ne "")
{
    SMT::CLI::createDBReplacementFile($createdbreplfile);
    exit 0;
}

if($fromdir ne "" && $todir ne "")
{
    # both options set == no option set
    $fromdir = "";
    $todir   = "";
}

if(!SMT::Utils::openLock("smt-sync"))
{
    print __("Syncronization process is still running.\n");
    exit 0;
}

# open the logfile

my $LOG = SMT::Utils::openLog($logfile);

my $cfg = undef;
eval
{
    $cfg = SMT::Utils::getSMTConfig();
};
if($@ || !defined $cfg)
{
    SMT::Utils::printLog($LOG, $vblevel, LOG_ERROR, sprintf(__("Cannot read the SMT configuration file: %s"), $@));
    SMT::Utils::unLockAndExit( "smt-sync", 1, $LOG, $vblevel);
}

if ( $cfg->val('NU', 'ApiType', 'NCC') ne 'SCC')
{
    SMT::Utils::printLog($LOG, $vblevel, LOG_ERROR, "Not connected to SCC");
    SMT::Utils::unLockAndExit( "smt-sync", 1, $LOG, $vblevel);
}

if($fromdir ne "" && $fromdir !~ /^\//)
{
    $fromdir = SMT::Utils::cleanPath($ENV{'PWD'}, $fromdir);
}

if($todir ne "" && $todir !~ /^\//)
{
    $todir = SMT::Utils::cleanPath($ENV{'PWD'}, $todir);
}

if($fromdir ne "" && ! -d $fromdir)
{
    SMT::Utils::printLog($LOG, $vblevel, LOG_ERROR, sprintf(__("Directory '%s' does not exist."), $fromdir));
    SMT::Utils::unLockAndExit( "smt-sync", 1, $LOG, $vblevel);
}

if($todir ne "" && ! -d $todir)
{
    # directory does not exists, try to create it.
    eval {
        &File::Path::mkpath($todir);
    };
    if ($@)
    {
        SMT::Utils::printLog($LOG, $vblevel, LOG_ERROR, sprintf(__("Cannot create %s: %s"), $todir, $@));
        SMT::Utils::unLockAndExit( "smt-sync", 1, $LOG, $vblevel);
    }
}

if($fromdir ne "")
{
    printLog($LOG, $vblevel, LOG_INFO1, sprintf(__("Read from directory: %s"), $fromdir));
}
if($todir ne "")
{
    printLog($LOG, $vblevel, LOG_INFO1, sprintf(__("Write to directory: %s"), $todir));
}

eval
{
    my $sccsync = SMT::SCCSync->new(vblevel => $vblevel,
                                    log     => $LOG,
                                    cfg     => $cfg,
                                    fromdir => (($fromdir ne "")?$fromdir:undef),
                                    todir   => (($todir ne "")?$todir:undef));
    printLog($LOG, $vblevel, LOG_INFO1, __("Downloading Product and Repository information"));
    my $res = $sccsync->products();
    if ($res)
    {
        SMT::Utils::printLog($LOG, $vblevel, LOG_ERROR, __("Error while fetching Product and Repository data."));
        $exitcode = 1;
    }
    printLog($LOG, $vblevel, LOG_INFO1, __("Downloading Subscription information"));
    $res = $sccsync->subscriptions();
    if ($res)
    {
        SMT::Utils::printLog($LOG, $vblevel, LOG_ERROR, __("Error while fetching Subscriptions data."));
        $exitcode = 1;
    }

    printLog($LOG, $vblevel, LOG_INFO1, __("Downloading Order information"));
    $res = $sccsync->orders();
    if ($res)
    {
        SMT::Utils::printLog($LOG, $vblevel, LOG_ERROR, __("Error while fetching Order data."));
        $exitcode = 1;
    }

    printLog($LOG, $vblevel, LOG_INFO1, __("Flagging repositories which can be mirrored"));
    SMT::CLI::setMirrorableCatalogs(log     => $LOG,
                                    vblevel => $vblevel,
                                    fromdir => (($fromdir ne "")?$fromdir:undef),
                                    todir   => (($todir ne "")?$todir:undef));
    if ($res)
    {
        SMT::Utils::printLog($LOG, $vblevel, LOG_ERROR, sprintf(__("%d Error(s) during sync."), $res));
        $exitcode = 1;
    }

    if( $fromdir ne "" && -d $fromdir )
    {
        my $mirrorinfofile = $fromdir."/mirrorinfo.xml";
        if ( -f $mirrorinfofile && (stat($fromdir."/catalogs.xml"))[9] <= (stat($mirrorinfofile))[9] )
        {
            SMT::Utils::printLog($LOG, $vblevel, LOG_ERROR, __("Updating mirror flags from $mirrorinfofile."));
            SMT::CLI::setDoMirrorFromXml( xml => $mirrorinfofile );
        }
    }

};
if ($@)
{
    SMT::Utils::printLog($LOG, $vblevel, LOG_ERROR, $@);
    $exitcode = 1;
}

if($mail)
{
    close (STDERR);
    close (STDOUT);
    close (MAILTEMPFILE);
    my $body = "";

    open(MAIL, "< $mailtempfile") and do
    {
        while(<MAIL>)
        {
            $body .= $_;
        }
        close MAIL;
    };
    my $datestring = POSIX::strftime("%Y-%m-%d %H:%M", localtime);
    my $subject = sprintf("SMT Sync Report $datestring (%s) -- Sync %s",
                          SMT::Utils::getFQDN(), (($exitcode > 0)?"failed":"successful"));

    SMT::Utils::sendMailToAdmins($subject, $body);
}
print "\n";
SMT::Utils::unLockAndExit("smt-sync", $exitcode, $LOG, $vblevel);



#
# Manpage
#

=head1 NAME

smt scc-sync -

=head1 SYNOPSIS

smt scc-sync [options]

=head1 DESCRIPTION

C<smt scc-sync> gets data from SUSE Customer Center and updates the local database.

=head1 OPTIONS

=head2 COMMANDLINE

=over

=item --fromdir directory

Reads SCC information from directory instead of downloading it from SCC and update the database.

=item --todir directory

Write SCC informations to directory without updating the database.

=item --createdbreplacementfile

Creates a database replacement file for using smt-mirror without database.

=item --logfile -L file

Path to logfile.

=item --debug

Enable display of debug information.

=item --verboselevel -v <level>

Set the output verbose level. The following categories exists.
These categories can be bitwise-or'd to use as verbose level.

=over 4

=item error messages

Value: 0x0001 == 1

=item warning messages

Value: 0x0002 == 2

=item info messages 1

Value: 0x0004 == 4

=item info messages 2

Value: 0x0008 == 8

=item debug messages 1

Value: 0x0010 == 16

=item debug messages 2

Value: 0x0020 == 32

=item debug messages 3

Value: 0x0040 == 64

=back

The default verbose level is 15 (error, warning and all info messages).
B<--debug> set the verbose level to 63.

=item --mail -m

Send output as e-mail to the administrators defined in reportEmail in smt.conf .
The output on stdout and stderr will be suppressed in this mode.

=back

=head1 AUTHORS and CONTRIBUTORS

Duncan Mac-Vicar Prett, Jens Daniel Schmidt, Michael Calmer

=head1 LICENSE

Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.

This program 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 of the License, 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, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.

=cut
