blob: 50cc5e15bbfc68ec3d3f4861eb941e3e3206950f [file] [log] [blame]
//!
//! High-level IPP operation abstractions
//!
use http::Uri;
use crate::{
attribute::IppAttribute,
model::{DelimiterTag, IppVersion, Operation},
payload::IppPayload,
request::IppRequestResponse,
value::IppValue,
};
pub mod builder;
pub mod cups;
fn with_user_name(user_name: Option<String>, req: &mut IppRequestResponse) {
if let Some(user_name) = user_name {
req.attributes_mut().add(
DelimiterTag::OperationAttributes,
IppAttribute::new(
IppAttribute::REQUESTING_USER_NAME,
IppValue::NameWithoutLanguage(user_name),
),
);
}
}
fn with_document_format(document_format: Option<String>, req: &mut IppRequestResponse) {
if let Some(document_format) = document_format {
req.attributes_mut().add(
DelimiterTag::OperationAttributes,
IppAttribute::new(IppAttribute::DOCUMENT_FORMAT, IppValue::MimeMediaType(document_format)),
);
}
}
/// Trait which represents a single IPP operation
pub trait IppOperation {
/// Convert this operation to IPP request which is ready for sending
fn into_ipp_request(self) -> IppRequestResponse;
/// Return IPP version for this operation. Default is 1.1
fn version(&self) -> IppVersion {
IppVersion::v1_1()
}
}
impl<T: IppOperation> From<T> for IppRequestResponse {
fn from(op: T) -> Self {
op.into_ipp_request()
}
}
/// IPP operation Print-Job
pub struct PrintJob {
printer_uri: Uri,
payload: IppPayload,
user_name: Option<String>,
job_name: Option<String>,
document_format: Option<String>,
attributes: Vec<IppAttribute>,
}
impl PrintJob {
/// Create Print-Job operation
///
/// * `printer_uri` - printer URI<br/>
/// * `payload` - job payload<br/>
/// * `user_name` - name of the user (requesting-user-name)<br/>
/// * `document_format` - mime-type of the payload<br/>
/// * `job_name` - job name (job-name)<br/>
pub fn new<S, U, N, D>(
printer_uri: Uri,
payload: S,
user_name: Option<U>,
job_name: Option<N>,
document_format: Option<D>,
) -> PrintJob
where
S: Into<IppPayload>,
U: AsRef<str>,
N: AsRef<str>,
D: AsRef<str>,
{
PrintJob {
printer_uri,
payload: payload.into(),
user_name: user_name.map(|v| v.as_ref().to_string()),
job_name: job_name.map(|v| v.as_ref().to_string()),
document_format: document_format.map(|v| v.as_ref().to_string()),
attributes: Vec::new(),
}
}
/// Set extra job attribute for this operation, for example `colormodel=grayscale`
pub fn add_attribute(&mut self, attribute: IppAttribute) {
self.attributes.push(attribute);
}
}
impl IppOperation for PrintJob {
fn into_ipp_request(self) -> IppRequestResponse {
let mut retval = IppRequestResponse::new(self.version(), Operation::PrintJob, Some(self.printer_uri));
with_user_name(self.user_name, &mut retval);
with_document_format(self.document_format, &mut retval);
if let Some(job_name) = self.job_name {
retval.attributes_mut().add(
DelimiterTag::OperationAttributes,
IppAttribute::new(IppAttribute::JOB_NAME, IppValue::NameWithoutLanguage(job_name)),
)
}
for attr in self.attributes {
retval.attributes_mut().add(DelimiterTag::JobAttributes, attr);
}
*retval.payload_mut() = self.payload;
retval
}
}
/// IPP operation Get-Printer-Attributes
pub struct GetPrinterAttributes {
printer_uri: Uri,
attributes: Vec<String>,
}
impl GetPrinterAttributes {
/// Create Get-Printer-Attributes operation to return all attributes
///
/// * `printer_uri` - printer URI
pub fn new(printer_uri: Uri) -> GetPrinterAttributes {
GetPrinterAttributes {
printer_uri,
attributes: Vec::new(),
}
}
/// Create Get-Printer-Attributes operation to get a given list of attributes
///
/// * `printer_uri` - printer URI
/// * `attributes` - list of attribute names to request from the printer
pub fn with_attributes<I, T>(printer_uri: Uri, attributes: I) -> GetPrinterAttributes
where
I: IntoIterator<Item = T>,
T: AsRef<str>,
{
GetPrinterAttributes {
printer_uri,
attributes: attributes.into_iter().map(|a| a.as_ref().to_string()).collect(),
}
}
}
impl IppOperation for GetPrinterAttributes {
fn into_ipp_request(self) -> IppRequestResponse {
let mut retval =
IppRequestResponse::new(self.version(), Operation::GetPrinterAttributes, Some(self.printer_uri));
if !self.attributes.is_empty() {
let vals: Vec<IppValue> = self.attributes.into_iter().map(IppValue::Keyword).collect();
retval.attributes_mut().add(
DelimiterTag::OperationAttributes,
IppAttribute::new(IppAttribute::REQUESTED_ATTRIBUTES, IppValue::Array(vals)),
);
}
retval
}
}
/// IPP operation Create-Job
pub struct CreateJob {
printer_uri: Uri,
job_name: Option<String>,
attributes: Vec<IppAttribute>,
}
impl CreateJob {
/// Create Create-Job operation
///
/// * `printer_uri` - printer URI
/// * `job_name` - optional job name (job-name)<br/>
pub fn new<T>(printer_uri: Uri, job_name: Option<T>) -> CreateJob
where
T: AsRef<str>,
{
CreateJob {
printer_uri,
job_name: job_name.map(|v| v.as_ref().to_string()),
attributes: Vec::new(),
}
}
/// Set extra job attribute for this operation, for example `colormodel=grayscale`
pub fn add_attribute(&mut self, attribute: IppAttribute) {
self.attributes.push(attribute);
}
}
impl IppOperation for CreateJob {
fn into_ipp_request(self) -> IppRequestResponse {
let mut retval = IppRequestResponse::new(self.version(), Operation::CreateJob, Some(self.printer_uri));
if let Some(job_name) = self.job_name {
retval.attributes_mut().add(
DelimiterTag::OperationAttributes,
IppAttribute::new(IppAttribute::JOB_NAME, IppValue::NameWithoutLanguage(job_name)),
)
}
for attr in self.attributes {
retval.attributes_mut().add(DelimiterTag::JobAttributes, attr);
}
retval
}
}
/// IPP operation Send-Document
pub struct SendDocument {
printer_uri: Uri,
job_id: i32,
payload: IppPayload,
user_name: Option<String>,
document_format: Option<String>,
last: bool,
}
impl SendDocument {
/// Create Send-Document operation
///
/// * `printer_uri` - printer URI<br/>
/// * `job_id` - job ID returned by Create-Job operation<br/>
/// * `payload` - `IppPayload`<br/>
/// * `user_name` - name of the user (requesting-user-name)<br/>
/// * `document_format` - mime-type of the payload<br/>
/// * `last` - whether this document is a last one<br/>
pub fn new<S, U, D>(
printer_uri: Uri,
job_id: i32,
payload: S,
user_name: Option<U>,
document_format: Option<D>,
last: bool,
) -> SendDocument
where
S: Into<IppPayload>,
U: AsRef<str>,
D: AsRef<str>,
{
SendDocument {
printer_uri,
job_id,
payload: payload.into(),
user_name: user_name.map(|v| v.as_ref().to_string()),
document_format: document_format.map(|v| v.as_ref().to_string()),
last,
}
}
}
impl IppOperation for SendDocument {
fn into_ipp_request(self) -> IppRequestResponse {
let mut retval = IppRequestResponse::new(self.version(), Operation::SendDocument, Some(self.printer_uri));
retval.attributes_mut().add(
DelimiterTag::OperationAttributes,
IppAttribute::new(IppAttribute::JOB_ID, IppValue::Integer(self.job_id)),
);
retval.attributes_mut().add(
DelimiterTag::OperationAttributes,
IppAttribute::new(IppAttribute::LAST_DOCUMENT, IppValue::Boolean(self.last)),
);
with_user_name(self.user_name, &mut retval);
with_document_format(self.document_format, &mut retval);
*retval.payload_mut() = self.payload;
retval
}
}
/// IPP operation Purge-Jobs
pub struct PurgeJobs {
printer_uri: Uri,
user_name: Option<String>,
}
impl PurgeJobs {
/// Create Purge-Jobs operation
///
/// * `printer_uri` - printer URI<br/>
/// * `user_name` - name of the user (requesting-user-name)<br/>
pub fn new<U>(printer_uri: Uri, user_name: Option<U>) -> Self
where
U: AsRef<str>,
{
Self {
printer_uri,
user_name: user_name.map(|u| u.as_ref().to_owned()),
}
}
}
impl IppOperation for PurgeJobs {
fn into_ipp_request(self) -> IppRequestResponse {
let mut retval = IppRequestResponse::new(self.version(), Operation::PurgeJobs, Some(self.printer_uri));
with_user_name(self.user_name, &mut retval);
retval
}
}
/// IPP operation Cancel-Job
pub struct CancelJob {
printer_uri: Uri,
job_id: i32,
user_name: Option<String>,
}
impl CancelJob {
/// Create Cancel-Job operation
///
/// * `printer_uri` - printer URI<br/>
/// * `job_id` - job ID<br/>
/// * `user_name` - name of the user (requesting-user-name)<br/>
pub fn new<U>(printer_uri: Uri, job_id: i32, user_name: Option<U>) -> Self
where
U: AsRef<str>,
{
Self {
printer_uri,
job_id,
user_name: user_name.map(|u| u.as_ref().to_owned()),
}
}
}
impl IppOperation for CancelJob {
fn into_ipp_request(self) -> IppRequestResponse {
let mut retval = IppRequestResponse::new(self.version(), Operation::CancelJob, Some(self.printer_uri));
retval.attributes_mut().add(
DelimiterTag::OperationAttributes,
IppAttribute::new(IppAttribute::JOB_ID, IppValue::Integer(self.job_id)),
);
with_user_name(self.user_name, &mut retval);
retval
}
}
/// IPP operation Cancel-Job
pub struct GetJobAttributes {
printer_uri: Uri,
job_id: i32,
user_name: Option<String>,
}
impl GetJobAttributes {
/// Create Get-Job-Attributes operation
///
/// * `printer_uri` - printer URI<br/>
/// * `job_id` - job ID<br/>
/// * `user_name` - name of the user (requesting-user-name)<br/>
pub fn new<U>(printer_uri: Uri, job_id: i32, user_name: Option<U>) -> Self
where
U: AsRef<str>,
{
Self {
printer_uri,
job_id,
user_name: user_name.map(|u| u.as_ref().to_owned()),
}
}
}
impl IppOperation for GetJobAttributes {
fn into_ipp_request(self) -> IppRequestResponse {
let mut retval = IppRequestResponse::new(self.version(), Operation::GetJobAttributes, Some(self.printer_uri));
retval.attributes_mut().add(
DelimiterTag::OperationAttributes,
IppAttribute::new(IppAttribute::JOB_ID, IppValue::Integer(self.job_id)),
);
with_user_name(self.user_name, &mut retval);
retval
}
}
/// IPP operation Get-Jobs
pub struct GetJobs {
printer_uri: Uri,
user_name: Option<String>,
}
impl GetJobs {
/// Create Get-Jobs operation
///
/// * `printer_uri` - printer URI<br/>
/// * `user_name` - name of the user (requesting-user-name)<br/>
pub fn new<U>(printer_uri: Uri, user_name: Option<U>) -> Self
where
U: AsRef<str>,
{
Self {
printer_uri,
user_name: user_name.map(|u| u.as_ref().to_owned()),
}
}
}
impl IppOperation for GetJobs {
fn into_ipp_request(self) -> IppRequestResponse {
let mut retval = IppRequestResponse::new(self.version(), Operation::GetJobs, Some(self.printer_uri));
with_user_name(self.user_name, &mut retval);
retval
}
}