Cups support

This commit is contained in:
Mario Fetka
2026-05-21 18:58:59 +02:00
parent 339aa49d6b
commit a2f4f8a789
2 changed files with 221 additions and 2 deletions

View File

@@ -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<TR BGCOLOR="#ece0cf">\n\t\t<TD COLSPAN=2><B>CUPS printers detected on host</B></TD>\n\t</TR>\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<TR BGCOLOR=\"#fbf7f1\">\n";
$html .= "\t\t<TD><TT>" . html_escape( $printer ) . "</TT><BR><SMALL>Queue: <TT>" . html_escape( $queue ) . "</TT> &nbsp; Command: <TT>" . html_escape( $cmd ) . "</TT></SMALL></TD>\n";
$html .= "\t\t<TD ALIGN=RIGHT><A HREF=\"" . html_escape( $href ) . "\">Add as print queue</A></TD>\n";
$html .= "\t</TR>\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|<SELECT NAME="cups_printer" ID="cups_printer" ONCHANGE="smartUseCupsPrinter(this.value)">\n|;
$html .= qq|\t\t\t\t<OPTION VALUE="">-- choose CUPS printer --</OPTION>\n|;
foreach my $printer ( @printers )
{
my $sel = ( $printer eq $current ) ? ' SELECTED' : '';
$html .= qq|\t\t\t\t<OPTION VALUE="| . html_escape( $printer ) . qq|"| . $sel . qq|>| . html_escape( $printer ) . qq|</OPTION>\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</SELECT>|;
return ( $html, $js );
}
sub handle_request()
{
if( $c[1] eq 'general' )
@@ -2251,6 +2406,7 @@ EOF
</TR>
EOF
}
print cups_import_rows();
print <<EOF;
<TR BGCOLOR="#d7c0a0">
<TD COLSPAN=2>
@@ -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 <<EOF;
HTTP/1.0 200 OK
@@ -2308,6 +2473,26 @@ INPUT[type=SUBMIT], INPUT[type=RESET], INPUT[type=BUTTON] {
A { color:#9f2f26; }
TT { color:#5b4b38; }
</style>
<SCRIPT TYPE="text/javascript">
var smartCupsCommands = {};
var smartCupsQueues = {};
$cups_js
function smartUseCupsPrinter(printer) {
if (!printer) { return; }
var cmd = document.getElementById('unix_print');
if (cmd && smartCupsCommands[printer]) {
cmd.value = smartCupsCommands[printer];
}
var qn = document.getElementById('queue_name');
if (qn && smartCupsQueues[printer] && qn.value === '') {
qn.value = smartCupsQueues[printer];
}
}
window.onload = function() {
var sel = document.getElementById('cups_printer');
if (sel && sel.value) { smartUseCupsPrinter(sel.value); }
};
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#f6f2ea">
$settings_nav_bar
@@ -2332,19 +2517,36 @@ EOF
<B>Queue name:</B>
</TD>
<TD ALIGN=RIGHT>
<INPUT NAME="name" TYPE=TEXT SIZE=32><BR>
<INPUT ID="queue_name" NAME="name" TYPE=TEXT SIZE=32 VALUE="$queue_name_value"><BR>
</TD>
</TR>
EOF
}
print <<EOF;
EOF
if( $cups_select ne '' )
{
print <<EOF;
<TR BGCOLOR="#fbf7f1">
<TD>
<B>CUPS printer:</B><BR>
<SMALL>Select a host printer to generate the matching lp command.</SMALL>
</TD>
<TD ALIGN=RIGHT>
$cups_select<BR>
</TD>
</TR>
EOF
}
print <<EOF;
<TR BGCOLOR="#fbf7f1">
<TD>
<B>Unix printing command:</B>
</TD>
<TD ALIGN=RIGHT>
<INPUT NAME="unix_print" TYPE=TEXT SIZE=32 VALUE="$unix_print"><BR>
<INPUT ID="unix_print" NAME="unix_print" TYPE=TEXT SIZE=48 VALUE="$unix_print"><BR>
<SMALL>Example for CUPS: <TT>/usr/bin/lp -d printer -</TT></SMALL>
</TD>
</TR>
<TR BGCOLOR="#fbf7f1">

View File

@@ -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
# ------------------------------------------------------------