Skip to content

Commit 6af0ac1

Browse files
committed
feat: add raw ipp request constructor and a convenient api to add standard attributes
Signed-off-by: Ayush <[email protected]> feat: add `DeleteAttr` IppValueTag Signed-off-by: Ayush <[email protected]> refacator: use `config::get_user();` instead of reading `USER` env var Signed-off-by: Ayush <[email protected]> test: add test for `new_raw` IppRequest constructor Signed-off-by: Ayush <[email protected]>
1 parent 427bd71 commit 6af0ac1

1 file changed

Lines changed: 77 additions & 16 deletions

File tree

src/ipp.rs

Lines changed: 77 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030
//! }
3131
//! ```
3232
33-
use crate::bindings;
3433
use crate::connection::HttpConnection;
3534
use crate::error::{Error, Result};
35+
use crate::{bindings, config};
3636
use std::ffi::{CStr, CString};
3737
use std::marker::PhantomData;
3838
use std::ptr;
@@ -83,6 +83,7 @@ pub enum IppValueTag {
8383
Charset,
8484
Language,
8585
MimeType,
86+
DeleteAttr,
8687
}
8788

8889
impl From<IppValueTag> for bindings::ipp_tag_t {
@@ -99,6 +100,7 @@ impl From<IppValueTag> for bindings::ipp_tag_t {
99100
IppValueTag::Charset => bindings::ipp_tag_e_IPP_TAG_CHARSET,
100101
IppValueTag::Language => bindings::ipp_tag_e_IPP_TAG_LANGUAGE,
101102
IppValueTag::MimeType => bindings::ipp_tag_e_IPP_TAG_MIMETYPE,
103+
IppValueTag::DeleteAttr => bindings::ipp_tag_e_IPP_TAG_DELETEATTR,
102104
}
103105
}
104106
}
@@ -169,24 +171,18 @@ impl IppStatus {
169171
bindings::ipp_status_e_IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED => {
170172
IppStatus::OkIgnoredOrSubstituted
171173
}
172-
bindings::ipp_status_e_IPP_STATUS_OK_CONFLICTING => {
173-
IppStatus::OkConflicting
174-
}
174+
bindings::ipp_status_e_IPP_STATUS_OK_CONFLICTING => IppStatus::OkConflicting,
175175
bindings::ipp_status_e_IPP_STATUS_ERROR_BAD_REQUEST => IppStatus::ErrorBadRequest,
176176
bindings::ipp_status_e_IPP_STATUS_ERROR_FORBIDDEN => IppStatus::ErrorForbidden,
177177
bindings::ipp_status_e_IPP_STATUS_ERROR_NOT_AUTHENTICATED => {
178178
IppStatus::ErrorNotAuthenticated
179179
}
180-
bindings::ipp_status_e_IPP_STATUS_ERROR_NOT_AUTHORIZED => {
181-
IppStatus::ErrorNotAuthorized
182-
}
180+
bindings::ipp_status_e_IPP_STATUS_ERROR_NOT_AUTHORIZED => IppStatus::ErrorNotAuthorized,
183181
bindings::ipp_status_e_IPP_STATUS_ERROR_NOT_POSSIBLE => IppStatus::ErrorNotPossible,
184182
bindings::ipp_status_e_IPP_STATUS_ERROR_TIMEOUT => IppStatus::ErrorTimeout,
185183
bindings::ipp_status_e_IPP_STATUS_ERROR_NOT_FOUND => IppStatus::ErrorNotFound,
186184
bindings::ipp_status_e_IPP_STATUS_ERROR_GONE => IppStatus::ErrorGone,
187-
bindings::ipp_status_e_IPP_STATUS_ERROR_REQUEST_ENTITY => {
188-
IppStatus::ErrorRequestEntity
189-
}
185+
bindings::ipp_status_e_IPP_STATUS_ERROR_REQUEST_ENTITY => IppStatus::ErrorRequestEntity,
190186
bindings::ipp_status_e_IPP_STATUS_ERROR_REQUEST_VALUE => IppStatus::ErrorRequestValue,
191187
bindings::ipp_status_e_IPP_STATUS_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED => {
192188
IppStatus::ErrorDocumentFormatNotSupported
@@ -248,6 +244,23 @@ impl IppRequest {
248244
})
249245
}
250246

