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