ipp_proto/operation/
mod.rs

1//!
2//! High-level IPP operation abstractions
3//!
4use crate::{attribute::*, ipp::*, request::IppRequestResponse, IppJobSource, IppValue};
5
6pub mod cups;
7
8/// Trait which represents a single IPP operation
9pub trait IppOperation {
10    /// Convert this operation to IPP request which is ready for sending
11    fn into_ipp_request(self, uri: &str) -> IppRequestResponse;
12
13    /// Return IPP version for this operation. Default is 1.1
14    fn version(&self) -> IppVersion {
15        IppVersion::Ipp11
16    }
17}
18
19/// IPP operation Print-Job
20pub struct PrintJob {
21    source: IppJobSource,
22    user_name: Option<String>,
23    job_name: Option<String>,
24    attributes: Vec<IppAttribute>,
25}
26
27impl PrintJob {
28    /// Create Print-Job operation
29    ///
30    /// * `source` - `IppJobSource`<br/>
31    /// * `user_name` - name of the user (requesting-user-name)<br/>
32    /// * `job_name` - job name (job-name)<br/>
33    pub fn new<U, N>(source: IppJobSource, user_name: Option<U>, job_name: Option<N>) -> PrintJob
34    where
35        U: AsRef<str>,
36        N: AsRef<str>,
37    {
38        PrintJob {
39            source,
40            user_name: user_name.map(|v| v.as_ref().to_string()),
41            job_name: job_name.map(|v| v.as_ref().to_string()),
42            attributes: Vec::new(),
43        }
44    }
45
46    /// Set extra job attribute for this operation, for example `colormodel=grayscale`
47    pub fn add_attribute(&mut self, attribute: IppAttribute) {
48        self.attributes.push(attribute);
49    }
50}
51
52impl IppOperation for PrintJob {
53    fn into_ipp_request(self, uri: &str) -> IppRequestResponse {
54        let mut retval = IppRequestResponse::new(self.version(), Operation::PrintJob, Some(uri));
55
56        if let Some(ref user_name) = self.user_name {
57            retval.attributes_mut().add(
58                DelimiterTag::OperationAttributes,
59                IppAttribute::new(REQUESTING_USER_NAME, IppValue::NameWithoutLanguage(user_name.clone())),
60            );
61        }
62
63        if let Some(ref job_name) = self.job_name {
64            retval.attributes_mut().add(
65                DelimiterTag::OperationAttributes,
66                IppAttribute::new(JOB_NAME, IppValue::NameWithoutLanguage(job_name.clone())),
67            )
68        }
69
70        for attr in &self.attributes {
71            retval.attributes_mut().add(DelimiterTag::JobAttributes, attr.clone());
72        }
73        retval.add_payload(self.source);
74        retval
75    }
76}
77
78/// IPP operation Get-Printer-Attributes
79#[derive(Default)]
80pub struct GetPrinterAttributes {
81    attributes: Vec<String>,
82}
83
84impl GetPrinterAttributes {
85    /// Create Get-Printer-Attributes operation
86    ///
87    pub fn new() -> GetPrinterAttributes {
88        GetPrinterAttributes::default()
89    }
90
91    /// Set attributes to request from the printer
92    pub fn with_attributes<T>(attributes: &[T]) -> GetPrinterAttributes
93    where
94        T: AsRef<str>,
95    {
96        GetPrinterAttributes {
97            attributes: attributes.iter().map(|a| a.as_ref().to_string()).collect(),
98        }
99    }
100}
101
102impl IppOperation for GetPrinterAttributes {
103    fn into_ipp_request(self, uri: &str) -> IppRequestResponse {
104        let mut retval = IppRequestResponse::new(self.version(), Operation::GetPrinterAttributes, Some(uri));
105
106        if !self.attributes.is_empty() {
107            let vals: Vec<IppValue> = self.attributes.iter().map(|a| IppValue::Keyword(a.clone())).collect();
108            retval.attributes_mut().add(
109                DelimiterTag::OperationAttributes,
110                IppAttribute::new(REQUESTED_ATTRIBUTES, IppValue::ListOf(vals)),
111            );
112        }
113
114        retval
115    }
116}
117
118/// IPP operation Create-Job
119pub struct CreateJob {
120    job_name: Option<String>,
121    attributes: Vec<IppAttribute>,
122}
123
124impl CreateJob {
125    /// Create Create-Job operation
126    ///
127    /// * `job_name` - optional job name (job-name)<br/>
128    pub fn new<T>(job_name: Option<T>) -> CreateJob
129    where
130        T: AsRef<str>,
131    {
132        CreateJob {
133            job_name: job_name.map(|v| v.as_ref().to_string()),
134            attributes: Vec::new(),
135        }
136    }
137
138    /// Set extra job attribute for this operation, for example `colormodel=grayscale`
139    pub fn add_attribute(&mut self, attribute: IppAttribute) {
140        self.attributes.push(attribute);
141    }
142}
143
144impl IppOperation for CreateJob {
145    fn into_ipp_request(self, uri: &str) -> IppRequestResponse {
146        let mut retval = IppRequestResponse::new(self.version(), Operation::CreateJob, Some(uri));
147
148        if let Some(ref job_name) = self.job_name {
149            retval.attributes_mut().add(
150                DelimiterTag::OperationAttributes,
151                IppAttribute::new(JOB_NAME, IppValue::NameWithoutLanguage(job_name.clone())),
152            )
153        }
154
155        for attr in &self.attributes {
156            retval.attributes_mut().add(DelimiterTag::JobAttributes, attr.clone());
157        }
158        retval
159    }
160}
161
162/// IPP operation Send-Document
163pub struct SendDocument {
164    job_id: i32,
165    source: IppJobSource,
166    user_name: Option<String>,
167    last: bool,
168}
169
170impl SendDocument {
171    /// Create Send-Document operation
172    ///
173    /// * `job_id` - job ID returned by Create-Job operation<br/>
174    /// * `source` - `IppJobSource`<br/>
175    /// * `user_name` - name of the user (requesting-user-name)<br/>
176    /// * `last` - whether this document is a last one<br/>
177    pub fn new<S>(job_id: i32, source: IppJobSource, user_name: Option<S>, last: bool) -> SendDocument
178    where
179        S: AsRef<str>,
180    {
181        SendDocument {
182            job_id,
183            source,
184            user_name: user_name.map(|v| v.as_ref().to_string()),
185            last,
186        }
187    }
188}
189
190impl IppOperation for SendDocument {
191    fn into_ipp_request(self, uri: &str) -> IppRequestResponse {
192        let mut retval = IppRequestResponse::new(self.version(), Operation::SendDocument, Some(uri));
193
194        retval.attributes_mut().add(
195            DelimiterTag::OperationAttributes,
196            IppAttribute::new(JOB_ID, IppValue::Integer(self.job_id)),
197        );
198
199        if let Some(user_name) = self.user_name {
200            retval.attributes_mut().add(
201                DelimiterTag::OperationAttributes,
202                IppAttribute::new(REQUESTING_USER_NAME, IppValue::NameWithoutLanguage(user_name.clone())),
203            );
204        }
205
206        retval.attributes_mut().add(
207            DelimiterTag::OperationAttributes,
208            IppAttribute::new(LAST_DOCUMENT, IppValue::Boolean(self.last)),
209        );
210
211        retval.add_payload(self.source);
212
213        retval
214    }
215}