1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
extern crate hostname; extern crate username; use hostname::get_hostname; use username::get_user_name; use std::{ fs::File, io::{self, Error, ErrorKind, Read, Write}, net::TcpStream, process, time::Duration, }; #[derive(Debug)] pub struct LprConnection { stream: TcpStream, verbose: bool, } #[derive(Debug)] pub enum LprError { IoError(io::Error), AckError, } impl From<io::Error> for LprError { fn from(err: io::Error) -> LprError { LprError::IoError(err) } } impl LprConnection { pub fn new(ip_str: &str, timeout_ms: u64) -> Result<LprConnection, LprError> { let stream = TcpStream::connect(format!("{}:515", ip_str))?; stream .set_read_timeout(Some(Duration::from_millis(timeout_ms)))?; Ok(LprConnection { stream, verbose: false, }) } pub fn verbose(&mut self, verbose: bool) { self.verbose = verbose; } pub fn status(mut self) -> io::Result<String> { let bytes_written = self.stream.write(&[4, b'\n'])?; match bytes_written { 2 => { let mut buf: Vec<u8> = Vec::new(); self.stream.read_to_end(&mut buf)?; let buf_str = String::from_utf8_lossy(&buf).to_string(); let split: Vec<&str> = buf_str.split("\n\n").collect(); Ok(split[0].to_string()) } _ => Err(Error::new( ErrorKind::Interrupted, "not all bytes have been written", )), } } fn send_and_wait_for_ack(&mut self, data: &[u8], description: &str) -> Result<(), LprError> { if self.verbose { print!("Sending {}.. ", description); } self.stream.write_all(data)?; let mut buf = [0; 1]; self.stream.read_exact(&mut buf)?; if self.verbose { println!("acknowledged"); } if buf[0] != 0 { return Err(LprError::AckError); } Ok(()) } fn generate_control_file_and_name(&self) -> (String, String) { let host = match get_hostname() { Some(name) => name, None => "lpr-host".to_string(), }; let user = match get_user_name() { Ok(name) => name, Err(_) => "lpr-user".to_string(), }; let name = format!("fA{}{}", process::id() % 1000, host); (format!("H{}\nP{}\nld{}\n", host, user, name), name) } pub fn print_file(&mut self, path_to_file: &str) -> Result<(), LprError> { if self.verbose { print!("Priting {}.. ", &path_to_file) } let mut file = File::open(path_to_file)?; let mut buf: Vec<u8> = Vec::with_capacity(8096); let file_size = file.read_to_end(&mut buf)?; if self.verbose { println!("File Size: {:?}", file_size); } self.print(&buf)?; Ok(()) } pub fn print_file_with_pjl_header( &mut self, path_to_file: &str, mut header_data: Vec<u8>, ) -> Result<(), LprError> { let mut buf: Vec<u8> = Vec::with_capacity(8096); let mut file = File::open(path_to_file)?; let mut file_buf: Vec<u8> = Vec::with_capacity(8096); let _file_size = file.read_to_end(&mut file_buf)?; buf.append(&mut header_data); buf.append(&mut file_buf); buf.append(&mut b"\x1b%-12345X@PJL EOJ\r\n\x1b%-12345X".to_vec()); self.print(&buf)?; Ok(()) } pub fn print(&mut self, data: &[u8]) -> Result<(), LprError> { let (controlfile, job_name) = self.generate_control_file_and_name(); if self.verbose { println!("generated controlfile:\n{}", controlfile) } self.send_and_wait_for_ack(b"\x02lp\n", "receive job command")?; self.send_and_wait_for_ack( &format!("\x02{} c{}\n", controlfile.len(), job_name).as_bytes(), "receive controlfile subcommand", )?; self.send_and_wait_for_ack(&format!("{}\x00", controlfile).as_bytes(), "control file")?; self.send_and_wait_for_ack( &format!("\x03{} d{}\n", data.len(), job_name).as_bytes(), "receive datafile subcommand", )?; self.stream.write_all(data)?; self.send_and_wait_for_ack(&[0], "data file and ack")?; Ok(()) } }