#!/usr/bin/perl -w 

#---------------------------------------------------------------------
# Copyright (C) 2016 Firewall-Services
# daniel@firewall-services.com
# 
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
#----------------------------------------------------------------------
package esmith::FormMagick::Panel::expireaccounts;

use strict;

use esmith::FormMagick;
use esmith::AccountsDB;
use esmith::ConfigDB;
use esmith::cgi;
use DateTime;
use File::Basename;
use Exporter;
use Carp qw(verbose);

our @ISA = qw(esmith::FormMagick Exporter);

our @EXPORT = qw(
    print_user_table
    print_save_button
    print_custom_button
    print_section_bar
    print_account_name
);

our $a = esmith::AccountsDB->open || die "Couldn't open AccountsDB";
our $c = esmith::ConfigDB->open   || die "Couldn't open ConfigDB";

our %defaults = (
    ExpireAutoReply       => 'enabled',
    ExpireDeleteAfterLock => 'never',
    WarnUsers             => 'enabled'
);

sub new {
    shift;
    my $self = esmith::FormMagick->new();
    $self->{calling_package} = (caller)[0];
    bless $self;
    return $self;
}

sub print_user_table {
    my $self = shift;
    my $q = $self->{cgi};

    my @users = $a->users;

    if ( scalar @users < 1) {
        print $q->Tr($q->td($self->localise('NO_USER_ACCOUNTS')));
        return "";
    }

    my $scriptname = basename($0);
    my $now = DateTime->now;

    print "  <tr><td colspan=\"2\">";
    print $q->start_table ({-CLASS => "sme-border"});

    if (_count_active_users() > 0){
        print $q->Tr(
            esmith::cgi::genSmallCell($q, $self->localise('ACTIVE_ACCOUNT'),     "header"),
            esmith::cgi::genSmallCell($q, $self->localise('USER_NAME'),          "header"),
            esmith::cgi::genSmallCell($q, $self->localise('FORWARD'),            "header"),
            esmith::cgi::genSmallCell($q, $self->localise('DAYS_BEFORE_LOCK'),   "header"),
            esmith::cgi::genSmallCell($q, $self->localise('ACTION'),             "header")
        );

        foreach my $u (@users) {
            my $username    = $u->key();
            next unless (($u->prop('PasswordSet') || 'no') eq 'yes');
            my $first       = $u->prop('FirstName')      || '';
            my $last        = $u->prop('LastName')       || '';
            my $lock_date   = $u->prop('ExpireLockOn')   || '';
            my $delivery    = $u->prop('EmailForward')   || 'local';
            my $fwd         = $u->prop('ForwardAddress') || '';
            my $action      = "<a href=\"$scriptname?page=0&page_stack=&acctName=$username&wherenext=ModifyActive\">" .
                              $self->localise('MODIFY') . "</a>";
            my $days_left = '';
            if ($lock_date =~ m/^(\d{4})\-(\d{1,2})\-(\d{1,2})$/){
              my $lock_on = eval {
                DateTime->new(
                  year  => $1,
                  month => $2,
                  day   => $3
                );
              };
              $days_left = $lock_on->delta_days($now)->in_units('days') if ($lock_on);
            }
            my $addr = ($delivery eq 'local') ? '' : $fwd;
             print $q->Tr(
                esmith::cgi::genSmallCell($q, $username,      "normal"),
                esmith::cgi::genSmallCell($q, "$first $last", "normal"),
                esmith::cgi::genSmallCell($q, $addr,          "normal"),
                esmith::cgi::genSmallCell($q, $days_left,     "normal"),
                esmith::cgi::genSmallCell($q, $action,        "normal")
            );
        }
    }
    if (_count_inactive_users() > 0){
        # Now, same for locked accounts
        print $q->Tr(
            esmith::cgi::genSmallCell($q, $self->localise('INACTIVE_ACCOUNT'),   "header"),
            esmith::cgi::genSmallCell($q, $self->localise('USER_NAME'),          "header"),
            esmith::cgi::genSmallCell($q, $self->localise('FORWARD'),            "header"),
            esmith::cgi::genSmallCell($q, $self->localise('DAYS_BEFORE_DELETE'), "header"),
            esmith::cgi::genSmallCell($q, $self->localise('ACTION'),             "header")
        );
        foreach my $u (@users) {
            my $username    = $u->key();
            next unless (($u->prop('PasswordSet') || 'no') ne 'yes');
            my $first       = $u->prop('FirstName')             || '';
            my $last        = $u->prop('LastName')              || '';
            my $delete_in   = $u->prop('ExpireDeleteAfterLock') || '';
            my $locked_on   = $u->prop('ExpireLockedOn')        || '';
            my $delivery    = $u->prop('EmailForward')          || '';
            my $fwd         = $u->prop('ForwardAddress')        || '';
            my $action      = "<a href=\"$scriptname?page=0&page_stack=&acctName=$username&wherenext=ModifyLocked\">" .
                              $self->localise('MODIFY') . "</a>";
            # Skip if not locked by this contrib
            next unless ($locked_on =~ m/^\d{4}\-\d{1,2}\-\d{1,2}$/);
            my $days_left = '';
            if ($delete_in =~ m/^\d+$/ && $locked_on =~ m/^(\d{4})\-(\d{1,2})\-(\d{1,2})$/){
              my $locked_date = eval {
                DateTime->new(
                  year  => $1,
                  month => $2,
                  day   => $3
                );
              };
              if ($locked_date){
                my $delete_on = $locked_date->add(days => $delete_in);
                $days_left = $delete_on->delta_days($now)->in_units('days');
              }
            }
            my $addr = ($delivery eq 'local') ? '' : $fwd;
            print $q->Tr(
                esmith::cgi::genSmallCell($q, $username,      "normal"),
                esmith::cgi::genSmallCell($q, "$first $last", "normal"),
                esmith::cgi::genSmallCell($q, $addr,          "normal"),
                esmith::cgi::genSmallCell($q, $days_left,     "normal"),
                esmith::cgi::genSmallCell($q, $action,        "normal")
            );
        }
    }
    print qq(</table></td></tr>\n);
    return "";
}

