mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-14 09:42:10 -04:00
feat(cups): add manual printer addition by IP/hostname (#1868)
Add a new "Add by Address" flow in the printer settings that allows users to manually add printers by IP address or hostname, enabling printing to devices not visible via mDNS/Avahi discovery (e.g., printers behind Tailscale subnet routers, VPNs, or across network boundaries). Go backend: - New cups.testConnection IPC method that probes remote printers via IPP Get-Printer-Attributes with /ipp/print then / fallback - Input validation with host sanitization and protocol allowlist - Auth-aware probing (HTTP 401/403 reported as reachable) - lpadmin CLI fallback for CreatePrinter/DeletePrinter when cups-pk-helper polkit authorization fails QML frontend: - "Add by Address" toggle alongside existing device discovery - Manual entry form with host, port, protocol fields - Test Connection button with loading state and result display - Smart PPD auto-selection by probed makeModel with driverless fallback - All strings use I18n.tr() with translator context Includes 20+ unit tests covering validation, probe delegation, TLS flag propagation, auth error detection, and handler routing.
This commit is contained in:
@@ -2,8 +2,10 @@ package cups
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -275,13 +277,42 @@ func (m *Manager) GetClasses() ([]PrinterClass, error) {
|
||||
return classes, nil
|
||||
}
|
||||
|
||||
func createPrinterViaLpadmin(name, deviceURI, ppd, information, location string) error {
|
||||
args := []string{"-p", name, "-E", "-v", deviceURI, "-m", ppd}
|
||||
if information != "" {
|
||||
args = append(args, "-D", information)
|
||||
}
|
||||
if location != "" {
|
||||
args = append(args, "-L", location)
|
||||
}
|
||||
out, err := exec.Command("lpadmin", args...).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("lpadmin failed: %s: %w", strings.TrimSpace(string(out)), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deletePrinterViaLpadmin(name string) error {
|
||||
out, err := exec.Command("lpadmin", "-x", name).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("lpadmin failed: %s: %w", strings.TrimSpace(string(out)), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) CreatePrinter(name, deviceURI, ppd string, shared bool, errorPolicy, information, location string) error {
|
||||
usedPkHelper := false
|
||||
|
||||
err := m.client.CreatePrinter(name, deviceURI, ppd, shared, errorPolicy, information, location)
|
||||
if isAuthError(err) && m.pkHelper != nil {
|
||||
if err = m.pkHelper.PrinterAdd(name, deviceURI, ppd, information, location); err != nil {
|
||||
return err
|
||||
// pkHelper failed (e.g., no polkit agent), try lpadmin as last resort.
|
||||
// lpadmin -E enables the printer, so no further setup needed.
|
||||
if lpadminErr := createPrinterViaLpadmin(name, deviceURI, ppd, information, location); lpadminErr != nil {
|
||||
return err
|
||||
}
|
||||
m.RefreshState()
|
||||
return nil
|
||||
}
|
||||
usedPkHelper = true
|
||||
} else if err != nil {
|
||||
@@ -308,6 +339,12 @@ func (m *Manager) DeletePrinter(printerName string) error {
|
||||
err := m.client.DeletePrinter(printerName)
|
||||
if isAuthError(err) && m.pkHelper != nil {
|
||||
err = m.pkHelper.PrinterDelete(printerName)
|
||||
if err != nil {
|
||||
// pkHelper failed, try lpadmin as last resort
|
||||
if lpadminErr := deletePrinterViaLpadmin(printerName); lpadminErr == nil {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
m.RefreshState()
|
||||
|
||||
Reference in New Issue
Block a user