#!/usr/local/bin/perl
# Dhcphosts

use Dhcphosts;
my $Dhcphosts = Dhcphosts->new($db, $admin, \%conf);

use Abills::Base;
use Socket;

use Nas;
my $Nas = Nas->new($db, \%conf);

#*******************************************************************
# Delete user from module
# dhcphosts_user_del()
#*******************************************************************
sub dhcphosts_user_del {
  my ($uid, $attr) = @_;

  $Dhcphosts->{UID} = $uid;
  $Dhcphosts->host_del({ UID => $uid });

  return 0;
}

#*******************************************************************
#
#*******************************************************************
sub dhcphosts_periodic {
  my ($attr) = @_;

  my $debug = $attr->{DEBUG} || 0;
  my $debug_output = '';
  $debug_output .= "Dhcphosts: Dhcp reconfigure\n" if ($debug > 1);

  dhcphosts_config(
    {
      NETWORKS => '-',
      reconfig => 1,
      QUITE    => 1,
      DEBUG    => $attr->{DEBUG}
    }
  );

  $DEBUG .= $debug_output;
  return $debug_output;
}

#*******************************************************************
#
#*******************************************************************
sub dhcphosts_mac_static {

  if ($FORM{MAKE}) {
    if (!open(FILE, ">$conf{TPL_DIR}/Dhcphosts_dhcphosts_ipguard_static.tpl")) {
      $html->message('err', $_ERROR, "Can't open file '$conf{TPL_DIR}/Dhcphosts_dhcphosts_ipguard_static.tpl' $!\n");

    }
    else {
      print FILE "$FORM{ETHERS}";
      close(FILE);
      print $html->message('info', $_INFO, "$_CHANGED '$conf{TPL_DIR}/Dhcphosts_dhcphosts_ipguard_static.tpl'");
    }
  }

  my $ethers_content = $html->tpl_show(_include('dhcphosts_ipguard_static', 'Dhcphosts'), {}, { OUTPUT2RETURN => 1 });
  $html->tpl_show(_include('dhcphosts_ipguard', 'Dhcphosts'), { ETHER_CONTENT => "$ethers_content", });
}

#*******************************************************************
#
#*******************************************************************
sub dhcphosts_mac_block_show {
  my ($attr) = @_;
  my $debug = $attr->{DEBUG} || 0;

  my $ethers_content = "# $DATE $TIME\n# ABillS IPGuard CONFIG: \n";

  my @pair_status = ('ACCEPT', 'DENY');
  my $list = $Dhcphosts->hosts_list(
    {
      STATUS                     => $LIST_PARAMS{STATUS},
      PAGE_ROWS                  => 1000000,
      DHCPHOSTS_DEPOSITCHECK     => $conf{DHCPHOSTS_DEPOSITCHECK},
      DHCPHOSTS_EXT_DEPOSITCHECK => $conf{DHCPHOSTS_EXT_DEPOSITCHECK}
    }
  );

  #Get Templates default for IP Guard
  my $DENY_TEMPLATE   = ($conf{DHCPHOSTS_IPGUARD_DENY_TPL})   ? $conf{DHCPHOSTS_IPGUARD_DENY_TPL}   : '';
  my $ACCEPT_TEMPLATE = ($conf{DHCPHOSTS_IPGUARD_ACCEPT_TPL}) ? $conf{DHCPHOSTS_IPGUARD_ACCEPT_TPL} : '%MAC% %IP% # %LOGIN%; %STATUS%; %DEPOSIT%';

  foreach my $line (@$list) {

    #Block
    if ($line->[6] eq '') {
      next;
    }
    elsif (!defined($line->[1])) {
      print 'Warning: IP: ' . ($ip || 'No ip') . ' MAC: ' . ($mac || 'No MAC') . " Record don't have users (ID: $line->[0])\n";
      next;
    }

    #Chack status
    my $status = ($line->[10] == 1 || $line->[ 14 + $Dhcphosts->{SEARCH_FIELDS_COUNT} ] == 1) ? 1 : 0;

    my $deposit = 0;

    if (defined($conf{DHCPHOSTS_EXT_DEPOSITCHECK})) {
      $deposit = $line->[ 15 + $Dhcphosts->{SEARCH_FIELDS_COUNT} ];
    }
    elsif (defined($conf{DHCPHOSTS_DEPOSITCHECK})) {
      $deposit = $line->[ 15 + $Dhcphosts->{SEARCH_FIELDS_COUNT} ];
    }

    $deposit = 0 if (!$deposit);

    my %INFO = (
      IP => ($conf{DHCPHOSTS_IPGUARD_FORMAT} && $conf{DHCPHOSTS_IPGUARD_FORMAT} eq 'MAC') ? '0.0.0.0' : $line->[11],
      MAC     => $line->[6],
      LOGIN   => $line->[1],
      DEPOSIT => $deposit,
      UID     => $line->[ 12 + $Dhcphosts->{SEARCH_FIELDS_COUNT} ],
      EXPIRE  => $line->[7]
    );

    #DENY
    if ($status == 1 || ((defined($conf{DHCPHOSTS_DEPOSITCHECK}) && $deposit < $conf{DHCPHOSTS_DEPOSITCHECK}) || (defined($conf{DHCPHOSTS_EXT_DEPOSITCHECK}) && $deposit < $conf{DHCPHOSTS_EXT_DEPOSITCHECK}))) {
      next if ($DENY_TEMPLATE eq '');
      $ethers_content .= tpl_parse(
        $DENY_TEMPLATE,
        {
          STATUS => $pair_status[1],
          %INFO
        }
      );
    }

    #Allow
    else {
      next if ($ACCEPT_TEMPLATE eq '');
      $ethers_content .= tpl_parse(
        $ACCEPT_TEMPLATE,
        {
          STATUS => $pair_status[$status],
          %INFO
        }
      );
    }

    $ethers_content .= "\n";
  }

  $ethers_content .= $html->tpl_show(_include('dhcphosts_ipguard_static', 'Dhcphosts'), undef, { OUTPUT2RETURN => 1 });

  return $ethers_content;
}

#*******************************************************************
#
#*******************************************************************
sub dhcphosts_mac_block_make {
  my ($attr) = shift;

  if (!$attr->{ETHER_CONTENT}) {
    $attr->{ETHER_CONTENT} = dhcphosts_mac_block_show();
  }

  my $debug = $attr->{DEBUG} || 0;
  my $debug_output = '';
  $debug_output = "$attr->{ETHER_CONTENT}\n" if ($debug > 1);
  $DEBUG .= $debug_output;

  if ($debug > 4) {

    return 1;
  }

  open(FILE, ">$var_dir/ipguard") || return "Can't open '$var_dir/ipguard' $!";
  print FILE "$attr->{ETHER_CONTENT}";
  close(FILE);

  $DEBUG .= $debug_output;
  return 1;
}

#*******************************************************************
#
#*******************************************************************
sub dhcphosts_mac_block {
  if ($FORM{MAKE}) {
    my $ret = dhcphosts_mac_block_make($FORM{ETHER_CONTENT});
    if ($ret eq '1') {
      print $html->message('info', $_INFO, "$_CHANGED '$var_dir/ipguard'");
    }
    else {
      print $html->message('err', $_ERROR, "$ret");
    }
  }

  my $ethers_content = dhcphosts_mac_block_show();
  $html->tpl_show(
    _include('dhcphosts_ipguard', 'Dhcphosts'),
    {
      ETHER_CONTENT => "$ethers_content",
      FILE          => "$var_dir/ipguard"
    }
  );
}

