1use crate::{
2 config::{CertificateConfig, PrintConfig},
3 error::EricError,
4 error_code::ErrorCode,
5 response::{EricResponse, ResponseBuffer},
6 utils::ToCString,
7 ProcessingFlag,
8};
9use anyhow::{anyhow, Context};
10use eric_bindings::{
11 EricBearbeiteVorgang, EricBeende, EricDekodiereDaten, EricEntladePlugins, EricHoleFehlerText,
12 EricInitialisiere,
13};
14use std::{
15 env::{self},
16 path::Path,
17 ptr,
18};
19
20pub struct Eric;
24
25impl Eric {
26 pub fn new(log_path: &Path) -> Result<Self, EricError> {
30 println!("Initializing eric");
31
32 let plugin_path = env::var("PLUGIN_PATH").ok();
33 let plugin_ptr = match plugin_path {
34 Some(plugin_path) => {
35 println!(
36 "Setting plugin path '{}'",
37 Path::new(&plugin_path).display()
38 );
39
40 plugin_path.try_to_cstring()?.as_ptr()
41 }
42 None => ptr::null(),
43 };
44
45 println!("Setting log path '{}'", log_path.display());
46 println!("Logging to '{}'", log_path.join("eric.log").display());
47
48 let log_path = log_path.try_to_cstring()?;
49
50 let error_code = unsafe { EricInitialisiere(plugin_ptr, log_path.as_ptr()) };
51
52 match error_code {
53 x if x == ErrorCode::ERIC_OK as i32 => Ok(Eric),
54 error_code => Err(EricError::Internal(anyhow!(
55 "Can't init eric: {}",
56 error_code
57 ))),
58 }
59 }
60
61 pub fn validate(
65 &self,
66 xml: String,
67 taxonomy_type: &str,
68 taxonomy_version: &str,
69 pdf_path: Option<&str>,
70 ) -> Result<EricResponse, EricError> {
71 let processing_flag: ProcessingFlag;
72 let type_version = format!("{}_{}", taxonomy_type, taxonomy_version);
73 let print_config = if let Some(pdf_path) = pdf_path {
74 processing_flag = ProcessingFlag::Print;
75 Some(PrintConfig::new(pdf_path, &processing_flag)?)
76 } else {
77 processing_flag = ProcessingFlag::Validate;
78 None
79 };
80 Self::process(xml, type_version, processing_flag, print_config, None, None)
81 }
82
83 pub fn send(
90 &self,
91 xml: String,
92 taxonomy_type: &str,
93 taxonomy_version: &str,
94 pdf_path: Option<&str>,
95 ) -> Result<EricResponse, EricError> {
96 let certificate_path = env::var("CERTIFICATE_PATH")
97 .context("Missing environment variable 'CERTIFICATE_PATH'")?;
98 let certificate_password = env::var("CERTIFICATE_PASSWORD")
99 .context("Missing environment variable 'CERTIFICATE_PASSWORD'")?;
100
101 let processing_flag: ProcessingFlag;
102 let type_version = format!("{}_{}", taxonomy_type, taxonomy_version);
103 let print_config = if let Some(pdf_path) = pdf_path {
104 processing_flag = ProcessingFlag::SendAndPrint;
105 Some(PrintConfig::new(pdf_path, &processing_flag)?)
106 } else {
107 processing_flag = ProcessingFlag::Send;
108 None
109 };
110 let certificate_config = CertificateConfig::new(&certificate_path, &certificate_password)?;
111 Self::process(
112 xml,
113 type_version,
114 processing_flag,
115 print_config,
116 Some(certificate_config),
117 None,
118 )
119 }
120
121 pub fn get_error_text(&self, error_code: i32) -> Result<String, EricError> {
123 let response_buffer = ResponseBuffer::new()?;
124
125 unsafe {
126 EricHoleFehlerText(error_code, response_buffer.as_ptr());
127 }
128
129 Ok(response_buffer.read()?.to_string())
130 }
131
132 #[allow(dead_code)]
133 fn decrypt(
134 &self,
135 encrypted_file: &str,
136 certificate_config: CertificateConfig,
137 ) -> Result<i32, EricError> {
138 let encrypted_data = encrypted_file.try_to_cstring()?;
139 let response_buffer = ResponseBuffer::new()?;
140
141 let error_code = unsafe {
142 EricDekodiereDaten(
143 certificate_config.certificate.handle,
144 certificate_config.password.as_ptr(),
145 encrypted_data.as_ptr(),
146 response_buffer.as_ptr(),
147 )
148 };
149
150 Ok(error_code)
151 }
152
153 fn process(
154 xml: String,
155 type_version: String,
156 processing_flag: ProcessingFlag,
157 print_config: Option<PrintConfig>,
158 certificate_config: Option<CertificateConfig>,
159 transfer_code: Option<u32>,
160 ) -> Result<EricResponse, EricError> {
161 println!("Processing xml file");
162
163 match processing_flag {
164 ProcessingFlag::Validate => println!("Validating xml file"),
165 ProcessingFlag::Print => println!("Validating xml file"),
166 ProcessingFlag::Send => println!("Sending xml file"),
167 ProcessingFlag::SendAndPrint => println!("Send and print"),
168 ProcessingFlag::CheckHints => println!("Check hints"),
169 ProcessingFlag::ValidateWithoutDate => println!("Validate without release date"),
170 }
171
172 let xml = xml.try_to_cstring()?;
173 let type_version = type_version.try_to_cstring()?;
174
175 let transfer_code = match transfer_code {
178 Some(mut code) => &mut code,
179 None => ptr::null::<u32>() as *mut u32,
180 };
181
182 match &print_config {
183 Some(print_config) => println!(
184 "Printing confirmation to file '{}'",
185 print_config
186 .pdf_path
187 .to_str()
188 .context("failed to convert path to string")?
189 ),
190 None => (),
191 }
192
193 let validation_response_buffer = ResponseBuffer::new()?;
194 let server_response_buffer = ResponseBuffer::new()?;
195
196 let error_code = unsafe {
197 EricBearbeiteVorgang(
198 xml.as_ptr(),
199 type_version.as_ptr(),
200 processing_flag.into_u32(),
201 match &print_config {
205 Some(el) => el.print_parameter.as_ptr(),
206 None => ptr::null(),
207 },
208 match &certificate_config {
212 Some(el) => el.certificate_parameter.as_ptr(),
213 None => ptr::null(),
214 },
215 transfer_code,
216 validation_response_buffer.as_ptr(),
217 server_response_buffer.as_ptr(),
218 )
219 };
220
221 let transfer_code = unsafe { transfer_code.as_ref() };
222
223 if let Some(code) = transfer_code {
224 println!("Transfer code: {}", code)
225 }
226
227 let validation_response = validation_response_buffer.read()?;
228 let server_response = server_response_buffer.read()?;
230
231 if error_code != ErrorCode::ERIC_OK as i32 {
232 let response_buffer = ResponseBuffer::new()?;
233 unsafe {
234 EricHoleFehlerText(error_code, response_buffer.as_ptr());
235 }
236 let error_text = response_buffer.read()?;
237 return Err(EricError::ApiError {
238 code: error_code,
239 message: error_text.to_string(),
240 validation_response: validation_response.to_string(),
241 server_response: server_response.to_string(),
242 });
243 }
244
245 let response = EricResponse::new(
246 error_code,
247 validation_response.to_string(),
248 server_response.to_string(),
249 );
250
251 Ok(response)
252 }
253}
254
255impl Drop for Eric {
256 fn drop(&mut self) {
257 println!("Closing eric");
258
259 let error_code = unsafe { EricEntladePlugins() };
260
261 if error_code != ErrorCode::ERIC_OK as i32 {
262 println!("Error while unloading plugins: {}", error_code);
263 }
264
265 let error_code = unsafe { EricBeende() };
266
267 if error_code != ErrorCode::ERIC_OK as i32 {
268 println!("Can't close eric: {}", error_code)
269 }
270 }
271}