#!/usr/bin/perl -w
#==============================================================================
# lat-dump
# ========
# 0.9.0 (2004-09-08)
# (c)2003-2004 Altiplano bvba
#==============================================================================
package esmith;
use strict;
use esmith::config;
use esmith::db;
use esmith::util;
use Getopt::Long;
use Pod::Usage;
my %conf;
tie %conf, 'esmith::config';
my %accounts;
tie %accounts, 'esmith::config', '/home/e-smith/db/accounts';
my %hosts;
tie %hosts, 'esmith::config', '/home/e-smith/db/hosts';
my %domains;
tie %domains, 'esmith::config', '/home/e-smith/db/domains';
my %processmail;
# Really unsure of what this line does - John Bennett
tie %processmail, 'esmith::config', '/home/e-smith/db/processmail';
my ($Dump, $OutDir, $Hlp);
my $HostName = db_get(\%conf, 'SystemName');

#==============================================================================
#  Main
#==============================================================================
# Analyze commandline options
GetOptions  ("help"           => \$Hlp,
             "dump"           => \$Dump,
             "output-path=s"  => \$OutDir);

if ( $Hlp ) { &PrintPod(9); exit; }

if ($OutDir) {
    if ( ! -d $OutDir ) { die "Error: $OutDir is not a directory\n\a"; }
}
else
    { $OutDir = "./"; }

if ($Dump) {
    print "Creating input files for the lat-toolkit... ";
    &ReadUsers;
    &ReadPseudonyms;
    &ReadProcmail;
    &ReadQuota;
    &ReadGroups;
    &ReadPPTP;
    &ReadIbays;
    &ReadDomains;
    &ReadHosts;
    &ReadShadow;

    open (REST, "> $OutDir/lat-restore");
    print REST "#!/bin/bash\n";
    print REST "echo 'This script was automatically created by lat-dump and will recreate all user'\n";
    print REST "echo 'accounts, ibays, etc on this server.'\n";
    print REST "echo 'Do you want to continue (Y/N)?'\n";
    print REST "read c\n";
    print REST 'if [ $c = "y" ] || [ $c = "Y" ]; then'."\n"; 
    print REST "	/usr/sbin/lat-users -a -i=$HostName.Users\n";
    print REST "	/usr/sbin/lat-procmail -i=$HostName.Procmail\n";
    print REST "	/usr/sbin/lat-quota -i=$HostName.Quota\n";
    print REST "	/usr/sbin/lat-groups -a -i=$HostName.Groups\n";
    print REST "	/usr/sbin/lat-pptp -i=$HostName.PPTP\n";
    print REST "	/usr/sbin/lat-ibays -a -i=$HostName.Ibays\n";
    print REST "	/usr/sbin/lat-domains -a -i=$HostName.Domains\n";
    print REST "	/usr/sbin/lat-hosts -a -i=$HostName.Hosts\n";
    print REST "        /usr/sbin/lat-pseudonyms -a -i=$HostName.Pseudonyms\n";
    print REST "        /usr/sbin/lat-shadow -a -i=$HostName.shadow\n";
    print REST "else\n";
    print REST "	echo 'Action cancelled!'\n";
    print REST "fi\n";
    close(REST);
    chmod 0750, "$OutDir/lat-restore";
    print "\nDone!\n";
    print "Use lat-restore to recreate the accounts, ibays, etc on a different server \nor on a clean install.\n";
}
else { &PrintPod(1); exit; }

