feat(rdp): printer redirection, saved as PostScript

An optional 'Nexus Terminal' printer (IronRDP's PostScript driver
announce) appears on the remote desktop; each job is written to
'Nexus print <time>.ps' in Downloads, with a toast saying where. Jobs
are capped at 256 MiB and empty jobs leave no file. The shared drive and
the printer now share one RDPDR backend (rdp_devices); the printer
works on every platform, the drive on Linux and macOS.

Tested with a unit test driving create/write/close; xrdp has no printer
redirection, so not exercised against a server.
This commit is contained in:
Andy Dixon
2026-10-12 18:14:31 +01:00
parent b798422735
commit 2fa56e0723
11 changed files with 354 additions and 139 deletions
+13
View File
@@ -356,6 +356,12 @@ impl Manager {
allow_tls_only: rc.allow_tls_only,
audio: rc.audio,
shared_folder: (!rc.shared_folder.trim().is_empty()).then(|| (rc.shared_folder.trim().into(), "Nexus".into())),
printer: rc.redirect_printer.then(|| {
let (me, sid) = (self.clone(), id.to_string());
let on_printed: clients::rdp_devices::PrintedFn =
Arc::new(move |f: PathBuf| me.emit(Event::Info { session: sid.clone(), message: format!("Print job saved to {}", f.display()) }));
(downloads_dir(), on_printed)
}),
dial,
check_cert,
connect_timeout: timeout,
@@ -418,3 +424,10 @@ pub(super) fn connect_vnc_client(
Err(e) => Err(e),
}
}
/// Where print jobs and similar go: ~/Downloads when it exists, else the home folder.
fn downloads_dir() -> PathBuf {
let home = std::env::var_os(if cfg!(windows) { "USERPROFILE" } else { "HOME" }).map(PathBuf::from).unwrap_or_else(std::env::temp_dir);
let d = home.join("Downloads");
if d.is_dir() { d } else { home }
}