#!/usr/bin/perl
#
# ID synchronization command
#
# Copyright(c) SECIOSS CORPORATION 2010
#

use strict;
use lib '../lib/perl';
use LISM;
use XML::Simple;
use Net::LDAP::Util qw(ldap_error_desc);
use Net::LDAP::Constant qw(:all);
use DBI;
use DBD::SQLite;
use POSIX;
use Getopt::Std;
use Data::Dumper;

our $BASEDIR = '/opt/secioss';
our $CONFDIR = "$BASEDIR/etc";
our $BASEDN = 'o=secioss';
our $PASSWD = 'secioss';
our $SYNCDIR = "$BASEDIR/var/lib/ldap";
our $DBFILE = "$BASEDIR/var/lib/ldap/user.db";
our $STATUSFILE = "$SYNCDIR/status";

sub updatesync
{
    my ($lism, $type, $syncfilter) = @_;
    my @modinfo;
    my $rdn;

    if ($type eq 'master') {
        $rdn = 'cn=master-sync';
    } else {
        $rdn = 'cn=cluster-sync';
    }

    push(@modinfo, 'REPLACE', 'lismSyncStatus', 'sync');
    if ($syncfilter) {
        push(@modinfo, 'REPLACE', 'lismSyncFilter', $syncfilter);
    }

    my $rc = $lism->modify("$rdn,$BASEDN", @modinfo);
    if ($rc) {
        print STDERR ldap_error_desc($rc)."($rc)\n";
    }

    return $rc;
}

sub factory
{
    my ($conf) = @_;

    my $lism = new LISM;
    $lism->config('basedn', $BASEDN);
    $lism->config('admindn', "cn=Idsync,$BASEDN");
    $lism->config('adminpw', $PASSWD);
    $lism->config('syncdir', $SYNCDIR);
    $lism->config('conf', $conf);
    if ($^O eq 'MSWin32') {
        $lism->config('logfile', "/opt/secioss/var/log/lism.log");
    }

    return $lism;
}

sub usage
{
    print STDERR "Usage: idsync idp|sp\n";
    exit 1;
}

my %opt;
getopts("n", \%opt);

if (@ARGV < 1) {
    usage();
}

my $list = "$BASEDIR/var/lib/csv/user.csv";
my $type = $ARGV[0];
if ($type ne 'idp' && $type ne 'sp') {
    usage();
}
my $rc = 0;

if ($type eq 'sp' && -f $list) {
    print STDERR "Delete $list\n";
    unlink($list);
}

my $lism = factory("$CONFDIR/lism-$type.conf");
$rc = $lism->init();
if ($rc) {
    print STDERR "Bad configuration\n";
    exit 1;
}
$lism->bind("cn=Idsync,$BASEDN", $PASSWD);

if ($type eq 'idp') {
    if (!-f $DBFILE) {
        my $dbh = DBI->connect("DBI:SQLite:dbname=$DBFILE");
        $dbh->do("create table user (uid, empnum, cn, sn, givenname, jacn, jasn, jagivenname, encn, ensn, engivenname, mail, language, status)");
        $dbh->disconnect();
    }

    $rc = updatesync($lism, 'master');
    if ($rc) {
        print STDERR "Can't get updated entries\n";
        exit 1;
    }
} else {
    my $prevtime;
    if (-f $STATUSFILE) {
        if (!open(STATUS, "<$STATUSFILE")) {
            print STDERR "Can't open status file\n";
            exit 1;
        }
        $prevtime = <STATUS>;
        $prevtime =~ s/\n//;
        close(STATUS);
    }
    if (!$prevtime) {
        $prevtime = '19700101000000';
    }

    my $ctime = strftime("%Y%m%d%H%M%S", localtime(time));
    $rc = updatesync($lism, 'master', '(seciossPersonModifyTime>='.$prevtime.'Z)');
    if ($rc) {
        print STDERR "Can't get updated entries\n";
        exit 1;
    }

    if (!-f $list) {
        print STDERR "$list doesn't exist\n";
        exit 1;
    }

    if (defined($opt{n})) {
        print "Updated user list is created\n";
        exit 0;
    }

    my $conf = XMLin("$CONFDIR/lism-sp.conf", ForceArray => 1);
    my $appconf = XMLin("$CONFDIR/lism.conf", ForceArray => 1);
    foreach my $key (keys %{$appconf->{sync}[0]->{data}}) {
        $conf->{sync}[0]->{data}{$key} = $appconf->{sync}[0]->{data}{$key};
    }
    foreach my $key (keys %{$appconf->{data}}) {
        $conf->{data}{$key} = $appconf->{data}{$key};
    }

    my $fh;
    open($fh, ">$CONFDIR/lism-all.conf");
    XMLout($conf, RootName => 'config', OutputFile => $fh);
    close $fh;

    $lism = factory("$CONFDIR/lism-all.conf");
    $rc = $lism->init();
    if ($rc) {
        print STDERR "Bad configuration\n";
        exit 1;
    }
    $lism->bind("cn=Idsync,$BASEDN", $PASSWD);

    if (!open(LIST, "<$list")) {
        print STDERR "Can't read $list\n";
        exit 1;
    }
    while (<LIST>) {
        my ($user) = split(/, */);
        $rc = updatesync($lism, 'cluster', "(uid=$user)");
        if ($rc) {
            print STDERR "Synchronization of $user failed\n";
            last;
        } else {
            print "Synchronization of $user succeded\n";
        }
    }
    close(LIST);
    unlink($list);

    if (!$rc) {
        if (!open(STATUS, ">$STATUSFILE")) {
            print STDERR "Can't open status file\n";
            exit 1;
        }
        print STATUS "$ctime";
        close(STATUS);
    }
}

exit ($rc);