#*******************************************************************
# Show dhcpd.leases information
#*******************************************************************
sub dhcphosts_monitor {

  if (!$conf{DHCPHOSTS_LEASES} && !$AUTH{dhcp}) {
    print $html->message('err', $_ERROR, "$_NOT_EXIST " . '$conf{DHCPHOSTS_LEASES}');
    return 0;
  }

  if ($FORM{ping}) {
    if ($FORM{ping} =~ /^(\d){1,3}\.(\d){1,3}\.(\d){1,3}\.(\d){1,3}$/) {
      my $res = `$PING -c 5 $FORM{ping}`;
      $html->message('info', $_INFO, "Ping  $FORM{ping}" . $html->br() . 'Result:' . $html->br() . $html->pre($res, { OUTPUT2RETURN => 1 }));
    }
    else {
      $html->message('err', $_ERROR, "$ERR_WRONG_DATA: IP");
    }
  }

  #Get info from DB
  if ($conf{DHCPHOSTS_LEASES} eq 'db') {
    my %state_hash = (
      'unknown'   => 0,
      'free'      => 1,
      'active'    => 2,
      'abandoned' => 3
    );

    my %state_hash_rev = reverse %state_hash;

    form_search(
      {
        SIMPLE => {
          "$_HOSTS_HOSTNAME" => 'HOSTNAME',
          'IP'               => 'IP',
          'MAC'              => 'HARDWARE',
          "$_EXPIRE"         => 'ENDS',
          'CIRCUIT_ID'       => 'CIRCUIT_ID',
          'REMOTE_ID'        => 'REMOTE_ID',
          'STATE'            => { '' => '', %state_hash_rev }
        },

      }
    );

    my $list = $Dhcphosts->leases_list({%LIST_PARAMS});

    my $table = $html->table(
      {
        width   => '100%',
        caption => "$_HOSTS",
        title   => [ "$_USER", 'IP', "$_START", "MAC", "$_HOSTS", "abandoned", "$_STATE", "$_PORT", "Vlan", "$_MODE", "remote-id", "circuit_id", "-" ],
        cols_align => [ 'left', 'right', 'right', 'right', 'left', 'center:noprint', 'center:noprint', 'center:noprint', 'center:noprint' ],
        ID         => 'MONITOR_DHCP',
        qs         => $pages_qs,
        pages      => $Dhcphosts->{TOTAL},
      }
    );

    foreach my $line (@$list) {
      $table->addrow(
        ($line->[0]) ? $html->button($line->[0], "index=15&UID=$line->[13]") : '',
        $line->[1], $line->[2], $line->[3], $line->[4], $line->[5], $state_hash_rev{ $line->[6] },
        $line->[7], $line->[8], $line->[9], $line->[10], $line->[11], $html->button('P', "index=$index&ping=$line->[1]", { TITLE => 'ping', BUTTON => 1 })
      );
    }
    print $table->show();

    $table = $html->table(
      {
        width      => '100%',
        cols_align => [ 'right', 'right' ],
        rows       => [ [ "$_TOTAL:", $html->b($Dhcphosts->{TOTAL}) ] ]
      }
    );
    print $table->show();

    return 0;
  }

  #Get info from dhcpd.leased
  my $dhcp_hash = leaseparse($conf{DHCPHOSTS_LEASES});

  #Get user info from DB
  $LIST_PARAMS{PAGE_ROWS} = 100000;
  $LIST_PARAMS{IPS} = join(", ", keys %$dhcp_hash);

  my $hosts_list = $Dhcphosts->hosts_list({%LIST_PARAMS});

  my $table = $html->table(
    {
      width   => '100%',
      caption => "$_HOSTS",
      title   => [ "$_USER", 'IP', "$_START", "MAC", "$_HOSTS", "abandoned", "$_STATE", "remote-id", "circuit_id", "-" ],
      cols_align => [ 'left', 'right', 'right', 'right', 'left', 'center:noprint', 'center:noprint', 'center:noprint', 'center:noprint' ],
      ID         => 'MONITOR_DHCP'
    }
  );

  $table->{rowcolor} = $_COLORS[0];
  $table->{extra}    = "colspan='9'";
  $table->addrow("$_TOTAL: $Dhcphosts->{TOTAL}");
  $table->{extra}    = undef;
  $table->{rowcolor} = undef;

  #Get info derect from file
  foreach my $line (@$hosts_list) {
    $table->addrow(
      $html->button("$line->[1]", "index=15&UID=" . $line->[ 13 + $Dhcphosts->{SEARCH_FIELDS_COUNT} ]),
      $line->[11],
      $dhcp_hash->{ $line->[2] }{starts},
      $dhcp_hash->{ $line->[2] }{hardware} || $line->[6],
      $dhcp_hash->{ $line->[2] }{'client-hostname'},
      $dhcp_hash->{ $line->[2] }{abandoned},
      $dhcp_hash->{ $line->[2] }{state},
      $dhcp_hash->{ $line->[2] }{remote_id},
      $dhcp_hash->{ $line->[2] }{circuit_id},
      $html->button('P', "index=$index&ping=$line->[11]", { TITLE => 'ping', BUTTON => 1 }),
    );

    delete $dhcp_hash->{ $line->[2] };
  }

  my @unregistred = sort keys %$dhcp_hash;
  $table->{rowcolor} = $_COLORS[0];
  $table->{extra}    = "colspan='9'";
  $table->addrow("$_NOT_EXIST $_TOTAL: " . ($#unregistred + 1));
  $table->{extra}    = undef;
  $table->{rowcolor} = undef;

  foreach my $ip (@unregistred) {
    $table->addrow(
      '',
      $ip,
      $dhcp_hash->{$ip}{starts},
      $dhcp_hash->{$ip}{hardware},
      $dhcp_hash->{$ip}{'client-hostname'},
      $dhcp_hash->{$ip}{abandoned},
      $dhcp_hash->{$ip}{state},
      $dhcp_hash->{$ip}{remote_id},
      $dhcp_hash->{$ip}{circuit_id},
      $html->button('P', "index=$index&ping=$ip", { TITLE => 'ping', BUTTON => 1 }),

    );
  }

  print $table->show();

}

#*******************************************************************
# Parse dhcpd.leases
#*******************************************************************
sub leaseparse {
  my ($logfile) = @_;
  my (%list, $ip);

  open(FILE, $logfile) or print "Can't read file '$logfile' $!";

  my $state = '';
  while (<FILE>) {
    next if /^#|^$/;

    if (/^lease (\d+\.\d+\.\d+\.\d+)/) {
      $ip = $1;
      $list{$ip}{ip} = sprintf("%s", $ip);
    }

    # $list{$ip}{state} ne 'active' &&
    elsif (/^\s*binding state ([a-zA-Z]{4,6});/) {
      $state = sprintf("%s", $1);
      $list{$ip}{state} = $state if ($state eq 'active');
    }
    elsif (/^\s*client-hostname "(.*)";/) {
      $list{$ip}{'client-hostname'} = sprintf("%s", $1);
    }
    elsif (/^\s*hardware ethernet (.*);/) {
      $list{$ip}{hardware} = $1;
    }

    /^\s*starts \d (.*);/                       && ($list{$ip}{starts}     = sprintf("%-21s", $1));
    /^\s*(abandoned).*/                         && ($list{$ip}{abandoned}  = sprintf("%-19s", $1));
    /^\s*option agent.circuit-id ([a-b0-9:]+);/ && ($list{$ip}{circuit_id} = sprintf("%s",    $1));
    /^\s*option agent.remote-id ([a-b0-9:]+);/  && ($list{$ip}{remote_id}  = sprintf("%s",    $1));
  }

  close FILE;
  return \%list;
}

#*******************************************************************
#
#
#*******************************************************************
sub dhcphosts_networks {
  $Dhcphosts->{ACTION}     = 'add';
  $Dhcphosts->{ACTION_LNG} = $_ADD;

  if ($FORM{NAME} and $FORM{NAME} !~ /^[0-9a-zA-Z_\-]+$/) {
    print $html->message('err', $_ERROR, "$_HOSTS_NETWORKS_NAME - '$FORM{NAME}' $ERR_WRONG_DATA");
    return 0;
  }

  if ($FORM{config}) {
    dhcphosts_config({ NETWORKS => $FORM{IDS} });

    return 0;
  }
  elsif ($FORM{add}) {
    $FORM{ROUTERS} = '0.0.0.0' if (!$FORM{ROUTERS});
    if (
      $FORM{IP_RANGE_FIRST} ne '0.0.0.0'
      && ( ip2int($FORM{IP_RANGE_FIRST}) < ip2int($FORM{NETWORK})
        || ip2int($FORM{IP_RANGE_FIRST}) > ip2int($FORM{NETWORK}) + (ip2int('255.255.255.255') - ip2int($FORM{MASK}))
        || ip2int($FORM{IP_RANGE_LAST}) < ip2int($FORM{NETWORK})
        || ip2int($FORM{IP_RANGE_LAST}) > ip2int($FORM{NETWORK}) + (ip2int('255.255.255.255') - ip2int($FORM{MASK})))
    )
    {
      $html->message('err', $_ERROR, "$ERR_WRONG_RANGE");
    }
    else {
      $Dhcphosts->network_add({%FORM});
      if (!$Dhcphosts->{errno}) {
        $html->message('info', $_ADDED, "$_HOSTS_NETWORKS_NAME [$FORM{NAME}] ");
      }
    }
  }
  elsif ($FORM{change}) {
    $FORM{MASK}           = ip2int($FORM{MASK});
    $FORM{NETWORK}        = ip2int($FORM{NETWORK});
    $FORM{ROUTERS}        = ip2int($FORM{ROUTERS});
    $FORM{IP_RANGE_FIRST} = ip2int($FORM{IP_RANGE_FIRST});
    $FORM{IP_RANGE_LAST}  = ip2int($FORM{IP_RANGE_LAST});

    if (
      $FORM{IP_RANGE_FIRST} > 0
      && ( $FORM{IP_RANGE_FIRST} < $FORM{NETWORK}
        || $FORM{IP_RANGE_FIRST} > $FORM{NETWORK} + (ip2int('255.255.255.255') - $FORM{MASK})
        || $FORM{IP_RANGE_LAST} < $FORM{NETWORK}
        || $FORM{IP_RANGE_LAST} > $FORM{NETWORK} + (ip2int('255.255.255.255') - $FORM{MASK}))
    )
    {
      $html->message('err', $_ERROR, "$ERR_WRONG_RANGE");
    }

    $Dhcphosts->network_change({%FORM});

    if (!$Dhcphosts->{errno}) {
      $html->message('info', $_CHANGED, "$_CHANGED [$FORM{ID}] $FORM{NAME} ");
    }
  }
  elsif ($FORM{chg}) {
    $Dhcphosts->network_info($FORM{chg});

    $Dhcphosts->{ACTION}     = 'change';
    $Dhcphosts->{ACTION_LNG} = $_CHANGE;

    if (!$Dhcphosts->{errstr}) {
      $html->message('info', $_CHANGE, "$_CHANGE [$FORM{chg}] ");
    }
  }
  elsif ($FORM{del} && $FORM{is_js_confirmed}) {
    $Dhcphosts->network_del($FORM{del});
    if (!$Dhcphosts->{errstr}) {
      $html->message('info', $_DELETED, "$_DELETED [$FORM{del}] ");
    }
  }

  if ($Dhcphosts->{errno}) {
    $html->message('err', $_ERROR, "[$Dhcphosts->{errno}] $err_strs{$Dhcphosts->{errno}}");
  }

  $Dhcphosts->{STATIC}               = ' checked' if ($Dhcphosts->{STATIC});
  $Dhcphosts->{DISABLE}              = ' checked' if ($Dhcphosts->{DISABLE});
  $Dhcphosts->{DENY_UNKNOWN_CLIENTS} = ' checked' if ($Dhcphosts->{DENY_UNKNOWN_CLIENTS});
  $Dhcphosts->{AUTHORITATIVE}        = ' checked' if ($Dhcphosts->{AUTHORITATIVE});

  my $net_defaults = $Dhcphosts->network_defaults();

  $Dhcphosts->{PARENT_SEL} = $html->form_select(
    'NET_PARENT',
    {
      SELECTED          => $Dhcphosts->{NET_PARENT},
      SEL_MULTI_ARRAY   => [ [ '', '' ], @{ $Dhcphosts->networks_list({ PARENT => 0 }) } ],
      MULTI_ARRAY_KEY   => 0,
      MULTI_ARRAY_VALUE => 1,
    }
  );

  $html->tpl_show(_include('dhcphosts_network', 'Dhcphosts'), { %$net_defaults, %$Dhcphosts });
  my $list = $Dhcphosts->networks_list({%LIST_PARAMS});

  my $table = $html->table(
    {
      width   => '100%',
      caption => "$_HOSTS_NETWORKS",
      title   => [ '#', "$_HOSTS_NETWORKS_NAME", "$_HOSTS_NETWORKS_NET", "$_HOSTS_NETWORKS_COORDINATOR", "$_HOSTS_NETWORKS_COORDINATOR_PHONE", "$_STATUS", "$_TYPE", "-", "-", '-' ],
      cols_align => [ 'left', 'left', 'left', 'left', 'left', 'center:noprint', 'center:noprint', 'center:noprint', 'center:noprint' ],
      qs         => $pages_qs,
      pages      => $Dhcphosts->{TOTAL},
      ID         => 'DHCP_NETWORKS',
      header     => "<script language=\"JavaScript\" type=\"text/javascript\">
<!-- 
function CheckAllINBOX() {
  for (var i = 0; i < document.dhcp_list.elements.length; i++) {
    if(document.dhcp_list.elements[i].type == 'checkbox' && document.dhcp_list.elements[i].name == 'IDS'){
      document.dhcp_list.elements[i].checked =         !(document.dhcp_list.elements[i].checked);
    }
  }
}
//-->
</script>\n

<div id='tabs'>
<ul class=\"user_menu\">
<li class=\"active\"><a href=\"javascript:void(0)\" onClick=\"CheckAllINBOX();\">$_SELECT_ALL</a></li>
</ul>
</div>\n"
    }
  );

  foreach my $line (@$list) {
    $table->{rowcolor} = ($line->[0] eq $FORM{chg}) ? $_COLORS[0] : undef;
    $table->addrow(
      $line->[0] . $html->form_input('IDS', "$line->[0]", { TYPE => 'checkbox', }),
      $line->[1], $line->[2] . "/" . $line->[3],
      $line->[4], $line->[5],
      $status[ $line->[6] ],
      ($line->[7]) ? "$_SUBNET: $line->[7]" : "$_NETWORK",
      $html->button("$_ROUTES", "index=" . get_function_index('dhcphosts_routes') . "&NET_ID=$line->[0]", { CLASS => 'routes' }),
      $html->button($_CHANGE,   "index=$index&chg=$line->[0]",                                            { CLASS => 'change' }),
      $html->button($_DEL, "index=$index&del=$line->[0]", { MESSAGE => "$_DEL $line->[0]?", CLASS => 'del' }),
    );
  }

  print $html->form_main(
    {
      CONTENT => $table->show(),
      HIDDEN  => { index => $index },
      SUBMIT  => { config => "$_SHOW " . ' dhcpd.conf, ' . $_RECONFIGURE },
      NAME    => 'dhcp_list'
    }
  );

  $table = $html->table(
    {
      width      => '100%',
      cols_align => [ 'right', 'right' ],
      rows       => [ [ "$_TOTAL:", $html->b($Dhcphosts->{TOTAL}) ] ]
    }
  );
  print $table->show();
}

#*******************************************************************
#
#
#*******************************************************************
sub dhcphosts_hosts {

  my $nas_list = $Nas->list();
  if (!$FORM{UID}) {
    $Dhcphosts->{STATUS_SEL} = $html->form_select(
      'STATUS',
      {
        SELECTED => $FORM{STATUS} || '',
        SEL_HASH => {
          '' => "$_ALL",
          0  => "$_ENABLE",
          1  => "$_DISABLE"
        },
        NO_ID => 1
      }
    );

    $Dhcphosts->{NETWORKS_SEL} = dhcphosts_network_sel({ SEARCH => 1 });
    $Dhcphosts->{SWITCH_SEL} = $html->form_select(
      'NAS_ID',
      {
        SELECTED => $Dhcphosts->{NAS_ID} || $FORM{NAS_ID},
        SEL_MULTI_ARRAY => [ [ '', $_ALL ], @$nas_list ],
        MULTI_ARRAY_KEY => 0,
        MULTI_ARRAY_VALUE => 1,
      }
    );

    if ($FORM{MAC}) {
      $FORM{MAC} =~ s/\-/:/g;
    }

    form_search({ SEARCH_FORM => $html->tpl_show(_include('dhcphosts_search', 'Dhcphosts'), 
    	               { %$Dhcphosts, %FORM }, 
    	               { OUTPUT2RETURN => 1 }),
    	            ADDRESS_FORM => 1     
    	         });
  }

  my @TITLE = ('#', "$_USER", "IP", "$_HOSTS_HOSTNAME", "$_HOSTS_NETWORKS_NET", "$_HOSTS_MAC", "$_STATUS", "$_HOSTS_BLOCKTIME", "$_HOSTS_BLOCKED", "-", "-");

  my %NAS_HASH = ();
  if ($FORM{VIEW} && $FORM{VIEW} == 1) {
    @TITLE = ('#', "$_USER", "IP", "$_HOSTS_HOSTNAME", "$_HOSTS_NETWORKS_NET", "$_HOSTS_MAC", "$_STATUS", "$_SWITCH", "VLAN", "$_PORT", "-", "-");
    $LIST_PARAMS{VIEW} = $FORM{VIEW};
    foreach my $line (@$nas_list) {
      $NAS_HASH{ $line->[0] } = $line->[1];
    }
    $pages_qs .= "&VIEW=1";
  }

  my $list  = $Dhcphosts->hosts_list({%LIST_PARAMS});
  my $table = $html->table(
    {
      width      => '100%',
      caption    => "$_HOSTS_USER",
      title      => \@TITLE,
      cols_align => [ 'left', 'left', 'left', 'left', 'left', 'left', 'center:noprint', 'center:noprint' ],
      qs         => $pages_qs,
      pages      => $Dhcphosts->{TOTAL},
      ID         => 'DHCP_HOSTS',
      VIEW       => form_view({ VIEW => { 0 => STANDART, 1 => 'OPTION 82' } })
    }
  );

  foreach my $line (@$list) {
    $status = $line->[10] + $line->[7];
    my $status_color = $_COLORS[9];
    if    ($status == 0) { $status_color = $_COLORS[9]; }
    elsif ($status == 1) { $status_color = $_COLORS[6]; }
    elsif ($status == 2) { $status_color = $_COLORS[6]; }

    if (($line->[ 12 + $Dhcphosts->{SEARCH_FIELDS_COUNT} ] == 1) && $status) {
      $table->{rowcolor} = $_COLORS[0];
    }
    else {
      $table->{rowcolor} = undef;
    }
    my $uid = 0;
    my @arr = ();

    if ($FORM{VIEW}) {
      $status = $line->[6];

      if    ($status == 0) { $status_color = $_COLORS[9]; }
      elsif ($status == 1) { $status_color = $_COLORS[6]; }
      elsif ($status == 2) { $status_color = $_COLORS[6]; }

      $uid = $line->[ 12 + $Dhcphosts->{SEARCH_FIELDS_COUNT} ];
      push @arr, $line->[0], $html->button($line->[1], "index=15&UID=$uid&MODULE=Dhcphosts"), $line->[10], $line->[3], $line->[4], $line->[5], $html->color_mark($status[ $line->[6] ], $status_color), $NAS_HASH{ $line->[7] }, $line->[8], $line->[9];
    }
    else {
      $uid = $line->[ 13 + $Dhcphosts->{SEARCH_FIELDS_COUNT} ];
      push @arr, $line->[0], $html->button($line->[1], "index=15&UID=$uid&MODULE=Dhcphosts"), $line->[11], $line->[3], $line->[5] . ": " . $line->[4], $line->[6], $html->color_mark($status[ $line->[7] ], $status_color), $line->[9], $line->[8];
    }

    $table->addrow(
      @arr,
      $html->button($_CHANGE, "index=" . get_function_index('dhcphosts_user') . "&chg=$line->[0]&MODULE=Dhcphosts&UID=$uid", { CLASS => 'change' }),
      $html->button($_DEL, "index=" . get_function_index('dhcphosts_user') . "&del=$line->[0]&UID=$uid&IP=$line->[11]", { MESSAGE => "$_DEL $line->[0]?", CLASS => 'del' })
    );
  }
  print $table->show();

  $table = $html->table(
    {
      width      => '100%',
      cols_align => [ 'right', 'right' ],
      rows       => [ [ "$_TOTAL:", $html->b($Dhcphosts->{TOTAL}) ] ]
    }
  );
  print $table->show();
}

#**********************************************************
#
#**********************************************************
sub dhcphosts_routes {
  $Dhcphosts->{ACTION}     = 'add';
  $Dhcphosts->{ACTION_LNG} = $_ADD;

  if ($FORM{add}) {
    $Dhcphosts->route_add({%FORM});
    if (!$Dhcphosts->{errno}) {
      $html->message('info', $_ADDED, "$_ADDED [$FORM{SRC}] ");
    }
  }
  elsif ($FORM{change}) {
    $FORM{SRC}    = ip2int($FORM{SRC});
    $FORM{MASK}   = ip2int($FORM{MASK});
    $FORM{ROUTER} = ip2int($FORM{ROUTER});
    $Dhcphosts->route_change({%FORM});

    if (!$Dhcphosts->{errno}) {
      $html->message('info', $_CHANGED, "$_CHANGED [$FORM{ID}] $FORM{SRC} ");
    }
  }
  elsif ($FORM{chg}) {
    $Dhcphosts->route_info($FORM{chg});

    $Dhcphosts->{ACTION}     = 'change';
    $Dhcphosts->{ACTION_LNG} = $_CHANGE;

    if (!$Dhcphosts->{errstr}) {
      $html->message('info', $_CHANGE, "$_CHANGE [$FORM{chg}] ");
    }
  }
  elsif ($FORM{del} && $FORM{is_js_confirmed}) {
    $Dhcphosts->route_del($FORM{del});
    if (!$Dhcphosts->{errstr}) {
      $html->message('info', $_DELETED, "$_DELETED [$FORM{del}] ");
    }
  }

  if ($Dhcphosts->{errno}) {
    $html->message('err', $_ERROR, "[$Dhcphosts->{errno}] $err_strs{$Dhcphosts->{errno}}");
  }

  $html->tpl_show(_include('dhcphosts_routes', 'Dhcphosts'), $Dhcphosts);

  $LIST_PARAMS{NET_ID} = $FORM{NET_ID};
  my $list = $Dhcphosts->routes_list({%LIST_PARAMS});

  my $table = $html->table(
    {
      width      => '100%',
      caption    => "Routes",
      title      => [ '#', "$_HOSTS_NETWORKS_NAME", "$_HOSTS_NETWORKS_NET", "NETMASK", "$_HOSTS_ROUTER", "-", "-" ],
      cols_align => [ 'left', 'left', 'right', 'right', 'right', 'center:noprint', 'center:noprint' ],
      qs         => $pages_qs,
      pages      => $Dhcphosts->{TOTAL},
      ID         => 'DHCPHOSTS_ROUTES'
    }
  );

  foreach my $line (@$list) {
    $table->addrow(
      $line->[0], $line->[1] . ":" . $line->[5],
      $line->[2], $line->[3], $line->[4],
      $html->button($_CHANGE, "index=$index&chg=$line->[0]&NET_ID=" . $FORM{NET_ID}, { CLASS => 'change' }),
      $html->button($_DEL, "index=$index&del=$line->[0]&NET_ID=" . $FORM{NET_ID}, { MESSAGE => "$_DEL $line->[0]?", CLASS => 'del' }),
    );
  }

  print $table->show();

  $table = $html->table(
    {
      width      => '100%',
      cols_align => [ 'right', 'right' ],
      rows       => [ [ "$_TOTAL:", $html->b($Dhcphosts->{TOTAL}) ] ]
    }
  );
  print $table->show();
}

#**********************************************************
#
#**********************************************************
sub dhcphosts_user {
  my ($attr) = @_;

  if ($attr->{ACTION}) {
    $Dhcphosts->{ACTION}     = $attr->{ACTION};
    $Dhcphosts->{ACTION_LNG} = $attr->{LNG_ACTION};
  }
  else {
    $Dhcphosts->{ACTION}     = 'add';
    $Dhcphosts->{ACTION_LNG} = $_ADD;
  }

  if ($FORM{add}) {
    if ($FORM{AUTO_IP} && !$FORM{NETWORK}) {
      $html->message('err', $_ERROR, "$ERR_WRONG_DATA: Select network");
      return 1 if ($attr->{REGISTRATION});
    }
    elsif (($FORM{IP} eq '0.0.0.0' || $FORM{IP} eq '') && $FORM{AUTO_IP} && $FORM{NETWORK}) {
      $FORM{IP} = dhcphosts_get_static_ip($FORM{NETWORK});
    }

    if ($FORM{IP} eq '0.0.0.0' && !$FORM{OPTION_82}) {
      $html->message('err', $_ERROR, "$ERR_WRONG_DATA: IP '0.0.0.0' ");
      return 1 if ($attr->{REGISTRATION});
    }
    elsif ($FORM{MAC} !~ /[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}/i) {
      $html->message('err', $_ERROR, "$ERR_WRONG_DATA: MAC ");
      return 1 if ($attr->{REGISTRATION});
    }
    elsif (!$FORM{HOSTNAME}) {
      $html->message('err', $_ERROR, "$ERR_WRONG_DATA: $_HOSTS_HOSTNAME  ");
      return 1 if ($attr->{REGISTRATION});
    }
    else {
      if (!$FORM{NETWORK}) {
        $FORM{NETWORK} = auto_net_sign($FORM{IP});
      }

      $Dhcphosts->host_check({%FORM});

      if (!$Dhcphosts->{errno} && $FORM{OPTION_82} && $FORM{PORTS} && $FORM{NAS_ID} && !$conf{DHCPHOSTS_O82_USE_MAC}) {
        my $list = $Dhcphosts->hosts_list({ NAS_ID => $FORM{NAS_ID}, PORTS => $FORM{PORTS} });
        if ($Dhcphosts->{TOTAL} > 0) {
          $Dhcphosts->{errno} = 8;
          $Dhcphosts->{LOGIN} = $list->[0][1];
          $Dhcphosts->{UID}   = $list->[0][ 13 + $Dhcphosts->{SEARCH_FIELDS_COUNT} ];

          #my $login = $html->button("$Dhcphosts->{LOGIN}", "index=15&UID=$Dhcphosts->{UID}&MODULE=Dhcphosts");
          #$html->message('err', $_ERROR, "Option 82 $_EXIST NAS: $FORM{NAS_ID} $_PORT: $FORM{PORTS} $login");
        }
      }

      if (!$Dhcphosts->{errno}) {
        $FORM{MAC} = uc($FORM{MAC});
        $Dhcphosts->host_add({%FORM});
        if (!$Dhcphosts->{errno}) {
          $html->message('info', "Dhcp : $_ADDED", "$_ADDED [$FORM{HOSTNAME}] ");
          dhcphosts_config(
            {
              NETWORKS => $FORM{NETWORK},
              reconfig => 1
            }
          );

          # If install Snmputils make make assign
          if (in_array('Snmputils', \@MODULES) && $FORM{NAS_ID}) {
            require "Abills/modules/Snmputils/webinterface";
            my $return = snmputils_periodic({ NAS_IDS => $FORM{NAS_ID}, DEBUG => 1 });
            print $html->message('info', $_INFO, $html->pre($return, { OUTPUT2RETURN => 1 }));
          }

          #Activate IPN Section
          if ($FORM{IPN_ACTIVATE} && $conf{IPN_DHCP_ACTIVE} && in_array('Ipn', \@MODULES)) {
            load_module('Ipn', $html);
            $FORM{ACTIVE} = 1;
            $FORM{NAS_ID} = undef;
            ipn_user_activate({ IP => $FORM{IP} });
          }
        }
        return 0 if ($attr->{REGISTRATION});
      }
    }
  }
  elsif ($FORM{change}) {
    if ($FORM{IP} eq '0.0.0.0' && $FORM{AUTO_IP} && $FORM{NETWORK}) {
      $FORM{IP} = dhcphosts_get_static_ip($FORM{NETWORK});
    }

    if ($FORM{MAC} !~ /[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}/i) {
      $html->message('err', $_ERROR, "WRONG MAC ");
    }
    else {
      if (!$FORM{NETWORK}) {
        $FORM{NETWORK} = auto_net_sign($FORM{IP});
      }

      $Dhcphosts->host_check({%FORM});
      if (!$Dhcphosts->{errno} && $FORM{OPTION_82} && $FORM{PORTS} && $FORM{NAS_ID} && !$conf{DHCPHOSTS_O82_USE_MAC}) {
        my $list = $Dhcphosts->hosts_list(
          {
            NAS_ID => $FORM{NAS_ID},
            PORTS  => $FORM{PORTS}
          }
        );
        if ($Dhcphosts->{TOTAL} > 0 && $FORM{ID} != $list->[0][0]) {
          $Dhcphosts->{errno} = 8;
          $Dhcphosts->{LOGIN} = $list->[0][1];
          $Dhcphosts->{UID}   = $list->[0][ 13 + $Dhcphosts->{SEARCH_FIELDS_COUNT} ];
        }
      }

      if (!$Dhcphosts->{errno}) {
        $Dhcphosts->host_change({%FORM});

        if (!$Dhcphosts->{errno}) {
          $html->message('info', $_CHANGED, "$_CHANGED [$FORM{ID}] $FORM{NAME} ");
          dhcphosts_config({ NETWORKS => $FORM{NETWORK}, reconfig => 1 });

          # If install Snmputils make make assign
          if (in_array('Snmputils', \@MODULES) && $FORM{NAS_ID}) {
            require "Abills/modules/Snmputils/webinterface";
            my $return = snmputils_periodic({ NAS_IDS => $FORM{NAS_ID}, DEBUG => 1 });
            print $html->message('info', $_INFO, $html->pre($return, { OUTPUT2RETURN => 1 }));
          }

        }
      }
    }
  }
  elsif ($FORM{chg}) {
    $Dhcphosts->host_info($FORM{chg});
    $FORM{NETWORK}           = $Dhcphosts->{NETWORK};
    $Dhcphosts->{ACTION}     = 'change';
    $Dhcphosts->{ACTION_LNG} = $_CHANGE;

    if (!$Dhcphosts->{errstr}) {
      $html->message('info', $_CHANGE, "$_CHANGE [$FORM{chg}] ");
    }
  }
  elsif ($FORM{del} && $FORM{is_js_confirmed}) {

    # If install Snmputils make make assign
    if (in_array('Snmputils', \@MODULES)) {
      $Dhcphosts->host_info($FORM{del});
    }

    $Dhcphosts->host_del({ ID => $FORM{del} });

    if (!$Dhcphosts->{errstr}) {
      $html->message('info', $_DELETED, "$_DELETED [$FORM{del}] ");

      $FORM{NETWORK} = auto_net_sign($FORM{IP});
      dhcphosts_config(
        {
          NETWORKS => $FORM{NETWORK},
          reconfig => 1
        }
      );

      if (in_array('Snmputils', \@MODULES)) {
        if ($Dhcphosts->{NAS_ID}) {
          require "Abills/modules/Snmputils/webinterface";
          my $return = snmputils_periodic({ NAS_IDS => $Dhcphosts->{NAS_ID}, DEBUG => 1 });
          print $html->message('info', "SNMP", $html->pre($return, { OUTPUT2RETURN => 1 }));
        }
      }
    }
  }

  if ($Dhcphosts->{errno}) {
    if ($Dhcphosts->{errno} == 17) {
      $html->message('err', $_ERROR, "# $FORM{NETWORK} $ERR_WRONG_NETWORK");
    }
    elsif ($Dhcphosts->{errno} == 7) {
      my %SEARCH_PARAMS = ();

      if ($FORM{IP} eq '0.0.0.0') {
        $SEARCH_PARAMS{MAC} = $FORM{MAC};
      }
      else {
        $SEARCH_PARAMS{IP} = $FORM{IP};
      }

      my $list = $Dhcphosts->hosts_list(\%SEARCH_PARAMS);

      my $login = '';
      if ($Dhcphosts->{TOTAL} > 0) {
        $login = $html->button("$list->[0][1]", "index=15&UID=" . $list->[0][ 13 + $Dhcphosts->{SEARCH_FIELDS_COUNT} ] . "&MODULE=Dhcphosts"),;
      }

      $html->message('err', $_ERROR, "[7] $_EXIST $FORM{IP}/$FORM{MAC} $login");
    }
    elsif ($Dhcphosts->{errno} == 8) {
      my $login = $html->button("$Dhcphosts->{LOGIN}", "index=15&UID=$Dhcphosts->{UID}&MODULE=Dhcphosts");
      $html->message('err', $_ERROR, "Option 82 $_EXIST NAS: $FORM{NAS_ID} $_PORT: $FORM{PORTS} $login");
    }
    else {
      $html->message('err', $_ERROR, "[$Dhcphosts->{errno}] $err_strs{$Dhcphosts->{errno}}");
    }
    return 1 if ($attr->{REGISTRATION});
  }

  $Dhcphosts->{NETWORKS_SEL} = dhcphosts_network_sel({ AUTOSIGN => 1 });
  $Dhcphosts->{STATUS_SEL} = $html->form_select(
    'STATUS',
    {
      SELECTED => $FORM{STATUS},
      SEL_HASH => {
        0  => "Not Set",
        -1 => $_DISABLE,
        1  => "$_ENABLE"
      }
    }
  );

  $Dhcphosts->{DISABLE} = ' checked' if ($Dhcphosts->{DISABLE});
  if ($Dhcphosts->{IPN_ACTIVATE}) {
    $Dhcphosts->{IPN_ACTIVATE} = ' checked';
    if ($Dhcphosts->{IP} ne '0.0.0.0') {
      use Dv_Sessions;
      my $Sessions = Dv_Sessions->new($db, $admin, \%conf);
      my $list = $Sessions->online({ FRAMED_IP_ADDRESS => $Dhcphosts->{IP} });
      if ($Sessions->{TOTAL}) {
        $Dhcphosts->{IPN_ACTIVATE_BUTTON} = $html->color_mark('Online', '#00FF00');
      }
      else {
        $Dhcphosts->{IPN_ACTIVATE_BUTTON} = $html->button($_ACTIVATE, "UID=$FORM{UID}&ACTIVE=1&REMOTE_ADDR=$Dhcphosts->{IP}&index=" . get_function_index('ipn_user_activate'), { BUTTON => 1 });
      }
    }
  }

  if (!$Dhcphosts->{OPTION_82}) {

    #$Dhcphosts->{INPUT_STATE}=" DISABLED STYLE='background-color: $_COLORS[3]'";
    $Dhcphosts->{OPTION_82} = '';
  }
  else {
    $Dhcphosts->{OPTION_82} = ' checked';
  }

  $Dhcphosts->{SWITCH_SEL} = $html->form_select(
    'NAS_ID',
    {
      SELECTED => $Dhcphosts->{NAS_ID} || $FORM{NAS_ID},
      SEL_MULTI_ARRAY => [ [ '', $_ALL ], @{ $Nas->list() } ],
      MULTI_ARRAY_KEY => 0,
      MULTI_ARRAY_VALUE => 1,
    }
  );

  $Dhcphosts->{NAS_SEL} = $html->form_select(
    'NAS_ID',
    {
      POPUP_WINDOW => 'form_nas_search',

      #SELECTED          => $Dhcphosts->{NAS_ID} || $FORM{NAS_ID},
      #SEL_MULTI_ARRAY   => [['', $_ALL], @{ $Nas->list() } ],
      #MULTI_ARRAY_KEY   => 0,
      #MULTI_ARRAY_VALUE => 1,
    }
  );

  dhcphosts_hosts();

  my $nas_index = get_function_index('form_nas');
  if ($nas_index) {
    $Dhcphosts->{NAS_BUTTON} = $html->button($_INFO, "&index=$nas_index&NAS_ID=$Dhcphosts->{NAS_ID}", { CLASS => 'show rightAlignText' });
  }

  my $network_index = get_function_index('dhcphosts_networks');
  if ($network_index) {
    $Dhcphosts->{NETWORK_BUTTON} = $html->button($_INFO, "&index=$network_index&chg=$Dhcphosts->{NETWORK}", { CLASS => 'show rightAlignText' });
  }

  $html->tpl_show(
    _include('dhcphosts_host', 'Dhcphosts'),
    {
      %{ $Dhcphosts->host_defaults() },
      HOSTNAME => $users->{LOGIN} . (($Dhcphosts->{TOTAL}) ? '_' . ($Dhcphosts->{TOTAL} + 1) : ''),
      %FORM,
      %$attr,
      %$Dhcphosts,
    }
  );

  #dhcphosts_hosts();
}

#**********************************************************
# Get static ip from pool
# form_tp
#**********************************************************
sub dhcphosts_get_static_ip {
  my ($network_id) = @_;
  my $ip = '0.0.0.0';

  my $nas = Nas->new($db, \%conf);

  $Dhcphosts->network_info($network_id);

  my $start_ip = ip2int($Dhcphosts->{IP_RANGE_FIRST});
  my $end_ip   = ip2int($Dhcphosts->{IP_RANGE_LAST});

  if ($start_ip == 0 || $end_ip == 0) {
    $html->message('err', $_ERROR, "$ERR_WRONG_RANGE. $_START IP: $Dhcphosts->{IP_RANGE_FIRST} $_END IP: $Dhcphosts->{IP_RANGE_LAST}");
  }
  else {
    my %users_ips = ();

    my $list = $Dhcphosts->hosts_list(
      {    #NETWORK   => $network_id,
        PAGE_ROWS => 100000
      }
    );

    foreach my $line (@$list) {
      $users_ips{ $line->[2] } = 1;
    }

    for (my $ip_cur = $start_ip ; $ip_cur <= $end_ip ; $ip_cur++) {
      if (!$users_ips{$ip_cur}) {
        return int2ip($ip_cur);
      }
    }
    $html->message('err', $_ERROR, "$ERR_NO_FREE_IP_IN_POOL");
  }

  return $ip;
}

#**********************************************************
#
#**********************************************************
sub dhcphosts_network_sel {
  my ($attr) = @_;

  my $list = $Dhcphosts->networks_list({ PAGE_ROWS => 10000, SORT => 2 });
  if ($Dhcphosts->{errno}) {
    print $html->message('err', $_ERROR, "[$Hosts->{errno}] $err_strs{$Hosts->{errno}}");
    return 0;
  }

  my %networks = ();

  $networks{0} = "$_ALL"  if ($attr->{SEARCH});
  $networks{0} = "$_AUTO" if ($attr->{AUTOSIGN});

  foreach my $line (@$list) {
    my $autoselect = ($line->[9]) ? " $_AUTO IP" : '';
    $networks{ $line->[0] } = $line->[1] . "(" . $line->[2] . "/" . $line->[3] . ") $autoselect";
  }

  return $html->form_select(
    'NETWORK',
    {
      SELECTED => $FORM{NETWORK} || 0,
      SEL_HASH => \%networks
    }
  );

}

#**********************************************************
#
#**********************************************************
sub dhcphosts_config {
  my ($attr) = @_;

  if (!$attr->{NETWORKS}) {
    $html->message('err', $_ERROR, "$ERR_WRONG_DATA. Select NETWORK ");
    return 0;
  }

  my %INFO     = ();
  my %NAS_MACS = ();

  # Nas CSI
  my $nas_list = $Nas->list();

  foreach my $line (@$nas_list) {
    if ($line->[15]) {
      $NAS_MACS{ $line->[0] } = "$line->[1],$line->[15]";
    }
    elsif ($line->[12] =~ /Called-Station-Id=[\"\'](.+)[\'\"]/i) {
      $NAS_MACS{ $line->[0] } = "$line->[1],$1";
    }
  }

  my $list = $Dhcphosts->networks_list(
    {
      DISABLE   => 0,
      PAGE_ROWS => 10000,
      SORT      => 2
    }
  );

  my %SUBNETS = ();

  foreach my $line (@$list) {
    my $NET_ID = $line->[0];
    my %curnet = ();
    $INFO{OPTION82_POOLS} = '';
    $Dhcphosts->network_info($NET_ID);

    $INFO{DNS} = ($Dhcphosts->{DNS}) ? "option domain-name-servers $Dhcphosts->{DNS}" : undef;
    $INFO{DNS} .= ",$Dhcphosts->{DNS2}" if ($Dhcphosts->{DNS2});
    $INFO{DNS} .= ';' if ($INFO{DNS});
    $INFO{NTP} = "option ntp-servers $Dhcphosts->{NTP};" if ($Dhcphosts->{NTP});

    $INFO{DOMAINNAME} = ($Dhcphosts->{DOMAINNAME}) ? "option domain-name \"$Dhcphosts->{DOMAINNAME}\";" : undef;

    $INFO{ROUTERS} = ($Dhcphosts->{ROUTERS} ne '0.0.0.0') ? "option routers $Dhcphosts->{ROUTERS};" : '';
    $INFO{DATETIME} = "$DATE $TIME / Dhcphosts";

    $INFO{NETWORK_ID}    = $Dhcphosts->{ID};
    $INFO{NETWORK_NAME}  = $Dhcphosts->{NAME} || 'NETWORK_NAME';
    $INFO{BLOCK_NETWORK} = $Dhcphosts->{BLOCK_NETWORK};
    $INFO{BLOCK_MASK}    = $Dhcphosts->{BLOCK_MASK};
    $INFO{NETWORK}       = $Dhcphosts->{NETWORK};
    $INFO{NETWORK_MASK}  = $Dhcphosts->{MASK};
    $INFO{DESCRIBE}      = $Dhcphosts->{NAME};

    $INFO{DESCRIBE}             = $Dhcphosts->{COMMENTS};
    $INFO{AUTHORITATIVE}        = ($Dhcphosts->{AUTHORITATIVE}) ? 'authoritative;' : '';
    $INFO{DENY_UNKNOWN_CLIENTS} = ($Dhcphosts->{DENY_UNKNOWN_CLIENTS}) ? 'deny unknown-clients;' : '';

    if (!$Dhcphosts->{STATIC} && $Dhcphosts->{IP_RANGE_FIRST} ne '0.0.0.0') {
      $INFO{RANGE} = "range $Dhcphosts->{IP_RANGE_FIRST} $Dhcphosts->{IP_RANGE_LAST};";
    }
    else {
      $INFO{RANGE} = '';
    }

    #Add static route
    my $list = $Dhcphosts->routes_list({ NET_ID => $NET_ID });
    $INFO{NET_ROUTES}         = '';
    $INFO{NET_ROUTES_RFC3442} = '';
    if ($Dhcphosts->{TOTAL} > 0) {
      my $routes = "";

      foreach my $line (@$list) {
        my $src    = $line->[2];
        my $mask   = $line->[3];
        my $router = $line->[4];

        my @ip  = split(/\./, $src);
        my @ip2 = split(/\./, $router);
        $mask = mask2bitlen($mask);
        $routes .= $mask;

        for (my $i = 0 ; $i < $mask / 8 ; $i++) {
          $routes .= ", $ip[$i]";
        }
        $routes .= ", " . join(", ", @ip2) . ",\n";
      }

      chop $routes;
      chop $routes;
      $routes .= ";";

      # MS routes: adds extras to supplement routers option
      $INFO{NET_ROUTES} = "option ms-classless-static-routes $routes";

      # RFC3442 routes: overrides routers option
      $INFO{NET_ROUTES_RFC3442} = "option rfc3442-classless-static-routes $routes";
    }

    #Make hosts
    $INFO->{NETWORK} = '';
    $list = $Dhcphosts->hosts_list(
      {
        NETWORK                    => $NET_ID,
        STATUS                     => 0,
        PAGE_ROWS                  => 100000,
        DHCPHOSTS_DEPOSITCHECK     => $conf{DHCPHOSTS_DEPOSITCHECK},
        DHCPHOSTS_EXT_DEPOSITCHECK => $conf{DHCPHOSTS_EXT_DEPOSITCHECK},
        USER_DISABLE               => 0,
        PORTS                      => '*',
        NAS_ID                     => '>=0',
        OPTION_82                  => '>=0',
        VID                        => '>=0',
        BOOT_FILE                  => '*',
        DELETED                    => 0,
        NEXT_SERVER                => '*',
        COLS_NAME                  => 1
      }
    );

    foreach my $host (@$list) {
      my $deposit = $host->{deposit} || 0;

      if (defined($conf{DHCPHOSTS_DEPOSITCHECK}) && $deposit < $conf{DHCPHOSTS_DEPOSITCHECK}) {
        next;
      }
      elsif (defined($conf{DHCPHOSTS_EXT_DEPOSITCHECK}) && $deposit < $conf{DHCPHOSTS_EXT_DEPOSITCHECK}) {
        next;
      }
      else {

      }

      $INFO{LOGIN}      = $host->{login};
      $INFO{CLIENT_MAC} = $host->{mac};
      $INFO{CLIENT_IP}  = $host->{ip};

      #Option 82
      if ($host->{option_82}) {
        $INFO{CLIENT_MAC}        =~ s/^00/0/;
        $INFO{CLIENT_MAC}        =~ s/:0/:/g;
        $INFO{CLIENT_MAC}        = lc($INFO{CLIENT_MAC});
        $INFO{OPTION82_NAS_PORT} = $host->{ports};
        $INFO{CLIENT_VLAN}       = $host->{vid};
        my @OPTION82_MATCHES     = ();

        #Check swich
        if ($NAS_MACS{ $host->{nas} }) {
          ($INFO{OPTION82_NAS_NAME}, $INFO{OPTION82_NAS_MAC}) = split(/,/, $NAS_MACS{ $host->{nas} }, 2);
          if ($INFO{OPTION82_NAS_MAC} =~ /:/) {
            $INFO{OPTION82_NAS_MAC} =~ s/^00/0/;
            $INFO{OPTION82_NAS_MAC} =~ s/:0/:/g;
          }

          $INFO{OPTION82_NAS_MAC} = lc($INFO{OPTION82_NAS_MAC});
          $INFO{OPTION82_NAS_NAME} =~ s/ /\_/g;
          push @OPTION82_MATCHES, "binary-to-ascii(16, 8, \":\", substring(option agent.remote-id, 2, 6)) = \"$INFO{OPTION82_NAS_MAC}\"";
        }
        else {
          print "Can't find NAS '$host->{nas}' MAC: $INFO{CLIENT_MAC} LOGIN: $INFO{LOGIN}\n" if (!$attr->{QUITE} && $host->{nas});
          $INFO{OPTION82_NAS_NAME} = '';
          $INFO{OPTION82_NAS_MAC}  = '';
        }

        #Check nas port
        push @OPTION82_MATCHES, "binary-to-ascii(10, 8, \":\", substring(option agent.circuit-id, 5, 1)) = \"$INFO{OPTION82_NAS_PORT}\"" if ($INFO{OPTION82_NAS_PORT} && $INFO{OPTION82_NAS_PORT} > 0);

        #Client MAC
        push @OPTION82_MATCHES, "binary-to-ascii (16, 8, \":\", substring(hardware, 1, 7))=\"$INFO{CLIENT_MAC}\"" if ($INFO{CLIENT_MAC} ne '0:0:0:0:0:0' && $conf{DHCPHOSTS_O82_USE_MAC});

        #Vlan option
        push @OPTION82_MATCHES, "binary-to-ascii (10, 16, \"\", substring( option agent.circuit-id, 2, 2)) = \"$INFO{CLIENT_VLAN}\" " if ($INFO{CLIENT_VLAN} > 0);

        my $matches = join(' and ', @OPTION82_MATCHES);
        $INFO{DHCPHOSTS_O82_CLASS_NAME} = "$INFO{OPTION82_NAS_NAME}-$INFO{OPTION82_NAS_MAC}-port-$INFO{OPTION82_NAS_PORT}";

        if ($conf{DHCPHOSTS_O82_USE_MAC}) {
          $INFO{OPTION82_CLASS_NAME} .= "-$INFO{CLIENT_MAC}";
        }

        # make custom option 82 tpl
        if ($conf{DHCPHOSTS_O82_CLASS_TPL}) {
          $INFO{OPTION82_CLASS} .= $html->tpl_show(_include('dhcphosts_dhcp_conf_o82_class', 'Dhcphosts'), \%INFO, { OUTPUT2RETURN => 1 });
        }
        else {
          $INFO{OPTION82_CLASS} .= "# LOGIN: $host->{login}\nclass \"$INFO{DHCPHOSTS_O82_CLASS_NAME}\" { match if $matches ;  \n }\n\n";
        }

        $INFO{OPTION82_POOLS} .= "pool { range $host->{ip}; allow members of \"$INFO{DHCPHOSTS_O82_CLASS_NAME}\"; }\n";
      }
      else {
        #Static hosts
        #Skip empty mac or ip
        if ($INFO{CLIENT_MAC} eq '00:00:00:00:00:00' || $INFO{CLIENT_IP} eq '0.0.0.0') {
          next;
        }

        $INFO{HOSTS} .= $html->tpl_show(
          _include('dhcphosts_dhcp_conf_host', 'Dhcphosts',),
          {
            MAC         => $INFO{CLIENT_MAC},
            IP          => $INFO{CLIENT_IP},
            ROUTERS     => ($Dhcphosts->{ROUTERS} ne '0.0.0.0') ? $Dhcphosts->{ROUTERS} : convert_ip("0.0.0.1", '', $Dhcphosts),
            LOGIN       => $host->{login},
            HOSTNAME    => $host->{hostname},
            BOOT_FILE   => ($host->{boot_file}) ? "filename \"" . $host->{boot_file} . "\";"    : '',
            NEXT_SERVER => ($host->{next_server}) ? "next-server \"" . $host->{next_server} . "\";" : '',
          },
          { OUTPUT2RETURN => 1 }
        );
      }
    }

    $SUBNETS{ $line->[7] }{ $line->[0] } .= $html->tpl_show(_include('dhcphosts_dhcp_conf_subnet', 'Dhcphosts'), \%INFO, { OUTPUT2RETURN => 1 });

    $INFO{SUBNETS} .= $html->tpl_show(_include('dhcphosts_dhcp_conf_subnet', 'Dhcphosts'), \%INFO, { OUTPUT2RETURN => 1 });
  }

  $INFO{NETWORKS} = '';
  foreach my $id (sort keys %{ $SUBNETS{0} }) {
    my $net_content = $SUBNETS{0}{$id};
    $INFO{NETWORKS} .= "#share network - $id 
shared-network $INFO{NETWORK_NAME}_$id {	 
$net_content";

    #Add subnets
    while (my ($id_sub, $subnet_content) = each %{ $SUBNETS{$id} }) {
      $INFO{NETWORKS} .= "\n #SUBNET $id_sub\n $subnet_content";
    }

    $INFO{NETWORKS} .= "}
#========================\n";
  }

  $conf{DHCPHOSTS_CONFIG} = "/usr/local/etc/dhcpd.conf" if (!$conf{DHCPHOSTS_CONFIG});
  $INFO{LEASES_FILE} = ($conf{DHCPHOSTS_LEASES} && $conf{DHCPHOSTS_LEASES} ne 'db') ? "lease-file-name \"$conf{DHCPHOSTS_LEASES}\";" : "lease-file-name \"/var/db/dhcpd/dhcpd.leases\";";

  if (!$AUTH{dhcp}) {
    if (($attr->{reconfig} || $FORM{reconfig})) {

      my $tpl = $html->tpl_show(_include('dhcphosts_dhcp_conf_main', 'Dhcphosts'), \%INFO, { OUTPUT2RETURN => 1 });

      if (open(FILE, ">$conf{DHCPHOSTS_CONFIG}")) {
        print FILE $tpl;
        close(FILE);
      }
      else {
        print "Can't open file '$conf{DHCPHOSTS_CONFIG}' $!";
        return 0;
      }

      dhcphosts_reconfigure({ DEBUG => $FORM{DEBUG} });
      $html->message('info', $_INFO, "DHCP $_RECONFIGURE '$conf{DHCPHOSTS_CONFIG}'") if (!$attr->{QUITE});
    }
    else {
      my $conf_content = $html->tpl_show(_include('dhcphosts_dhcp_conf_main', 'Dhcphosts'), \%INFO, { OUTPUT2RETURN => 1 });

      print "$conf{DHCPHOSTS_CONFIG}<br><textarea cols=90 rows=20>$conf_content</textarea>\n";
      print $html->form_main(
        {
          HIDDEN => {
            index  => $index,
            IDS    => $FORM{IDS},
            config => 'dhcp.conf'
          },
          SUBMIT => { reconfig => $_RECONFIGURE }
        }
      );
    }
  }
}

#**********************************************************
# Get bit count from net mask
#**********************************************************
sub dhcphosts_reconfigure {
  my ($attr) = @_;

  my $debug = $attr->{DEBUG} || 0;

  if (!$conf{DHCPHOSTS_RECONFIGURE}) {
    print $html->message('err', $_ERROR, "Can't find reconfiguration command " . '"$conf{DHCPHOSTS_RECONFIGURE}"');
    return 0;
  }

  dhcphosts_mac_block_make();

  open STDERR, '/dev/null';
  my $res = `$conf{DHCPHOSTS_RECONFIGURE}`;
  print $res if ($debug > 2);

  return 0;
}

#**********************************************************
#
#**********************************************************
sub convert_ip {
  my ($cid, $blocked, $attr) = @_;

  if (!$Dhcphosts->{NETWORK}) {
    $Dhcphosts->network_info($net_id);
  }

  my @ip = split(/\./, $cid);
  my @ip2 = ();
  if ($blocked) {
    @ip2 = split(/\./, $Dhcphosts->{BLOCK_NETWORK});
  }
  else {
    @ip2 = split(/\./, $Dhcphosts->{NETWORK});
  }

  return "$ip2[0].$ip2[1].$ip2[2].$ip[3]";
}

#**********************************************************
# Get bit count from net mask
#**********************************************************
sub mask2bitlen {
  my ($netmask) = @_;

  my @mask = split(/\./, $netmask, 4);
  my $bitlen = 0;
  foreach my $line (@mask) {
    my $bits = sprintf("%b", $line);
    $bits =~ s/0//g;
    $bitlen += length($bits);
  }
  return $bitlen;
}

#**********************************************************
# http://rfc3442svc.sourceforge.net/isc-dhcpd-configuration.html
#
# For isc-dhcpd
#  dhcpd.conf
#
#  option classless-route code 121 = string;
#  option classless-route-xp code 249 = string;
#  option classless-route  16:0a:0b:00:c0:a8:32:01:14:c0:a8:50:c0:a8:32:01:17:c0:a8:5a:c0:a8:32:01:20:0a:0a:0a:0a:c0:a8:32:02:14:c0:a8:00:c0:a8:32:01;
#  option classless-route-xp 16:0a:0b:00:c0:a8:32:01:14:c0:a8:50:c0:a8:32:01:17:c0:a8:5a:c0:a8:32:01:20:0a:0a:0a:0a:c0:a8:32:02:14:c0:a8:00:c0:a8:32:01;
#**********************************************************
sub make_classless_option {
  my $routes = shift;
  my ($s1, $s2, $s3, $s4, $len, @bytes, $net, $mask, $destination, $router);

  $len   = 2;
  @bytes = ();
  foreach $destination (keys %{$routes}) {
    ($net, $mask) = split('/', $destination);
    $router = $routes->{$destination};
    ($s1, $s2, $s3, $s4) = split(/\./, $net);
    push(@bytes, sprintf('%02x', $mask));
    push(@bytes, sprintf('%02x', $s1));
    push(@bytes, sprintf('%02x', $s2)) if ($mask > 8);
    push(@bytes, sprintf('%02x', $s3)) if ($mask > 16);
    push(@bytes, sprintf('%02x', $s4)) if ($mask > 24);
    ($s1, $s2, $s3, $s4) = split(/\./, $router);
    push(@bytes, sprintf('%02x', $s1));
    push(@bytes, sprintf('%02x', $s2));
    push(@bytes, sprintf('%02x', $s3));
    push(@bytes, sprintf('%02x', $s4));
  }

  return join(':', @bytes);
}

#**********************************************************
#
#**********************************************************
sub auto_net_sign {
  my ($ip) = @_;

  my %network_hash = ();
  my $list = $Dhcphosts->networks_list({ PAGE_ROWS => 10000 });
  $ip = ip2int($ip);

  foreach my $line (@$list) {
    my $first_ip = ip2int($line->[2]);
    my $last_ip = $first_ip + (4294967295 - ip2int($line->[3]));
    $network_hash{$first_ip} = "$last_ip:$line->[0]";
  }

  while (my ($first, $v) = each %network_hash) {
    my ($last, $id) = split(/:/, $v, 2);
    if ($ip >= $first && $ip <= $last) {
      return $id;
    }
  }

  return 0;
}

#**********************************************************
#
#**********************************************************
sub dhcphosts_log_clean {

  $Dhcphosts->log_del({ DAYS_OLD => $conf{DHCPHOSTS_LOG_CLEAN_DAYS} || 30 });
}

#**********************************************************
#
#**********************************************************
sub dhcphosts_log {

  my %DHCP_MESSAGE_TYPES = (
    DHCPDISCOVER        => 1,
    DHCPOFFER           => 2,
    DHCPREQUEST         => 3,
    DHCPDECLINE         => 4,
    DHCPACK             => 5,
    DHCPNAK             => 6,
    DHCPRELEASE         => 7,
    DHCPINFORM          => 8,
    DHCPLEASEQUERY      => 10,
    DHCPLEASEUNASSIGNED => 11,
    DHCPLEASEUNKNOWN    => 12,
    DHCPLEASEACTIVE     => 13
  );

  my %DHCP_MESSAGE_TYPES_REV = reverse %DHCP_MESSAGE_TYPES;

  if (!$FORM{sort}) {
    $LIST_PARAMS{SORT} = 1;
    $LIST_PARAMS{DESC} = 'desc';
  }

  #   if ($FORM{UID})  {
  #   	  my @macs_arr = '';
  #   	  my $list = $Dhcphosts->hosts_list({ UID => $FORM{UID} });
  #   	  foreach my $line  (@$list) {
  #   	  	push @macs_arr, $line->[6];
  #   	   }
  #      $LIST_PARAMS{MESSAGE}=join(';', @macs_arr);
  #    }

  $Dhcphosts->{MESSAGE_TYPE_SEL} = $html->form_select(
    'MESSAGE_TYPE',
    {
      SELECTED => $FORM{MESSAGE_TYPE},
      SEL_HASH => {
        '' => $_ALL,
        %DHCP_MESSAGE_TYPES_REV
      },
      NO_ID => 1
    }
  ),

  form_search({ SEARCH_FORM => $html->tpl_show(_include('dhcphosts_log_search', 'Dhcphosts'), 
  	          { %FORM, %$Dhcphosts }, 
  	          { OUTPUT2RETURN => 1 }) 
  	         });

  if ($FORM{search}) {
    $FORM{MESSAGE} =~ s/\-/:/g;
    $FORM{MESSAGE} =~ s/\*//g;
    push @{ $Dhcphosts->{IDS} }, $FORM{MESSAGE};
  }

  if ($FORM{MESSAGE_TYPE}) {
    $LIST_PARAMS{MESSAGE_TYPE} = $FORM{MESSAGE_TYPE};
  }

  my $list  = $Dhcphosts->log_list({%LIST_PARAMS});
  my $table = $html->table(
    {
      width      => '100%',
      caption    => "$_LOG",
      title      => [ "$_DATE $_TIME", "HOSTNAME", "$_MESSAGE $_TYPE", "$_MESSAGE", "-" ],
      cols_align => [ 'right', 'left', 'left', 'left', 'center:noprint' ],
      ID         => 'DHCP_LOG',
      qs         => $pages_qs,
      pages      => $Dhcphosts->{TOTAL},
    }
  );

  foreach my $line (@$list) {
    $table->addrow($line->[0], $line->[1], $DHCP_MESSAGE_TYPES_REV{ $line->[2] }, color_marks($line->[3], $Dhcphosts->{IDS}),);
  }
  print $table->show();

  $table = $html->table(
    {
      width      => '100%',
      cols_align => [ 'right', 'right' ],
      rows       => [ [ "$_TOTAL:", $html->b($Dhcphosts->{TOTAL}) ] ]
    }
  );
  print $table->show();
}

#**********************************************************
#
#**********************************************************
sub color_marks {
  my ($message, $ids) = @_;

  foreach my $id (@{$ids}) {
    my $replace = $html->b($id);
    $message =~ s/\s+$id\s+/ $replace /g;
  }

  return $message;
}

#**********************************************************
#
#**********************************************************
sub dhcphosts_payments_maked {
  my ($attr) = @_;
  my $deposit = $attr->{USER_INFO}->{DEPOSIT} + $attr->{USER_INFO}->{CREDIT};

  #  if ($deposit > 0) {
  my %NETWORKS = ();
  my %NAS_IDS  = ();

  my $list = $Dhcphosts->hosts_list({ UID => $attr->{USER_INFO}->{UID}, STATUS => 0, NAS_ID => '>0' });
  foreach my $line (@$list) {
    $NETWORKS{ $line->[5] } = 1;
    $NAS_IDS{ $line->[ 11 + $Dhcphosts->{SEARCH_FIELDS_COUNT} ] } = 1;
  }

  if (in_array('Snmputils', \@MODULES)) {
    if (scalar(keys %NAS_IDS) > 0) {
      require "Abills/modules/Snmputils/webinterface";
      my $return = snmputils_periodic({ NAS_IDS => join(',', keys %NAS_IDS), DEBUG => 0 });
      if ($return ne '' && !$attr->{QUITE}) {
        $html->message('info', "SNMP", $html->pre($return, { OUTPUT2RETURN => 1 }));
      }
    }
  }
  if (scalar(keys %NETWORKS) > 0) {
    dhcphosts_config(
      {
        NETWORKS => join(',', keys %NETWORKS),
        reconfig => 1,
        %$attr
      }
    );
  }

  #	 }
}

1
