diff --git a/CMakeLists.txt b/CMakeLists.txt
index c6ef08e..07f3106 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -71,6 +71,7 @@ INCLUDE_DIRECTORIES(
add_executable(nwwebui nwwebui.c)
add_executable(check_login check_login.c)
+add_executable(smart_userlist smart_userlist.c)
#################################
# Linking
@@ -86,6 +87,11 @@ target_link_libraries(check_login
${DL_LIBRARY}
)
+target_link_libraries(smart_userlist
+ ${PAM_LIBRARY}
+ ${DL_LIBRARY}
+)
+
#################################
# Install Files
##############
@@ -108,12 +114,28 @@ install(FILES static/favicon.ico DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}
install(FILES static/favicon-32x32.png DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
install(FILES static/favicon-16x16.png DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
install(FILES static/apple-touch-icon.png DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
+install(FILES static/icon-start.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
+install(FILES static/icon-service.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
+install(FILES static/icon-general.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
+install(FILES static/icon-dirs.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
+install(FILES static/icon-configh.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
+install(FILES static/icon-security.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
+install(FILES static/icon-susers.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
+install(FILES static/icon-volumes.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
+install(FILES static/icon-devices.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
+install(FILES static/icon-logging.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
+install(FILES static/icon-smart.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
+install(FILES static/icon-stations.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
+install(FILES static/icon-users.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
+install(FILES static/icon-groups.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
+install(FILES static/icon-queues.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static)
if(WITH_SYSTEMD)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mars-nwe-webui.service DESTINATION ${SYSTEMD_SERVICES_INSTALL_DIR})
endif()
install(TARGETS check_login DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR})
+install(TARGETS smart_userlist DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR})
install(TARGETS nwwebui DESTINATION ${CMAKE_INSTALL_SBINDIR})
diff --git a/apply.pl b/apply.pl
index ab32dc5..8590a55 100644
--- a/apply.pl
+++ b/apply.pl
@@ -22,12 +22,54 @@
#
#
+sub read_smart_bindery_values()
+{
+ my( $bind_server, $bind_user, $bind_pass ) = ( '', '', '' );
+
+ if( open( my $fh, '<' . $smart_nwclient_path ) )
+ {
+ my $line = <$fh>;
+ close( $fh );
+
+ chomp( $line ) if defined( $line );
+ ( $bind_server, $bind_user, $bind_pass ) = split( '[/ ]', $line ) if defined( $line );
+ }
+
+ $bind_server = '' unless defined( $bind_server );
+ $bind_user = '' unless defined( $bind_user );
+ $bind_pass = '' unless defined( $bind_pass );
+
+ return( $bind_server, $bind_user, $bind_pass );
+}
+
+sub write_smart_bindery_values( $$$ )
+{
+ my( $bind_server, $bind_user, $bind_pass ) = @_;
+
+ $bind_server = '' unless defined( $bind_server );
+ $bind_user = '' unless defined( $bind_user );
+ $bind_pass = '' unless defined( $bind_pass );
+
+ open( my $fh, '>' . $smart_nwclient_path ) or die "Could not open $smart_nwclient_path: $!";
+ print( $fh $bind_server . '/' . $bind_user . ' ' . $bind_pass . "\n" );
+ close( $fh );
+
+ chown( scalar( getpwnam( $nonroot_user ) ), 0, $smart_nwclient_path );
+ chmod( 0600, $smart_nwclient_path );
+}
+
+
sub handle_request()
{
if( $c[1] eq 'general' )
{
setc( 2, server_name );
setc( 3, internal_net );
+ if( defined( $p{sync_smart_bind_server} ) && $p{sync_smart_bind_server} eq 'on' && defined( $p{server_name} ) && $p{server_name} ne '' )
+ {
+ my( $old_bind_server, $old_bind_user, $old_bind_pass ) = read_smart_bindery_values();
+ write_smart_bindery_values( $p{server_name}, $old_bind_user, $old_bind_pass );
+ }
setc( 16, test );
setc( 210, timing_down );
setc( 211, timing_warn );
@@ -109,10 +151,6 @@ sub handle_request()
{
delconfigline( '4 ' . $c[2] );
}
- if( defined( $p{interface_manual} ) && $p{interface_manual} ne '' )
- {
- $p{interface} = $p{interface_manual};
- }
$p{interface} =~ s/[^-_\.A-Za-z0-9:\*]//g;
if( $p{number} ne '' )
{
@@ -148,12 +186,13 @@ sub handle_request()
close( FILE );
}
- open( FILE, '>' . $smart_nwclient_path ) or die "Could not open $smart_nwclient_path: $!";
- print( FILE $p{bind_server} . '/' . $p{bind_user} . ' ' . $p{bind_pass } . "\n" );
- close( FILE );
-
- chown( scalar( getpwnam( $nonroot_user ) ), 0, $smart_nwclient_path );
- chmod( 0600, $smart_nwclient_path );
+ write_smart_bindery_values( $p{bind_server}, $p{bind_user}, $p{bind_pass} );
+
+ if( defined( $p{sync_general_server_name} ) && $p{sync_general_server_name} eq 'on' && defined( $p{bind_server} ) && $p{bind_server} ne '' )
+ {
+ $p{server_name} = $p{bind_server};
+ setc( 2, server_name );
+ }
}
elsif( $c[1] eq 'users' )
{
@@ -355,6 +394,92 @@ EOF
redirect( '/settings/queues' );
}
+
+ elsif( $c[1] eq 'advanced' )
+ {
+ my $advanced_category = $p{advanced_category};
+ $advanced_category = 'all' if ! defined( $advanced_category ) || $advanced_category eq '';
+
+ my $save_devices = ( $advanced_category eq 'all' || $advanced_category eq 'devices' );
+ my $save_security = ( $advanced_category eq 'all' || $advanced_category eq 'security' );
+ my $save_users = ( $advanced_category eq 'all' || $advanced_category eq 'users' );
+ my $save_queues = ( $advanced_category eq 'all' || $advanced_category eq 'queues' );
+ my $save_configh = ( $advanced_category eq 'all' || $advanced_category eq 'configh' );
+ my $save_stations = ( $advanced_category eq 'all' || $advanced_category eq 'stations' );
+ my $save_network = ( $advanced_category eq 'all' || $advanced_category eq 'network' );
+
+ if( $save_devices )
+ {
+ my $device_flags = 0;
+ $device_flags += 1 if $p{dev_keep} eq 'on';
+ $device_flags += 2 if $p{dev_auto} eq 'on';
+ $device_flags += 4 if $p{dev_remove_all} eq 'on';
+
+ delconfigline( 5 );
+ addconfigline( '5 ' . $device_flags ) if $device_flags != 0;
+ }
+
+ if( $save_security )
+ {
+ my $security_flags = 0;
+ $security_flags += 0x8 if $p{sec_supervisor_ignore} eq 'on';
+ $security_flags += 0x40 if $p{sec_2gb_free} eq 'on';
+ $security_flags += 0x200 if $p{sec_int17} eq 'on';
+ $security_flags += 0x2 if $p{sec_delete_open} eq 'on';
+ $security_flags += 0x4 if $p{sec_rename_open} eq 'on';
+
+ delconfigline( 8 );
+ addconfigline( '8 ' . $security_flags ) if $security_flags != 0;
+ }
+
+ if( $save_users )
+ {
+ my $bindery_flags = 0;
+ $bindery_flags += 1 if $p{bindery_empty_scripts} eq 'on';
+
+ delconfigline( 17 );
+ addconfigline( '17 ' . $bindery_flags ) if $bindery_flags != 0;
+ }
+
+ if( $save_queues )
+ {
+ my $queue_flags = 0;
+ $queue_flags += 1 if $p{queue_no_banner} eq 'on';
+
+ delconfigline( 18 );
+ addconfigline( '18 ' . $queue_flags ) if $queue_flags != 0;
+
+ delconfigline( 22 );
+ foreach my $line ( split( /\r?\n/, $p{print_servers} ) )
+ {
+ $line =~ s/^\s+//;
+ $line =~ s/\s+$//;
+ next if $line eq '';
+ $line =~ s/#.*//;
+ next if $line eq '';
+ addconfigline( '22 ' . $line );
+ }
+ }
+
+ if( $save_configh )
+ {
+ setc( 50, conversion_tables );
+ setc( 80, max_dir_search_handles );
+ }
+
+ if( $save_network )
+ {
+ setc( 310, watchdogs );
+ }
+
+ if( $save_stations )
+ {
+ setc( 400, station_file );
+ setc( 401, nearest_replies );
+ setc( 402, connect_replies );
+ }
+ }
+
else
{
putp();
@@ -365,6 +490,42 @@ EOF
writeconfig();
}
+
+sub add_mask_flag( $$$ )
+{
+ my( $value, $param, $mask ) = @_;
+ if( defined( $p{$param} ) && $p{$param} ne '' )
+ {
+ $value |= $mask;
+ }
+ return $value;
+}
+
+sub addconfig_hex( $$ )
+{
+ delconfigline( $_[0] );
+ addconfigline( $_[0] . ' 0x' . sprintf( '%x', $_[1] ) );
+}
+
+sub sanitize_simple_value( $ )
+{
+ my $v = $_[0];
+ $v = '' unless defined $v;
+ $v =~ s/[\r\n]//g;
+ $v =~ s/^\s+//;
+ $v =~ s/\s+$//;
+ $v =~ s/[^-_\.\/\:\~A-Za-z0-9]//g;
+ return $v;
+}
+
+sub sanitize_number_value( $ )
+{
+ my $v = $_[0];
+ $v = '' unless defined $v;
+ $v =~ s/[^0-9xXa-fA-F\-]//g;
+ return $v;
+}
+
sub putp()
{
$cc =~ s/.*\?//;
diff --git a/cupsutils.cmake b/cupsutils.cmake
new file mode 100644
index 0000000..a3d6ac3
--- /dev/null
+++ b/cupsutils.cmake
@@ -0,0 +1,64 @@
+# Optional CUPS command line utility support for SMArT WebUI.
+#
+# This module intentionally searches for the CUPS command line utilities
+# used by the WebUI, not for libcups development headers/libraries.
+#
+# Variables exported:
+#
+# WITH_CUPSUTILS
+# User option to enable/disable CUPS utility discovery.
+#
+# HAVE_CUPSUTILS
+# ON when the required CUPS utilities were found.
+#
+# SMART_CUPS_ENABLE
+# 1 when HAVE_CUPSUTILS is ON, otherwise 0. Intended for configure_file()
+# into Perl config files.
+#
+# CUPS_LPSTAT_EXECUTABLE
+# Path to lpstat.
+#
+# CUPS_LP_EXECUTABLE
+# Path to lp.
+#
+# CUPS_LPR_EXECUTABLE
+# Optional path to lpr, if available.
+
+option(WITH_CUPSUTILS "Enable CUPS utility support for SMArT WebUI" ON)
+
+set(HAVE_CUPSUTILS OFF)
+set(SMART_CUPS_ENABLE 0)
+
+if(WITH_CUPSUTILS)
+ find_program(CUPS_LPSTAT_EXECUTABLE NAMES lpstat)
+ find_program(CUPS_LP_EXECUTABLE NAMES lp)
+ find_program(CUPS_LPR_EXECUTABLE NAMES lpr)
+
+ if(CUPS_LPSTAT_EXECUTABLE AND CUPS_LP_EXECUTABLE)
+ set(HAVE_CUPSUTILS ON)
+ set(SMART_CUPS_ENABLE 1)
+ message(STATUS "Found CUPS utilities: lpstat=${CUPS_LPSTAT_EXECUTABLE}, lp=${CUPS_LP_EXECUTABLE}")
+ if(CUPS_LPR_EXECUTABLE)
+ message(STATUS "Found optional CUPS lpr utility: ${CUPS_LPR_EXECUTABLE}")
+ endif()
+ else()
+ message(STATUS "CUPS utilities not found; SMArT WebUI CUPS printer discovery disabled")
+ endif()
+else()
+ message(STATUS "CUPS utility support disabled")
+endif()
+
+# Provide stable fallback strings for configure_file() consumers. These are
+# only used when SMART_CUPS_ENABLE is 0 or when the admin later overrides the
+# paths in smart.conf.
+if(NOT CUPS_LPSTAT_EXECUTABLE)
+ set(CUPS_LPSTAT_EXECUTABLE "/usr/bin/lpstat")
+endif()
+
+if(NOT CUPS_LP_EXECUTABLE)
+ set(CUPS_LP_EXECUTABLE "/usr/bin/lp")
+endif()
+
+if(NOT CUPS_LPR_EXECUTABLE)
+ set(CUPS_LPR_EXECUTABLE "/usr/bin/lpr")
+endif()
diff --git a/settings.pl b/settings.pl
index c12d79a..2648749 100644
--- a/settings.pl
+++ b/settings.pl
@@ -51,6 +51,112 @@ sub delete_confirm_attr( $ )
return ' onclick="return confirm(\'Delete ' . $what . '?\')"';
}
+sub advanced_link_row( $$ )
+{
+ my( $href, $label ) = @_;
+
+ return qq|\t
\n\t\t| $label | \n\t
\n|;
+}
+
+sub advanced_category()
+{
+ my $cat = $c[2];
+
+ $cat = 'all' if ! defined( $cat ) || $cat eq '';
+
+ if( $cat =~ /^(devices|security|users|queues|configh|stations|network|all)$/ )
+ {
+ return $cat;
+ }
+
+ return 'all';
+}
+
+sub advanced_section_visible( $$ )
+{
+ my( $cat, $section ) = @_;
+
+ return 1 if $cat eq 'all';
+
+ return 1 if $cat eq 'devices' && $section =~ /^(5)$/;
+ return 1 if $cat eq 'security' && $section =~ /^(8)$/;
+ return 1 if $cat eq 'users' && $section =~ /^(17)$/;
+ return 1 if $cat eq 'queues' && $section =~ /^(18|22)$/;
+ return 1 if $cat eq 'configh' && $section =~ /^(50|80)$/;
+ return 1 if $cat eq 'stations' && $section =~ /^(400|401|402)$/;
+ return 1 if $cat eq 'network' && $section =~ /^(310)$/;
+
+ return 0;
+}
+
+sub advanced_title( $ )
+{
+ my $cat = $_[0];
+
+ return 'Advanced device settings' if $cat eq 'devices';
+ return 'Advanced security settings' if $cat eq 'security';
+ return 'Advanced user / bindery settings' if $cat eq 'users';
+ return 'Advanced print queue settings' if $cat eq 'queues';
+ return 'Advanced precompiled / path settings' if $cat eq 'configh';
+ return 'Advanced station access settings' if $cat eq 'stations';
+ return 'Advanced network watchdog settings' if $cat eq 'network';
+
+ return 'Advanced settings';
+}
+
+sub advanced_hidden_category_input( $ )
+{
+ my $cat = $_[0];
+
+ return '' if ! defined( $cat ) || $cat eq '' || $cat eq 'all';
+
+ return '' . "\n";
+}
+
+
+
+sub cfg_int( $ )
+{
+ my $v = $_[0];
+ $v = '' unless defined $v;
+ $v =~ s/^\s+//;
+ $v =~ s/\s+$//;
+ return 0 if $v eq '';
+ return oct( $v ) if $v =~ /^0x[0-9a-f]+$/i;
+ return int( $v );
+}
+
+sub cfg_checked( $$ )
+{
+ my( $value, $mask ) = @_;
+ return ( cfg_int( $value ) & $mask ) ? ' CHECKED' : '';
+}
+
+sub html_selected( $$ )
+{
+ return ( defined $_[0] && defined $_[1] && $_[0] eq $_[1] ) ? ' SELECTED' : '';
+}
+
+sub option_012( $ )
+{
+ my $v = $_[0];
+ $v = '0' unless defined $v && $v ne '';
+ return
+ '' . "\n" .
+ '' . "\n" .
+ '' . "\n";
+}
+
+sub getconfiglines_without_section( $ )
+{
+ my @lines = getconfig( $_[0] );
+ foreach my $line ( @lines )
+ {
+ $line =~ s/^\s*$_[0]\s+//;
+ }
+ return @lines;
+}
+
$settings_nav_bar = settings_nav_bar();
sub kernel_network_interfaces()
@@ -241,89 +347,105 @@ sub cups_print_command( $ )
return $template;
}
+sub cups_add_printer( $$$ )
+{
+ my( $printers, $seen, $name ) = @_;
+
+ return if ! defined( $name );
+ $name =~ s/^\s+//;
+ $name =~ s/\s+$//;
+ return if $name eq '';
+ return if $name =~ /[^-_\.A-Za-z0-9]/;
+
+ my $queue = cups_queue_name( $name );
+
+ my $name_key = lc( $name );
+ my $queue_key = lc( $queue );
+
+ # Deduplicate by both the original CUPS name and the generated MARS_NWE
+ # queue name. This avoids duplicates when the same printer is discovered
+ # through lpstat -e and a localized lpstat -p fallback.
+ return if $seen->{'name:' . $name_key};
+ return if $seen->{'queue:' . $queue_key};
+
+ push( @$printers, {
+ name => $name,
+ queue => $queue,
+ command => cups_print_command( $name ),
+ } );
+
+ $seen->{'name:' . $name_key} = 1;
+ $seen->{'queue:' . $queue_key} = 1;
+}
+
sub cups_printers()
{
- return () unless defined( $smart_cups_enable ) && $smart_cups_enable;
+ my @printers = ();
+ my %seen = ();
- my %printers = ();
- my $lpstat = smart_find_executable(
- $smart_cups_lpstat_path,
- '/usr/bin/lpstat',
- '/bin/lpstat'
- );
+ return @printers if ! defined( $smart_cups_enable ) || !$smart_cups_enable;
+ return @printers if ! defined( $smart_cups_lpstat_path ) || $smart_cups_lpstat_path eq '';
+ return @printers if ! -x $smart_cups_lpstat_path;
- return () if $lpstat eq '';
-
- # Prefer lpstat -e: it prints one destination name per line and is
- # independent of translated words like "printer" / "Drucker".
- if( open( my $fh, '-|', $lpstat, '-e' ) )
+ # Prefer "lpstat -e": it prints only destination names and is language
+ # independent. If it returns at least one printer, do not run fallback
+ # parsers, because some CUPS versions/locales can expose aliases there.
+ if( open( my $fh, '-|', $smart_cups_lpstat_path, '-e' ) )
{
while( my $line = <$fh> )
{
chomp( $line );
$line =~ s/^\s+//;
$line =~ s/\s+$//;
- next if $line eq '';
- my $printer = sanitize_cups_printer_name( ( split( /\s+/, $line ) )[0] );
- $printers{$printer} = 1 if $printer ne '';
+ next if $line eq '';
+ next if $line =~ /[\r\n]/;
+
+ cups_add_printer( \@printers, \%seen, $line );
}
+
close( $fh );
}
- # Fallback: English "device for NAME:" and German "Gerät für NAME:".
- if( scalar( keys( %printers ) ) == 0 )
+ return @printers if scalar( @printers ) > 0;
+
+ # Fallback: "lpstat -v" is also mostly language independent because the
+ # destination name follows "for :" on many systems.
+ if( open( my $fh, '-|', $smart_cups_lpstat_path, '-v' ) )
{
- if( open( my $fh, '-|', $lpstat, '-v' ) )
+ while( my $line = <$fh> )
{
- while( my $line = <$fh> )
+ chomp( $line );
+
+ if( $line =~ /\bfor\s+([^:\s]+)\s*:/i )
{
- chomp( $line );
-
- my $printer = '';
- if( $line =~ /^device\s+for\s+([^:\s]+):/i )
- {
- $printer = $1;
- }
- elsif( $line =~ /^ger\S*\s+f\S*r\s+([^:\s]+):/i )
- {
- $printer = $1;
- }
-
- $printer = sanitize_cups_printer_name( $printer );
- $printers{$printer} = 1 if $printer ne '';
+ cups_add_printer( \@printers, \%seen, $1 );
}
- close( $fh );
}
+
+ close( $fh );
}
- # Fallback: English "printer NAME ..." and German "Drucker NAME ...".
- if( scalar( keys( %printers ) ) == 0 )
+ return @printers if scalar( @printers ) > 0;
+
+ # Last fallback: parse localized "lpstat -p" output. English starts with
+ # "printer ", German starts with "Drucker ".
+ if( open( my $fh, '-|', $smart_cups_lpstat_path, '-p' ) )
{
- if( open( my $fh, '-|', $lpstat, '-p' ) )
+ while( my $line = <$fh> )
{
- while( my $line = <$fh> )
+ chomp( $line );
+
+ if( $line =~ /^(?:printer|Drucker)\s+(\S+)/i )
{
- chomp( $line );
-
- my $printer = '';
- if( $line =~ /^printer\s+(\S+)/i )
- {
- $printer = $1;
- }
- elsif( $line =~ /^drucker\s+(\S+)/i )
- {
- $printer = $1;
- }
-
- $printer = sanitize_cups_printer_name( $printer );
- $printers{$printer} = 1 if $printer ne '';
+ cups_add_printer( \@printers, \%seen, $1 );
}
- close( $fh );
}
+
+ close( $fh );
}
- return sort( keys( %printers ) );
+ return @printers;
}
sub cups_import_rows()
@@ -340,12 +462,13 @@ sub cups_import_rows()
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 );
+ my $name = ref( $printer ) eq 'HASH' ? $printer->{name} : $printer;
+ my $queue = ref( $printer ) eq 'HASH' ? $printer->{queue} : cups_queue_name( $printer );
+ my $cmd = ref( $printer ) eq 'HASH' ? $printer->{command} : cups_print_command( $printer );
+ my $href = '/settings/queues/add_new?cups_printer=' . url_escape( $name );
$html .= "\t\n";
- $html .= "\t\t" . html_escape( $printer ) . " Queue: " . html_escape( $queue ) . " Command: " . html_escape( $cmd ) . " | \n";
+ $html .= "\t\t" . html_escape( $name ) . " Queue: " . html_escape( $queue ) . " Command: " . html_escape( $cmd ) . " | \n";
$html .= "\t\tAdd as print queue | \n";
$html .= "\t
\n";
}
@@ -367,10 +490,14 @@ sub cups_select_html( $ )
foreach my $printer ( @printers )
{
- my $sel = ( $printer eq $current ) ? ' SELECTED' : '';
- $html .= qq|\t\t\t\t\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";
+ my $name = ref( $printer ) eq 'HASH' ? $printer->{name} : $printer;
+ my $queue = ref( $printer ) eq 'HASH' ? $printer->{queue} : cups_queue_name( $printer );
+ my $cmd = ref( $printer ) eq 'HASH' ? $printer->{command} : cups_print_command( $printer );
+ my $sel = ( $name eq $current ) ? ' SELECTED' : '';
+
+ $html .= qq|\t\t\t\t\n|;
+ $js .= "smartCupsCommands['" . js_escape( $name ) . "'] = '" . js_escape( $cmd ) . "';\n";
+ $js .= "smartCupsQueues['" . js_escape( $name ) . "'] = '" . js_escape( $queue ) . "';\n";
}
$html .= qq|\t\t\t|;
@@ -378,12 +505,359 @@ sub cups_select_html( $ )
return ( $html, $js );
}
+sub ipx_interface_info( $ )
+{
+ my $want = $_[0];
+ my %info = ();
+
+ return %info if ! defined( $want ) || $want eq '';
+
+ 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 );
+ next if scalar( @fields ) < 5;
+
+ my $network = $fields[0];
+ my $dev = $fields[3];
+ my $frame = $fields[4];
+
+ next if ! defined( $dev ) || $dev ne $want;
+ next if lc( $dev ) eq 'internal';
+
+ $info{network} = $network;
+ $info{frame} = $frame;
+ last;
+ }
+
+ close( $fh );
+ }
+
+ return %info;
+}
+
+sub ipx_device_import_rows()
+{
+ my $html = '';
+ my @ifaces = ipx_enabled_interfaces();
+
+ if( scalar( @ifaces ) == 0 )
+ {
+ return qq|\t\n\t\t| IPX interfaces detected on host | \n\t
\n\t\n\t\t| No active IPX interfaces were found in /proc/net/ipx/interface. | \n\t
\n|;
+ }
+
+ $html .= qq|\t\n\t\t| IPX interfaces detected on host | \n\t
\n|;
+
+ foreach my $iface ( @ifaces )
+ {
+ my %info = ipx_interface_info( $iface );
+ my $net = $info{network};
+ my $frame = $info{frame};
+ my $delay = 1;
+
+ $net = '0x0' if ! defined( $net ) || $net eq '';
+ $frame = '802.2' if ! defined( $frame ) || $frame eq '' || lc( $frame ) eq 'none';
+
+ my $href = '/settings/devices/add_new?ipx_iface=' . url_escape( $iface );
+
+ $html .= "\t\n";
+ $html .= "\t\t" . html_escape( $iface ) . " Config line: 4 " . html_escape( $net ) . " " . html_escape( $iface ) . " " . html_escape( $frame ) . " " . html_escape( $delay ) . " | \n";
+ $html .= "\t\tAdd as device | \n";
+ $html .= "\t
\n";
+ }
+
+ return $html;
+}
+
+sub ipx_device_defaults_from_query()
+{
+ my %defaults = ();
+
+ $defaults{number} = '';
+ $defaults{interface} = '';
+ $defaults{frametype} = '802.2';
+ $defaults{delay} = 1;
+
+ if( defined( $p{ipx_iface} ) && $p{ipx_iface} ne '' )
+ {
+ my $iface = $p{ipx_iface};
+ $iface =~ s/[^-_\.A-Za-z0-9]//g;
+
+ my %info = ipx_interface_info( $iface );
+
+ $defaults{interface} = $iface;
+ $defaults{number} = defined( $info{network} ) && $info{network} ne '' ? $info{network} : '0x0';
+ $defaults{frametype} = defined( $info{frame} ) && $info{frame} ne '' && lc( $info{frame} ) ne 'none' ? $info{frame} : '802.2';
+ $defaults{delay} = 1;
+ }
+
+ return %defaults;
+}
+
+
+sub smart_bindery_values()
+{
+ my( $bind_server, $bind_user, $bind_pass ) = ( '', '', '' );
+
+ if( open( my $fh, '<' . $smart_nwclient_path ) )
+ {
+ my $line = <$fh>;
+ close( $fh );
+
+ chomp( $line ) if defined( $line );
+ ( $bind_server, $bind_user, $bind_pass ) = split( '[/ ]', $line ) if defined( $line );
+ }
+
+ $bind_server = '' unless defined( $bind_server );
+ $bind_user = '' unless defined( $bind_user );
+ $bind_pass = '' unless defined( $bind_pass );
+
+ return( $bind_server, $bind_user, $bind_pass );
+}
+
+sub sync_server_hint_row( $$$$ )
+{
+ my( $checkbox_name, $current_name, $other_name, $direction ) = @_;
+
+ $current_name = '' unless defined( $current_name );
+ $other_name = '' unless defined( $other_name );
+
+ my $msg = '';
+
+ if( $direction eq 'general_to_smart' )
+ {
+ $msg = 'Also update the SMArT bindery server when saving. Current SMArT bindery server: ';
+ $msg .= $other_name ne '' ? '' . html_escape( $other_name ) . '' : 'not set';
+ }
+ else
+ {
+ $msg = 'Also update the MARS_NWE server name when saving. Current MARS_NWE server name: ';
+ $msg .= $other_name ne '' ? '' . html_escape( $other_name ) . '' : 'not set';
+ }
+
+ return qq|\t\n\t\tKeep server names in sync: $msg | \n\t\tYes | \n\t
\n|;
+}
+
+
+sub unix_user_import_rows()
+{
+ my $html = '';
+ my @users = unix_userlist_effective();
+ my %existing = ();
+ my @candidates = ();
+
+ foreach my $line ( getconfig( 13 ) )
+ {
+ my @f = split( ' ', $line );
+ $existing{lc( $f[1] )} = 1 if defined( $f[1] ) && $f[1] ne '';
+ }
+
+ foreach my $u ( @users )
+ {
+ next if ! defined( $u->{name} ) || $u->{name} eq '';
+ next if defined( $u->{uid} ) && $u->{uid} < 1000;
+ next if lc( $u->{name} ) eq 'nobody';
+ next if lc( $u->{name} ) eq 'root';
+ next if $existing{lc( $u->{name} )};
+
+ push( @candidates, $u );
+ }
+
+ if( scalar( @candidates ) == 0 )
+ {
+ return qq|\t\n\t\t| Unix users detected on host | \n\t
\n\t\n\t\t| No additional local Unix users were found for import. | \n\t
\n|;
+ }
+
+ $html .= qq|\t\n\t\t| Unix users detected on host | \n\t
\n|;
+
+ foreach my $u ( @candidates )
+ {
+ my $name = $u->{name};
+ my $uid = $u->{uid};
+ my $gecos = defined( $u->{gecos} ) ? $u->{gecos} : '';
+ $gecos =~ s/,.*$//;
+
+ my $href = '/settings/users_import/' . url_escape( $name );
+
+ $html .= "\t\n";
+ $html .= "\t\t" . html_escape( $name ) . " UID: " . html_escape( $uid ) . "";
+ $html .= " " . html_escape( $gecos ) if $gecos ne '';
+ $html .= " | \n";
+ $html .= "\t\tAdd as MARS_NWE user | \n";
+ $html .= "\t
\n";
+ }
+
+ return $html;
+}
+
+sub unix_user_defaults_from_query()
+{
+ my %defaults = ();
+
+ $defaults{name} = '';
+ $defaults{unix_user} = '';
+ $defaults{fullname} = '';
+
+ my $want = '';
+
+ if( defined( $p{unix_user} ) && $p{unix_user} ne '' )
+ {
+ $want = $p{unix_user};
+ }
+ elsif( defined( $c[1] ) && $c[1] eq 'users_import' && defined( $c[2] ) && $c[2] ne '' )
+ {
+ $want = $c[2];
+ }
+ elsif( defined( $c[3] ) && $c[3] ne '' )
+ {
+ $want = $c[3];
+ }
+
+ if( $want ne '' )
+ {
+ $want =~ s/[^-_\.A-Za-z0-9]//g;
+
+ foreach my $u ( unix_userlist_effective() )
+ {
+ next if ! defined( $u->{name} ) || $u->{name} ne $want;
+
+ my $gecos = defined( $u->{gecos} ) ? $u->{gecos} : '';
+ $gecos =~ s/,.*$//;
+
+ $defaults{name} = uc( $u->{name} );
+ $defaults{name} =~ s/[^-_\.A-Za-z0-9]//g;
+ $defaults{unix_user} = $u->{name};
+ $defaults{fullname} = $gecos;
+ last;
+ }
+ }
+
+ return %defaults;
+}
+
+
+sub selected_attr( $$ )
+{
+ my( $a, $b ) = @_;
+
+ $a = '' unless defined( $a );
+ $b = '' unless defined( $b );
+
+ return $a eq $b ? ' SELECTED' : '';
+}
+
+
+sub smart_group_checkbox_rows( $ )
+{
+ my $server = $_[0];
+ my $html = '';
+
+ my @groups = ();
+ my $cmd = 'nwbols -t 2 -S ' . $server;
+
+ @groups = sort( split( "\n", `$cmd` ) );
+
+ foreach my $g ( @groups )
+ {
+ my @f = split( ' ', $g );
+ my $group = $f[0];
+
+ next if ! defined( $group ) || $group eq '';
+ next if $group =~ /[^-_\.A-Za-z0-9]/;
+
+ $html .= html_escape( $group ) . '
' . "\n";
+ }
+
+ if( $html eq '' )
+ {
+ $html = 'No bindery groups found. Save the user first, then add groups later.
' . "\n";
+ }
+
+ return $html;
+}
+
+
+sub smart_debug_user_import_row()
+{
+ my $p_unix = defined( $p{unix_user} ) ? $p{unix_user} : '';
+ my $line = '';
+
+ $line .= 'c0=' . html_escape( defined( $c[0] ) ? $c[0] : '' ) . ' ';
+ $line .= 'c1=' . html_escape( defined( $c[1] ) ? $c[1] : '' ) . ' ';
+ $line .= 'c2=' . html_escape( defined( $c[2] ) ? $c[2] : '' ) . ' ';
+ $line .= 'c3=' . html_escape( defined( $c[3] ) ? $c[3] : '' ) . ' ';
+ $line .= 'c4=' . html_escape( defined( $c[4] ) ? $c[4] : '' ) . ' ';
+ $line .= 'p_unix_user=' . html_escape( $p_unix );
+
+ return qq|\t\n\t\t| Debug user import: | \n\t\t$line | \n\t
\n|;
+}
+
+
+sub unix_userlist_effective()
+{
+ my @users = ();
+
+ if( defined( $smart_userlist_path ) && $smart_userlist_path ne '' && -x $smart_userlist_path )
+ {
+ my @cmd = ( $smart_userlist_path );
+
+ if( defined( $smart_userlist_pam_check ) && $smart_userlist_pam_check )
+ {
+ push( @cmd, '--pam-check' );
+ push( @cmd, '--pam-service', 'smart' );
+ }
+
+ if( open( my $fh, '-|', @cmd ) )
+ {
+ while( my $line = <$fh> )
+ {
+ chomp( $line );
+
+ my( $name, $uid, $gid, $gecos, $home, $shell ) = split( /\t/, $line, 6 );
+
+ next if ! defined( $name ) || $name eq '';
+ next if $name =~ /[^-_\.A-Za-z0-9]/;
+
+ push( @users, {
+ name => $name,
+ uid => $uid,
+ gid => $gid,
+ gecos => defined( $gecos ) ? $gecos : '',
+ home => defined( $home ) ? $home : '',
+ shell => defined( $shell ) ? $shell : '',
+ } );
+ }
+
+ close( $fh );
+ }
+ }
+
+ # Last-resort compatibility fallback: old SMArT unix_userlist() implementation.
+ if( scalar( @users ) == 0 )
+ {
+ @users = unix_userlist();
+ }
+
+ return @users;
+}
+
+
sub handle_request()
{
if( $c[1] eq 'general' )
{
$server_name = getconfigline( 2 );
$internal_net = getconfigline( 3 );
+ my( $smart_bind_server_for_general, $smart_bind_user_for_general, $smart_bind_pass_for_general ) = smart_bindery_values();
+ my $general_sync_server_row = sync_server_hint_row( 'sync_smart_bind_server', $server_name, $smart_bind_server_for_general, 'general_to_smart' );
( $burst_read, $burst_write ) = split( ' ', getconfigline( 30 ) );
$timing_down = getconfigline( 210 );
$timing_warn = getconfigline( 211 );
@@ -532,6 +1006,7 @@ $settings_nav_bar
+$general_sync_server_row
@@ -795,6 +1270,9 @@ $settings_nav_bar
|
+
+ | Advanced precompiled / path settings |
+
@@ -892,6 +1370,9 @@ $settings_nav_bar
Disallow encryption
|
+
+ | Advanced security settings |
+
@@ -913,7 +1394,7 @@ EOF
( $root_name, $root, $root_password ) = split( ' ', getconfigline( 12 ) );
$guest_user_list = '';
$root_list = '';
- foreach $u ( unix_userlist() )
+ foreach $u ( unix_userlist_effective() )
{
if( $u->{uid} eq $guest )
{ $guest_user_list .= "\t\t\t" . '' . "\n"; }
@@ -1063,6 +1544,9 @@ $root_list
|
+
+ | Advanced user / bindery settings |
+
@@ -1320,6 +1804,9 @@ $settings_nav_bar
Write to separate files (.1, .2, etc)
|
+
+ | Advanced network watchdog settings |
+
@@ -1634,6 +2121,8 @@ EOF
{
if( $c[2] eq '' )
{
+ my $ipx_device_import_rows = ipx_device_import_rows();
+
print <
- Add new device
+ Add new device manually
+ Advanced device settings
|
|
@@ -1712,13 +2203,42 @@ EOF
}
else
{
- $c = getconfigline( '4 ' . $c[2] );
- @c = split( ' ', $c );
- $interface_options = network_interface_options( $c[1] );
-
- $c[2] =~ s/\.//g;
- eval( '$frametype_' . $c[2] . ' = " SELECTED";' );
-
+ my $title = $c[2];
+ my $number = '';
+ my $interface = '';
+ my $frametype = '802.2';
+ my $delay = 1;
+
+ if( $c[2] eq 'add_new' )
+ {
+ my %defaults = ipx_device_defaults_from_query();
+ $number = $defaults{number};
+ $interface = $defaults{interface};
+ $frametype = $defaults{frametype};
+ $delay = $defaults{delay};
+ }
+ else
+ {
+ my $line = getconfigline( '4 ' . $c[2] );
+ my @dev = split( ' ', $line );
+
+ $number = $dev[0];
+ $interface = $dev[1];
+ $frametype = $dev[2];
+ $delay = $dev[3];
+
+ $title = $number;
+ }
+
+ $number = '' unless defined $number;
+ $interface = '' unless defined $interface;
+ $frametype = '802.2' unless defined $frametype && $frametype ne '';
+ $delay = 1 unless defined $delay && $delay ne '';
+
+ my $frametype_key = $frametype;
+ $frametype_key =~ s/\.//g;
+ eval( '$frametype_' . $frametype_key . ' = " SELECTED";' );
+
print <
$settings_nav_bar
-