sub print_save_button {
    my ($self) = @_;
    $self->print_button("SAVE");
}

sub print_section_bar{
    my $self = shift;
    print "  <tr>\n    <td colspan='2'>\n";
    print "<hr class=\"sectionbar\"/>\n";
    return undef;
}

sub print_custom_button{
    my ($self, $desc, $page) = @_;
    my $url = basename($0) . "?page=0&page_stack=&Next=Next&wherenext=" . $page;

    print "<tr><td colspan='2'>";
    print $self->{cgi}->p(
        $self->{cgi}->a({href => $url, -class => "button-like"}, $self->localise($desc))
    );
    print qq(</tr>);
    return undef;
}

sub print_account_name{
  my ($self) = @_;
  my $acctName = $self->{cgi}->param('acctName');
  print qq(<tr><td class="sme-noborders-label">) .
    $self->localise('LABEL_USER_ACCOUNT') .
    qq(</td>) .
    qq(<td class="sme-noborders-content">$acctName</td>);
  return undef;
}

sub get_user_prop{
    my ($self, $field) = @_;
    return $a->get($self->{cgi}->param('acctName'))->prop("$field") || $defaults{$field} || '';
}

sub get_user_bool{
    my ($self, $field) = @_;
    my $val = $a->get($self->{cgi}->param('acctName'))->prop("$field") || $defaults{$field} || '';
    return ($val =~ m/^yes|enabled|1|on$/) ? 'enabled' : 'disabled';
}

sub get_conf_prop{
    my ($self, $field) = @_;
    return $c->get('ExpireAccounts')->prop($field) || '';
}

sub get_conf_bool{
    my ($self, $field) = @_;
    my $val = $c->get('ExpireAccounts')->prop($field) || $defaults{$field} || '';
    return ($val =~ m/^yes|enabled|1|on$/) ? 'enabled' : 'disabled';
}