247+
/// Create a new IPP request from a raw operation code.
248+
/// This is useful for deprecated operations.
249+
pub fn new_raw(op_code: i32) -> Result<Self> {
250+
let ipp = unsafe { bindings::ippNewRequest(op_code) };
251+
252+
if ipp.is_null() {
253+
return Err(Error::UnsupportedFeature(
254+
"Failed to create IPP request".to_string(),
255+
));
256+
}
257+
258+
Ok(IppRequest {
259+
ipp,
260+
_phantom: PhantomData,
261+
})
262+
}
263+
251264
/// Get the raw pointer to the ipp_t structure
252265
pub fn as_ptr(&self) -> *mut bindings::_ipp_s {
253266
self.ipp
@@ -320,7 +333,12 @@ impl IppRequest {
320333
let name_c = CString::new(name)?;
321334

322335
let attr = unsafe {
323-
bindings::ippAddBoolean(self.ipp, group.into(), name_c.as_ptr(), value as ::std::os::raw::c_char)
336+
bindings::ippAddBoolean(
337+
self.ipp,
338+
group.into(),
339+
name_c.as_ptr(),
340+
value as ::std::os::raw::c_char,
341+
)
324342
};
325343

326344
if attr.is_null() {
@@ -347,7 +365,8 @@ impl IppRequest {
347365
.map(|v| CString::new(*v).map_err(Error::from))
348366
.collect::<Result<Vec<_>>>()?;
349367

350-
let values_ptrs: Vec<*const ::std::os::raw::c_char> = values_c.iter().map(|s| s.as_ptr()).collect();
368+
let values_ptrs: Vec<*const ::std::os::raw::c_char> =
369+
values_c.iter().map(|s| s.as_ptr()).collect();
351370

352371
let attr = unsafe {
353372
bindings::ippAddStrings(
@@ -371,6 +390,35 @@ impl IppRequest {
371390
}
372391
}
373392

393+
/// Add standard IPP operation attributes:
394+
/// - attributes-charset = "utf-8"
395+
/// - attributes-natural-language = "en"
396+
/// - requesting-user-name = $USER (or "unknown")
397+
pub fn add_standard_attrs(&mut self) -> Result<()> {
398+
let user = config::get_user();
399+
400+
self.add_string(
401+
IppTag::Operation,
402+
IppValueTag::Charset,
403+
"attributes-charset",
404+
"utf-8",
405+
)?;
406+
self.add_string(
407+
IppTag::Operation,
408+
IppValueTag::Language,
409+
"attributes-natural-language",
410+
"en",
411+
)?;
412+
self.add_string(
413+
IppTag::Operation,
414+
IppValueTag::Name,
415+
"requesting-user-name",
416+
&user,
417+
)?;
418+
419+
Ok(())
420+
}
421+
374422
/// Send this request and receive a response
375423
pub fn send(&self, connection: &HttpConnection, resource: &str) -> Result<IppResponse> {
376424
let resource_c = CString::new(resource)?;
@@ -464,11 +512,11 @@ impl IppResponse {
464512
Err(_) => return None,
465513
};
466514

467-
let group_tag = group.map(|g| g.into()).unwrap_or(bindings::ipp_tag_e_IPP_TAG_ZERO);
515+
let group_tag = group
516+
.map(|g| g.into())
517+
.unwrap_or(bindings::ipp_tag_e_IPP_TAG_ZERO);
468518

469-
let attr = unsafe {
470-
bindings::ippFindAttribute(self.ipp, name_c.as_ptr(), group_tag)
471-
};
519+
let attr = unsafe { bindings::ippFindAttribute(self.ipp, name_c.as_ptr(), group_tag) };
472520

473521
if attr.is_null() {
474522
None
@@ -562,6 +610,12 @@ mod tests {
562610
assert!(request.is_ok());
563611
}
564612

613+
#[test]
614+
fn test_ipp_request_creation_from_raw() {
615+
let request = IppRequest::new_raw(bindings::ipp_op_e_IPP_OP_CUPS_SET_DEFAULT);
616+
assert!(request.is_ok());
617+
}
618+
565619
#[test]
566620
fn test_ipp_add_string() {
567621
let mut request = IppRequest::new(IppOperation::GetPrinterAttributes).unwrap();
@@ -588,6 +642,13 @@ mod tests {
588642
assert!(result.is_ok());
589643
}
590644

645+
#[test]
646+
fn test_add_standard_attrs() {
647+
let mut request = IppRequest::new(IppOperation::GetJobs).unwrap();
648+
let result = request.add_standard_attrs();
649+
assert!(result.is_ok());
650+
}
651+
591652
#[test]
592653
fn test_ipp_status() {
593654
assert!(IppStatus::Ok.is_successful());

0 commit comments

Comments
 (0)