# Printing and scanning, opt-in and off by default. Both are network-facing # (CUPS, and mDNS discovery for WiFi devices), so a consumer that doesn't want # them — a server, a hardened host — simply leaves the flags off and gets none # of it: no avahi, no open firewall, no cups. Nothing to override. # # Printers take vendor drivers (the `drivers` option, never hard-coded). # Scanners are driverless by default via sane-airscan (eSCL/WSD); the one # exception is Canon's BJNP protocol, whose hosts are listed in `bjnpHosts`. # Avahi (mDNS) is shared by both and comes up when either is enabled, so WiFi # devices are discoverable. { config, lib, pkgs, ... }: let cfg = config.local; netDiscovery = cfg.printing.enable || cfg.scanning.enable; in { options.local = { printing = { enable = lib.mkEnableOption "CUPS printing (WiFi/driverless-friendly)"; drivers = lib.mkOption { type = lib.types.listOf lib.types.package; default = [ ]; example = lib.literalExpression "[ pkgs.gutenprint ]"; description = "Extra CUPS driver packages (vendor/model specific)."; }; }; scanning = { enable = lib.mkEnableOption "SANE scanning with driverless network scanners (sane-airscan)"; bjnpHosts = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ ]; example = lib.literalExpression ''[ "bjnp://192.168.1.50" ]''; description = '' Network scanners reachable over Canon's BJNP protocol, registered with SANE's `pixma` backend (written to `/etc/sane.d/pixma.conf`). BJNP is not driverless eSCL/WSD, so `sane-airscan` can't see these; and BJNP broadcast auto-discovery is usually dropped by the firewall, so list each device's `bjnp://` explicitly. ''; }; }; }; config = lib.mkMerge [ (lib.mkIf cfg.printing.enable { services.printing = { enable = true; drivers = cfg.printing.drivers; }; }) # sane-airscan = driverless eSCL/WSD; hardware.sane also creates the # `scanner` group + udev rules. Group membership is per-user → inventory. # A pixma.conf built the same way the module builds net.conf (a text file # dropped at /etc/sane.d/, merged by mkSaneConfig) registers BJNP hosts. (lib.mkIf cfg.scanning.enable { hardware.sane = { enable = true; extraBackends = [ pkgs.sane-airscan ] ++ lib.optional (cfg.scanning.bjnpHosts != [ ]) (pkgs.writeTextFile { name = "sane-pixma-net-conf"; destination = "/etc/sane.d/pixma.conf"; text = lib.concatMapStrings (h: h + "\n") cfg.scanning.bjnpHosts; }); }; }) # mDNS so CUPS/SANE can discover WiFi printers and scanners on the LAN. (lib.mkIf netDiscovery { services.avahi = { enable = true; nssmdns4 = true; openFirewall = true; }; }) ]; }