use libc::{c_char, c_int};
use std::{
ffi::{CStr, CString},
ptr,
};
use crate::shared::interface::PlatformPrinterGetters;
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct CupsOptionT {
pub name: *mut c_char,
pub value: *mut c_char,
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct CupsDestT {
name: *mut c_char,
instance: *mut c_char,
is_default: c_int,
num_options: c_int,
options: *mut CupsOptionT,
}
impl CupsDestT {
fn get_option_by_key(&self, key: &str) -> String {
let mut value = "".to_string();
for i in 1..self.num_options {
let option_ptr = unsafe { self.options.offset(i as isize) };
let option = unsafe { &*option_ptr };
let name = unsafe { CStr::from_ptr(option.name.clone()) };
if name.to_string_lossy() == key {
let value_srt = unsafe { CStr::from_ptr(option.value.clone()) };
value = value_srt.to_string_lossy().to_string();
break;
}
}
return value;
}
}
impl PlatformPrinterGetters for CupsDestT {
fn get_system_name(&self) -> String {
if self.name.is_null() {
return "".to_string();
}
let c_str = unsafe { CStr::from_ptr(self.name.clone()) };
return c_str.to_str().unwrap().to_string();
}
fn get_is_default(&self) -> bool {
return self.is_default == 1;
}
fn get_name(&self) -> String {
return self.get_option_by_key("printer-info");
}
fn get_marker_and_model(&self) -> String {
return self.get_option_by_key("printer-make-and-model");
}
fn get_is_shared(&self) -> bool {
return self.get_option_by_key("printer-is-shared") == "true";
}
fn get_uri(&self) -> String {
return self.get_option_by_key("device-uri");
}
fn get_location(&self) -> String {
return self.get_option_by_key("printer-location");
}
fn get_state(&self) -> String {
return self.get_option_by_key("printer-state");
}
}
#[link(name = "cups")]
extern "C" {
fn cupsGetDests(dests: *mut *mut CupsDestT) -> c_int;
fn cupsPrintFile(
printer_name: *const c_char,
filename: *const c_char,
title: *const c_char,
options: i32,
) -> i32;
}
pub fn get_dests() -> Vec<&'static CupsDestT> {
let mut dests_ptr: *mut CupsDestT = ptr::null_mut();
let dests_count = unsafe { cupsGetDests(&mut dests_ptr) };
let mut dests: Vec<&CupsDestT> = Vec::new();
for i in 0..dests_count {
let dest_ptr = unsafe { dests_ptr.offset(i as isize) };
let dest = unsafe { &*dest_ptr };
if !dest.name.is_null() && dest.get_option_by_key("printer-is-shared") != "" {
dests.push(dest);
}
}
return dests;
}
pub fn print_file(printer_name: &str, file_path: &str, job_name: Option<&str>) -> bool {
unsafe {
let printer_name = CString::new(printer_name).unwrap();
let filename = CString::new(file_path).unwrap();
let title = CString::new(job_name.unwrap_or(file_path)).unwrap();
let result = cupsPrintFile(printer_name.as_ptr(), filename.as_ptr(), title.as_ptr(), 0);
return result != 0;
}
}