#
# SMArT
#
# Handle /settings/ requests
#
# Copyright 2001 Wilmer van der Gaast (lintux@lintux.cx)
#
#
# 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
#
#
sub html_escape( $ )
{
my $s = $_[0];
$s = '' unless defined $s;
$s =~ s/&/&/g;
$s =~ s/</g;
$s =~ s/>/>/g;
$s =~ s/"/"/g;
return $s;
}
sub settings_nav_bar()
{
return <<'EOF_NAV';
EOF_NAV
}
sub delete_confirm_attr( $ )
{
my $what = html_escape( $_[0] );
return ' onclick="return confirm(\'Delete ' . $what . '?\')"';
}
$settings_nav_bar = settings_nav_bar();
sub kernel_network_interfaces()
{
my %interfaces = ();
if( opendir( my $dh, '/sys/class/net' ) )
{
foreach my $ifname ( readdir( $dh ) )
{
next if $ifname =~ /^\./;
next if $ifname =~ /[^-_\.A-Za-z0-9]/;
$interfaces{$ifname} = 1;
}
closedir( $dh );
}
return %interfaces;
}
sub ipx_enabled_interfaces()
{
my %ipx_interfaces = ();
# Modern Linux IPX procfs format:
# Network Node_Address Primary Device Frame_Type
# AC100B98 000000000001 Yes Internal None
# 00000022 508140F6AC45 No enp46s0u1u3u3 802.2
if( open( my $fh, '<', '/proc/net/ipx/interface' ) )
{
while( my $line = <$fh> )
{
chomp( $line );
$line =~ s/^\s+//;
$line =~ s/\s+$//;
next if $line eq '';
next if $line =~ /^Network\s+Node_Address\s+Primary\s+Device\s+Frame_Type/i;
my @fields = split( /\s+/, $line );
# Device is the fourth column. Do not scan all tokens, otherwise
# Network/Node/Frame_Type values can accidentally be treated as names.
next if scalar( @fields ) < 5;
my $dev = $fields[3];
next if ! defined( $dev );
next if $dev eq '';
next if lc( $dev ) eq 'internal';
next if $dev =~ /[^-_\.A-Za-z0-9]/;
# Only show real Linux network interfaces.
next if ! -e '/sys/class/net/' . $dev;
$ipx_interfaces{$dev} = 1;
}
close( $fh );
}
# Fallback for older distributions/tools, if present. This parser is kept
# deliberately conservative and still verifies /sys/class/net/.
if( open( my $fh, '<', '/proc/net/ipx_interfaces' ) )
{
while( my $line = <$fh> )
{
chomp( $line );
$line =~ s/^\s+//;
$line =~ s/\s+$//;
next if $line eq '';
next if $line =~ /^(Network|Net|Address|Node|Interface|Device)\b/i;
foreach my $dev ( split( /\s+/, $line ) )
{
next if ! defined( $dev );
next if $dev eq '';
next if lc( $dev ) eq 'internal';
next if $dev =~ /[^-_\.A-Za-z0-9]/;
next if ! -e '/sys/class/net/' . $dev;
$ipx_interfaces{$dev} = 1;
}
}
close( $fh );
}
return sort keys %ipx_interfaces;
}
sub network_interface_options( $ )
{
my $current = $_[0];
my @interfaces = ();
my %seen = ();
my $html = '';
$current = '' unless defined $current;
# Only show interfaces where IPX is currently active. The current value is
# still preserved below, so an existing config entry is not lost if the
# interface is temporarily down or IPX is not loaded at display time.
foreach my $ifname ( ipx_enabled_interfaces() )
{
next if $seen{$ifname};
push( @interfaces, $ifname );
$seen{$ifname} = 1;
}
# Keep special/manual values usable even if they are not real kernel interfaces.
foreach my $ifname ( '*', 'auto', $current )
{
next if !defined( $ifname ) || $ifname eq '';
next if $seen{$ifname};
push( @interfaces, $ifname );
$seen{$ifname} = 1;
}
foreach my $ifname ( @interfaces )
{
my $selected = ( $ifname eq $current ) ? ' SELECTED' : '';
my $label = $ifname;
$label = '* (all IPX interfaces)' if $ifname eq '*';
$label = 'auto' if $ifname eq 'auto';
$html .= '\t\t\t\t' . html_escape( $label ) . ' \n';
}
return $html;
}
sub url_escape( $ )
{
my $s = $_[0];
$s = '' unless defined $s;
$s =~ s/([^A-Za-z0-9_\.\-])/sprintf("%%%02X", ord($1))/eg;
return $s;
}
sub js_escape( $ )
{
my $s = $_[0];
$s = '' unless defined $s;
$s =~ s/\\/\\\\/g;
$s =~ s/'/\\'/g;
$s =~ s/\r/\\r/g;
$s =~ s/\n/\\n/g;
return $s;
}
sub smart_find_executable( @ )
{
foreach my $p ( @_ )
{
next if ! defined( $p ) || $p eq '';
return $p if -x $p;
}
return '';
}
sub sanitize_cups_printer_name( $ )
{
my $s = $_[0];
$s = '' unless defined $s;
$s =~ s/[^-_\.A-Za-z0-9]//g;
return $s;
}
sub cups_queue_name( $ )
{
my $s = sanitize_cups_printer_name( $_[0] );
$s = uc( $s );
$s =~ s/[^A-Z0-9_\-]/_/g;
$s = 'PRINTQ' if $s eq '';
$s = substr( $s, 0, 47 );
return $s;
}
sub cups_print_command( $ )
{
my $printer = sanitize_cups_printer_name( $_[0] );
my $template = $smart_cups_print_command_template;
$template = '/usr/bin/lp -d %p -' unless defined( $template ) && $template ne '';
$template =~ s/%p/$printer/g;
return $template;
}
sub cups_printers()
{
return () unless defined( $smart_cups_enable ) && $smart_cups_enable;
my %printers = ();
my $lpstat = smart_find_executable(
$smart_cups_lpstat_path,
'/usr/bin/lpstat',
'/bin/lpstat'
);
return () if $lpstat eq '';
if( open( my $fh, '-|', $lpstat, '-v' ) )
{
while( my $line = <$fh> )
{
chomp( $line );
if( $line =~ /^device\s+for\s+([^:\s]+):/i )
{
my $printer = sanitize_cups_printer_name( $1 );
$printers{$printer} = 1 if $printer ne '';
}
}
close( $fh );
}
if( scalar( keys( %printers ) ) == 0 )
{
if( open( my $fh, '-|', $lpstat, '-p' ) )
{
while( my $line = <$fh> )
{
chomp( $line );
if( $line =~ /^printer\s+(\S+)/i )
{
my $printer = sanitize_cups_printer_name( $1 );
$printers{$printer} = 1 if $printer ne '';
}
}
close( $fh );
}
}
return sort( keys( %printers ) );
}
sub cups_import_rows()
{
my $html = '';
my @printers = cups_printers();
return '' if scalar( @printers ) == 0;
$html .= qq|\t\n\t\tCUPS printers detected on host \n\t \n|;
foreach my $printer ( @printers )
{
my $queue = cups_queue_name( $printer );
my $cmd = cups_print_command( $printer );
my $href = '/settings/queues/add_new?cups_printer=' . url_escape( $printer );
$html .= "\t\n";
$html .= "\t\t" . html_escape( $printer ) . " Queue: " . html_escape( $queue ) . " Command: " . html_escape( $cmd ) . " \n";
$html .= "\t\tAdd as print queue \n";
$html .= "\t \n";
}
return $html;
}
sub cups_select_html( $ )
{
my $current = sanitize_cups_printer_name( $_[0] );
my @printers = cups_printers();
my $html = '';
my $js = '';
return ( '', '' ) if scalar( @printers ) == 0;
$html .= qq|\n|;
$html .= qq|\t\t\t\t-- choose CUPS printer -- \n|;
foreach my $printer ( @printers )
{
my $sel = ( $printer eq $current ) ? ' SELECTED' : '';
$html .= qq|\t\t\t\t| . html_escape( $printer ) . qq| \n|;
$js .= "smartCupsCommands['" . js_escape( $printer ) . "'] = '" . js_escape( cups_print_command( $printer ) ) . "';\n";
$js .= "smartCupsQueues['" . js_escape( $printer ) . "'] = '" . js_escape( cups_queue_name( $printer ) ) . "';\n";
}
$html .= qq|\t\t\t |;
return ( $html, $js );
}
sub handle_request()
{
if( $c[1] eq 'general' )
{
$server_name = getconfigline( 2 );
$internal_net = getconfigline( 3 );
( $burst_read, $burst_write ) = split( ' ', getconfigline( 30 ) );
$timing_down = getconfigline( 210 );
$timing_warn = getconfigline( 211 );
eval( '$test_' . getconfigline( 16 ) . ' = " CHECKED";' );
eval( '$version_' . ( split( ' ', getconfigline( 6 ) ) )[0] . ' = " CHECKED";' );
if( ( split( ' ', getconfigline( 6 ) ) )[1] == 1 )
{
$burst_enabled_0 = ' CHECKED';
}
else
{
$burst_enabled_0 = '';
}
print <
SMArT Settings
$settings_nav_bar