#==============================================================================
#  Subroutines
#==============================================================================
sub ReadShadow {
    open(BACACC, "> $OutDir/$HostName.shadow");
    print BACACC "#--------------------------------#\n";
    print BACACC "#User        |Encrypted Password |\n";
    print BACACC "#--------------------------------#\n";

use esmith::ConfigDB;
use esmith::AccountsDB;
my $adb = esmith::AccountsDB->open_ro();
    foreach my $user ($adb->users)
    {
        my %properties = $user->props;
        my $key = $user->key;

        # lecture shadow
        open(ACC, "< /etc/shadow") || die "Can't find /etc/shadow.\a\n";
        my $line = "";
        while (<ACC>){
                $line = $_;
                if($line =~ /^$key:(.*):(.*):(.*):(.*):(.*):(.*):(.*):$/){
                                print BACACC $key.(' ' x (12 - length($key)));
                                print BACACC " |";
                                print BACACC $1."\n";

                        }
                }
        close(ACC);
     }
}
#==============================================================================
sub ReadUsers {
    my @fldinf = ("User",              12,
                  "FirstName",         10,
                  "LastName",          15,
                  "Password",           8,
                  "Dept",              15,
                  "Company",           15,
                  "Street",            15,
                  "City",              20,
                  "Phone",             16,
                  "EmailForward",      12,
                  "ForwardAddress",    30,
                  "Uid",                5);
    &PrintDump("Users", "user", "accounts", \%accounts, @fldinf);
}
#==============================================================================
sub ReadQuota {
    my @fldinf = ("User",              30,
                  "MaxBlocksSoftLim",  16,
                  "MaxBlocks",         16);
    &PrintDump("Quota", "user", "accounts", \%accounts, @fldinf);
}
#==============================================================================
sub ReadDomains {
    my @fldinf = ("Domain",            30,
                  "Description",       23,
                  "Content",           12);
    &PrintDump("Domains", "domain", "domains", \%domains, @fldinf);
}
#==============================================================================
sub ReadIbays {
    my @fldinf = ("User",              12,
                  "Name",              23,
                  "Group",             12,
                  "UserAccess",        20,
                  "PublicAccess",      12,
                  "Password",           8,
                  "CgiBin",             9,
                  "Uid",                5);
    &PrintDump("Ibays", "ibay", "accounts", \%accounts, @fldinf);
}
#==============================================================================
sub ReadPPTP {
    my @fldinf = ("PPTPAccess",       10);

    open(ACC, "< /home/e-smith/db/accounts") || die "Can't find /home/e-smith/db/accounts.\a\n";
    my @accounts = sort(grep(/\=user\|/, <ACC>));
    close(ACC);

    open(BACACC, "> $OutDir/$HostName.PPTP");
    print BACACC "#-------------------------#\n";
    print BACACC "#User        |PPTP Access |\n";
    print BACACC "#-------------------------#\n";

    foreach (@accounts) {
        $_ =~ /\=user\|/;
        my $AccName = $`;
        print BACACC $AccName.(' ' x (12 - length($AccName)));
        my $SMEvalue = db_get_prop(\%accounts,$AccName,"PPTPAccess");
        if ( ! $SMEvalue) { $SMEvalue = "off" }
        print BACACC " |";
        print BACACC $SMEvalue."\n";
    }
    close(BACACC);
}
#==============================================================================
sub ReadPseudonyms {
    open(ACC, "< /home/e-smith/db/accounts") || die "Can't find /home/e-smith/db/accounts.\a\n";
    my @accounts = sort(grep(/\=user\|/i, <ACC>));
    close(ACC);
    push(@accounts,"admin=user|");
    open(ACC, "< /home/e-smith/db/accounts") || die "Can't find /home/e-smith/db/accounts.\a\n";
    my @pseudonyms = grep(/\=pseudonym\|/i, <ACC>);
    close(ACC);

    open(BACACC, "> $OutDir/$HostName.Pseudonyms");
    print BACACC "#".('-' x 78)."#\n";
    print BACACC "#User        |Pseudonyms".(' ' x 55)."|\n";
    print BACACC "#".('-' x 78)."#\n";

    foreach (@accounts) {
        if ($_ =~ /\=user\|/) {
            my $AccName = $`;
            my $pseudolist;
            foreach (@pseudonyms) {
                my $psinfo = $_;
                $psinfo =~ /\|Account\|/i;
                my $owner = $'; chomp($owner);
                if ($AccName eq $owner) {
                    if ($psinfo =~ /\=pseudonym\|/i) { $pseudolist .= " | ".$`; }
                }
            }
            if ($pseudolist) {
                print BACACC $AccName.(' ' x (12 - length($AccName))).$pseudolist."\n";
            }
        }
    }
    close(BACACC);
}
#==============================================================================
sub ReadGroups {
    my @finfo  = ("Group",              12,
                  "Description",        30,
                  "Gid",                 5,
                  "Members",            25);
    my $nm  =  "group";

    open(ACC, "< /home/e-smith/db/accounts") || die "Can't find /home/e-smith/db/accounts.\a\n";
    my @accounts = sort(grep(/\=group\|/, <ACC>));
    close(ACC);

    open(BACACC, "> $OutDir/$HostName.Groups");
    my $Header= "#$finfo[0]".(' ' x ($finfo[1] - 1 - length($finfo[0])))." |";
    for (my $cnt=2; $cnt<$#finfo; $cnt=$cnt+2) {
        $Header .= $finfo[$cnt].(' ' x ($finfo[$cnt+1] - length($finfo[$cnt])))." |";
    }

    print BACACC "#".("-" x (length($Header)-2))."#\n";
    print BACACC $Header."\n";
    print BACACC "#".("-" x (length($Header)-2))."#\n";

    foreach (@accounts) {
        $_ =~ /\=group\|/;
        my $AccName = $`;
        print BACACC $AccName.(' ' x ($finfo[1] - length($AccName)));
        my $cnt;
        for ($cnt=2; $cnt<$#finfo-2; $cnt=$cnt+2) {
            my $SMEvalue = db_get_prop(\%accounts,$AccName,$finfo[$cnt]);
            if ( ! $SMEvalue) { $SMEvalue = " " }
            print BACACC " |";
            print BACACC $SMEvalue.(' ' x ($finfo[$cnt+1] - length($SMEvalue)));
        }
        my $members = db_get_prop(\%accounts, $AccName, $finfo[$cnt]);
        $members =~  s/,/ \|/g;
        print BACACC " |$members\n";
    }
    close(BACACC);
}
#==============================================================================
sub ReadProcmail {
    my @finfo  = ("User",              12,
                  "Status",             8,
                  "deldups",            7,
                  "loglevel",           8,
                  "mode",               6);

    open(ACC, "< /home/e-smith/db/accounts") || die "Can't find /home/e-smith/db/accounts.\a\n";
    my @accounts = sort(grep(/\=user\|/, <ACC>));
    close(ACC);

    open(BACACC, "> $OutDir/$HostName.Procmail");
    my $Header= "#User        |";
    for (my $cnt=2; $cnt<$#finfo; $cnt=$cnt+2) {
        $Header .= $finfo[$cnt].(' ' x ($finfo[$cnt+1] - length($finfo[$cnt])))." |";
    }

    print BACACC "#".("-" x (length($Header)-2))."#\n";
    print BACACC $Header."\n";
    print BACACC "#".("-" x (length($Header)-2))."#\n";

    foreach (@accounts) {
        $_ =~ /\=user\|/;
        my $AccName = $`;
        print BACACC $AccName.(' ' x ($finfo[1] - length($AccName)));
        if (db_get_prop(\%accounts, $AccName, "EmailForward") =~ m/procmail/i)
             { print BACACC " |enabled " }
        else { print BACACC " |disabled" }
        for (my $cnt=4; $cnt<$#finfo; $cnt=$cnt+2) {
            my $SMEvalue = db_get_prop(\%processmail, $AccName, $finfo[$cnt]);
            if ( ! $SMEvalue) { $SMEvalue = " " }
            print BACACC " |";
            print BACACC $SMEvalue.(' ' x ($finfo[$cnt+1] - length($SMEvalue)));
        }
        print BACACC "\n";
    }
    close(BACACC);
}
#==============================================================================
sub ReadHosts {
    my @finfo = ("HostType",     8,
                 "Visibility",  10,
                 "InternalIP",  15,
                 "ExternalIP",  15,
                 "MACAddress",  17);

    open(ACC, "< /home/e-smith/db/hosts") || die "Can't find /home/e-smith/db/hosts.\a\n";
    my @accounts = sort(grep(/\=host\|/, <ACC>));
    close(ACC);

    open(BACACC, "> $OutDir/$HostName.Hosts");
    my $Header= "#Hosts       |";
    $Header .= "Domainname                          |";
    for (my $cnt=0; $cnt<$#finfo; $cnt=$cnt+2) {
        $Header .= $finfo[$cnt].(' ' x ($finfo[$cnt+1] - length($finfo[$cnt])))." |";
    }

    print BACACC "#".("-" x (length($Header)-2))."#\n";
    print BACACC $Header."\n";
    print BACACC "#".("-" x (length($Header)-2))."#\n";

    foreach (@accounts) {
        $_ =~ /\=host\|/;
        my $AccName = $`;
        $AccName =~ m/\./;
        $AccName = $`;
        my $Domain = $';
        print BACACC $AccName.(' ' x (12 - length($AccName)))." |";
        print BACACC $Domain.(' ' x (35 - length($Domain)));
        for (my $cnt=0; $cnt<$#finfo; $cnt=$cnt+2) {
            my $SMEvalue = db_get_prop(\%hosts,"$AccName.$Domain",$finfo[$cnt]);
            if ( ! $SMEvalue) { $SMEvalue = " " }
            print BACACC " |";
            print BACACC $SMEvalue.(' ' x ($finfo[$cnt+1] - length($SMEvalue)));
        }
        print BACACC "\n";
    }
    close(BACACC);
}
#==============================================================================
# Print lat-info in a nice format
sub PrintDump {
    my ($out, $nm, $src, $dbpointer, @finfo) = @_;

    open(ACC, "< /home/e-smith/db/$src") || die "Can't find /home/e-smith/db/$src.\a\n";
    my @accounts = sort(grep(/\=$nm\|/, <ACC>));
    close(ACC);

    open(BACACC, "> $OutDir/$HostName.$out");
    my $Header= "#$finfo[0]".(' ' x ($finfo[1] - 1 - length($finfo[0])))." |";
    for (my $cnt=2; $cnt<$#finfo; $cnt=$cnt+2) {
        $Header .= $finfo[$cnt].(' ' x ($finfo[$cnt+1] - length($finfo[$cnt])))." |";
    }

    print BACACC "#".("-" x (length($Header)-2))."#\n";
    print BACACC $Header."\n";
    print BACACC "#".("-" x (length($Header)-2))."#\n";

    foreach (@accounts) {
        $_ =~ /\=$nm\|/;
        my $AccName = $`;
        print BACACC $AccName.(' ' x ($finfo[1] - length($AccName)));
        for (my $cnt=2; $cnt<$#finfo; $cnt=$cnt+2) {
            my $SMEvalue = db_get_prop($dbpointer,$AccName,$finfo[$cnt]);
            if ( ! $SMEvalue) { $SMEvalue = " " }
            print BACACC " |";
            print BACACC $SMEvalue.(' ' x ($finfo[$cnt+1] - length($SMEvalue)));
        }
        print BACACC "\n";
    }
    close(BACACC);
}
#==============================================================================
# Print the pod text as a help screen
sub PrintPod {
    my ($verbose, $message) = @_;
    pod2usage(-verbose => $verbose, -message => $message, -exitval => 64);
}

#==============================================================================
=pod

=head1 NAME

B<lat-dump> - The lazy administrator's tool to extract config info

=head1 DESCRIPTION

Creates input-files for the lat-toolkit, based on the current configuration of the SME server (5.x/6.x). The information is extracted from the /home/e-smith/db/* databases.

The resulting input-files can be used to replicate user accounts, ibays, etc on a different SME server, or recreate them on a clean install. To facilitate the restoring/replicating, the lat-restore script is automatically created. This will launch the various lat-tools in the right sequence.

=head1 SYNOPSIS

B<lat-config> [options]

=head1 OPTIONS

The following options are supported:

=over 4

=item B<-d>, B<--dump>

Create input files

=item B<-h>, B<--help>

Extended help for this tool

=item B<-o=/path/>, B<--output-dir=/path/>

Directory where the configuration files should be stored. If omitted, the current directory is used.

=back

=head1 EXAMPLES

B<lat-dump -d -o=/var/tmp>

Creates the configuration files and writes them to /var/tmp.

=head1 SEE ALSO

lat-users(8), lat-group(8), lat-pseudonyms(8), lat-ibays(8), lat-quota(8), lat-domains(8), lat-hosts(8), lat-procmail(8), lat-pptp(8)

=head1 VERSION

Version 0.9.0 (2004-09-08). The latest version is hosted at B<http://www.contribs.org/contribs/mblotwijk/>

=head1 COPYRIGHT

(c)2003-2004, Altiplano bvba (B<http://www.altiplano.be>). Released under the terms of the GNU license.


=head1 BUGS

Please report bugs to <Bugs@Altiplano.Be>

=cut

#==============================================================================
