From a2f4f8a78998affd775041dd68ae833f586f3033 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Thu, 21 May 2026 18:58:59 +0200 Subject: [PATCH] Cups support --- settings.pl | 206 ++++++++++++++++++++++++++++++++++++++++++++++- smart.conf.cmake | 17 ++++ 2 files changed, 221 insertions(+), 2 deletions(-) diff --git a/settings.pl b/settings.pl index efc1d2c..fb38a30 100644 --- a/settings.pl +++ b/settings.pl @@ -182,6 +182,161 @@ sub network_interface_options( $ ) 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||; + + return ( $html, $js ); +} + sub handle_request() { if( $c[1] eq 'general' ) @@ -2251,6 +2406,7 @@ EOF EOF } + print cups_import_rows(); print < @@ -2268,11 +2424,20 @@ EOF { @all = sort( split( "\n", `nwbols -S $server` ) ); $man_list = ''; + $queue_name_value = ''; + $selected_cups_printer = sanitize_cups_printer_name( $p{cups_printer} ); if( $c[2] ne 'add_new' ) { $unix_print = read_property_string( $c[2], 3, 'Q_UNIX_PRINT' ); $spool_dir = read_property_string( $c[2], 3, 'Q_DIRECTORY' ); } + elsif( $selected_cups_printer ne '' ) + { + $queue_name_value = cups_queue_name( $selected_cups_printer ); + $unix_print = cups_print_command( $selected_cups_printer ); + } + + ( $cups_select, $cups_js ) = cups_select_html( $selected_cups_printer ); print < + $settings_nav_bar @@ -2332,19 +2517,36 @@ EOF Queue name: -
+
EOF } + print < + + CUPS printer:
+ Select a host printer to generate the matching lp command. + + + $cups_select
+ + +EOF + } print < Unix printing command: -
+
+ Example for CUPS: /usr/bin/lp -d printer - diff --git a/smart.conf.cmake b/smart.conf.cmake index 10f7915..b0d5371 100644 --- a/smart.conf.cmake +++ b/smart.conf.cmake @@ -79,6 +79,23 @@ $smart_systemctl_path = '@SYSTEMCTL_EXECUTABLE@'; # Uncomment and adjust only if a non-standard location must be used. # $smart_perl_path = '@MARS_NWE_INSTALL_FULL_LIBEXECDIR@/smart'; +# ------------------------------------------------------------ +# Host printer / CUPS utility integration +# ------------------------------------------------------------ + +# Enable CUPS host-printer discovery in the SMArT queue UI. +# This value is generated from cmake/modules/cupsutils.cmake. +# 1 = enabled, 0 = disabled +$smart_cups_enable = '@SMART_CUPS_ENABLE@'; + +# lpstat executable used to discover local CUPS printers for the queue UI. +$smart_cups_lpstat_path = '@CUPS_LPSTAT_EXECUTABLE@'; + +# Command template used when SMArT creates a print queue from a CUPS printer. +# %p is replaced with the sanitized CUPS printer name. +# The trailing '-' makes lp read the print job from stdin. +$smart_cups_print_command_template = '@CUPS_LP_EXECUTABLE@ -d %p -'; + # ------------------------------------------------------------ # nwwebui listener settings # ------------------------------------------------------------