3030//! }
3131//! ```
3232
33- use crate :: bindings;
3433use crate :: connection:: HttpConnection ;
3534use crate :: error:: { Error , Result } ;
35+ use crate :: { bindings, config} ;
3636use std:: ffi:: { CStr , CString } ;
3737use std:: marker:: PhantomData ;
3838use std:: ptr;
@@ -83,6 +83,7 @@ pub enum IppValueTag {
8383 Charset ,
8484 Language ,
8585 MimeType ,
86+ DeleteAttr ,
8687}
8788
8889impl 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