sub get_delete_options{
    my ($self) = @_;
    my $options = [ qw(never 7 30 180 365) ];
    my $acctName = $self->{cgi}->param('acctName');
    if ($acctName =~ /^(\w[\-\w_\.]*)$/){
        $acctName  = $1;
        my $acct   = $a->get($acctName);
        my $pass   = $acct->prop('PasswordSet') || 'no';
        my $locked = $acct->prop('ExpireLockedOn') || '';
        if ($pass eq 'no' && $locked !~ m/^\d{4}\-\d{1,2}\-\d{1,2}$/){
            $options = [ qw(never) ];
        }
    }
    return $options;
}

sub modify_config{
    my ($self) = @_;
    my $rec = $c->get('ExpireAccounts') || $c->new_record('ExpireAccounts', { type => 'service' });
    my %new_props = ();
    foreach my $prop (qw(WarningDelay DaysBetweenWarnings WarningRecipient)){
        if (!$self->{cgi}->param($prop) || $self->{cgi}->param($prop) eq ''){
            $rec->delete_prop($prop);
        }
        else{
            $new_props{$prop} = $self->{cgi}->param($prop);
        }
    }
    $rec->merge_props(%new_props);
    $self->success('CONFIG_MODIFIED');
}

sub modify_user {
    my ($self) = @_;
    my $acctName = $self->{cgi}->param('acctName');

    unless (($acctName) = ($acctName =~ /^(\w[\-\w_\.]*)$/)) {
        return $self->error(
            $self->localise('TAINTED_USER', { acctName => $acctName })
        );
    }
    $acctName = $1;

    my $acct = $a->get($acctName);
    my $type = $acct->prop('type');

    unless ($type eq 'user'){
        return $self->error(
          $self->localise('NOT_A_USER_ACCOUNT', { acctName => $acctName })
        );
    }
    my %new_props = ();
    foreach my $prop (qw(ExpireLockOn ExpireForwardAfterLock ExpireAutoReply ExpireDeleteAfterLock ExpireWarnUser)){
        if (!$self->{cgi}->param($prop) || $self->{cgi}->param($prop) eq ''){
            $acct->delete_prop($prop);
        }
        else{
            $new_props{$prop} = $self->{cgi}->param($prop);
        }
    }
    $acct->merge_props(%new_props);
    unless(system('/sbin/e-smith/signal-event', 'user-update-expire-settings', $acctName) == 0){
      return $self->error('ERROR_OCCURRED');
    }
    $self->success('USER_MODIFIED');
}

sub _count_active_users{
  my $users = 0;
  foreach my $user ($a->users){
    $users++ if ($user->prop('PasswordSet') || 'no') eq 'yes';
  }
  return $users;
}

sub _count_inactive_users{
  my $users = 0;
  foreach my $user ($a->users){
    if (($user->prop('PasswordSet') || 'no') eq 'no' &&
        ($user->prop('ExpireLockedOn') || '') =~ m/^\d{4}\-\d{1,2}\-\d{1,2}$/){
      $users++;
    }
  }
  return $users;
}

# Validation routines

# Number must be int and positive
sub is_positive_int{
    my ($self, $num) = @_;
    return $self->localise('MUST_BE_POSITIVE_NUMBER') unless ($num =~ m/^\d+$/ && $num > 0);
    return 'OK';
}

# Take a string representing a date, must be YYY-MM-DD format, and in the future (including today), or an empty string
sub is_future_date_or_empty {
    my ($self, $date_string) = @_;
    return 'OK' if ($date_string eq '');
    return $self->localise('DATE_FORMAT_INVALID') unless ($date_string =~ /^(\d{4})\-(\d{1,2})\-(\d{1,2})$/);
    my $date = eval {
      DateTime->new(
        year  => $1,
        month => $2,
        day   => $3
      );
    };
    return $self->localise('DATE_FORMAT_INVALID') unless ($date);
    my $now = DateTime->now;
    return $self->localise('DATE_IS_PASSED') unless ($date >= $now);
    return 'OK';
}

# Take a string, must be a valid email or an empty string
sub is_email_or_empty {
    my ($self, $field) = @_;
    return $self->localise('BAD_SYNTAX') unless (($field =~ m/^[a-zA-Z][a-zA-Z0-9\._\-]*\@?([a-zA-Z0-9\._\-]*)?$/) || ($field eq ''));
    return 'OK';
}

