package LATMOS::Accounts::Bases::Unix;

use 5.010000;
use strict;
use warnings;

use base qw(LATMOS::Accounts::Bases);

our $VERSION = (q$Rev$ =~ /^Rev: (\d+) /)[0];

=head1 NAME

LATMOS::Ad - Perl extension for blah blah blah

=head1 SYNOPSIS

  use LATMOS::Accounts::Bases;
  my $base = LATMOS::Accounts::Bases->new('unix');
  ...

=head1 DESCRIPTION

Account base access over standard unix file format.

=head1 FUNCTIONS

=cut

=head2 new(%options)

Create a new LATMOS::Ad object for windows AD $domain.

domain / server: either the Ad domain or directly the server

ldap_args is an optionnal list of arguments to pass to L<Net::LDAP>.

=cut

sub new {
    my ($class, %options) = @_;
    
    my $base = {
        passwd =>  $options{passwd} || '/etc/passwd',
        shadow =>  $options{shadow} || '/etc/shadow',
        group =>   $options{group} || '/etc/group',
        gshadow => $options{gshadow} || '/etc/gshadow',
        # are we using shadow, default to yes
        use_shadow => (defined($options{use_shadow}) ? $options{use_shadow} : 1),
        users => {},
        groups => {},
    };

    bless($base, $class);
}

my @password_fields = qw(account password uid gid gecos home shell);
my @shadow_fields =   qw(account spassword last_changed before_ch after_ch exp_warn exp_disable disable res);
my @group_fields =    qw(group_name passwd gid user_list);
my @gshadow_fields =  qw(group_name spassword unknown suser_list);

# All UNIX account file are colon separated field
# This function factorize open/read/split fields

sub _load_unix_file {
    my ($self, $file, $callback) = @_;
    open(my $handle, '<', $file) or return;
    while (my $line = <$handle>) {
        chomp($line);
        my @ch = split(':', $line);
        $callback->(@ch);
    }
    close($handle);
    return 1;
}

=head2 load

Read file and load data into memory

=cut

sub load {
    my ($self) = @_;
    
    $self->_load_unix_file(
        $self->{passwd},
        sub {
            my @ch = @_;
            my $user = $ch[0];
            # TODO add check ?
            foreach (@password_fields) {
                $self->{users}{$user}{$_} = shift(@ch);
            }
        },
    ) or return
    
    $self->_load_unix_file(
        $self->{group},
        sub {
            my @ch = @_;
            my $group = $ch[0];
            # TODO add check ?
            foreach (@group_fields) {
                $self->{groups}{$group}{$_} = shift(@ch);
            }
            # split user in the group
            foreach (split(',', $ch[3] || '')) {
                $self->{groups}{$group}{'users'}{$_} = 1;
            }
        }
    ) or return;

    # using shadow ? then reading shadow file
    if ($self->{use_shadow}) {
    $self->_load_unix_file(
        $self->{shadow},
        sub {
            my @ch = @_;
            my $user = $ch[0];
            foreach (@shadow_fields) {
                $self->{users}{$user}{$_} = shift(@ch);
            }
        }
    ) or return;

    $self->_load_unix_file(
        $self->{gshadow},
        sub {
            my @ch = @_;
            my $group = $ch[0];
            # TODO add check ?
            foreach (@gshadow_fields) {
                $self->{groups}{$group}{$_} = shift(@ch);
            }
            # split user in the group
            foreach (split(',', $ch[3] || '')) {
                $self->{groups}{$group}{'susers'}{$_} = 1;
            }
        }
    ) or return;

    } # use shadow ?
}

1;

__END__

=head1 SEE ALSO

=head1 AUTHOR

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

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2008, 2009 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
