├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── eric-bindings ├── CHANGELOG.md ├── Cargo.toml ├── bindings │ ├── bindings_eric_38_1_6_0_linux_x86_64.rs │ ├── bindings_eric_39_6_4_0_linux_x86_64.rs │ ├── bindings_eric_40_1_8_0_linux_x86_64.rs │ └── bindings_eric_40_2_10_0_linux_x86_64.rs ├── build.rs └── src │ └── lib.rs ├── eric-sdk ├── CHANGELOG.md ├── Cargo.toml ├── src │ ├── certificate.rs │ ├── config.rs │ ├── eric.rs │ ├── error_code.rs │ ├── lib.rs │ ├── response.rs │ └── utils.rs ├── test_data │ └── taxonomy │ │ └── v6.5 │ │ └── SteuerbilanzAutoverkaeufer_PersG.xml └── tests │ ├── test_send.rs │ └── test_validate.rs ├── rust-toolchain.toml └── rustfmt.toml /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: [main] 5 | pull_request: 6 | env: 7 | CARGO_TERM_COLOR: always 8 | LIBRARY_NAME: ericapi 9 | LIBRARY_PATH: ERiC-39.6.4.0-Linux-x86_64/ERiC-39.6.4.0/Linux-x86_64/lib 10 | HEADER_FILE: ERiC-39.6.4.0-Linux-x86_64/ERiC-39.6.4.0/Linux-x86_64/include/ericapi.h 11 | PLUGIN_PATH: ERiC-39.6.4.0-Linux-x86_64/ERiC-39.6.4.0/Linux-x86_64/lib/plugins2 12 | jobs: 13 | check: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: dtolnay/rust-toolchain@stable 18 | - name: cargo check 19 | run: cargo check --all-targets 20 | clippy: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v4 24 | - uses: dtolnay/rust-toolchain@stable 25 | - name: cargo clippy -- -D warnings 26 | run: cargo clippy --all-targets -- -D warnings 27 | doc: 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v4 31 | - uses: dtolnay/rust-toolchain@stable 32 | - name: cargo doc 33 | run: cargo doc --no-deps 34 | fmt: 35 | runs-on: ubuntu-latest 36 | steps: 37 | - uses: actions/checkout@v4 38 | - uses: dtolnay/rust-toolchain@stable 39 | - name: cargo fmt --check 40 | run: cargo fmt --check 41 | fmt-nightly: 42 | runs-on: ubuntu-latest 43 | steps: 44 | - uses: actions/checkout@v4 45 | - uses: dtolnay/rust-toolchain@nightly 46 | with: 47 | components: rustfmt 48 | - name: cargo +nightly fmt --check 49 | run: cargo +nightly fmt --check 50 | test: 51 | runs-on: ubuntu-latest 52 | steps: 53 | - uses: actions/checkout@v4 54 | - uses: dtolnay/rust-toolchain@stable 55 | - name: cargo test --lib 56 | run: cargo test --lib -p eric-sdk --features no-linking 57 | doc-test: 58 | runs-on: ubuntu-latest 59 | steps: 60 | - uses: actions/checkout@v4 61 | - uses: dtolnay/rust-toolchain@stable 62 | - name: cargo test --doc 63 | run: cargo test --locked --doc -p eric-sdk 64 | package-test: 65 | runs-on: ubuntu-latest 66 | steps: 67 | - uses: actions/checkout@v4 68 | - uses: dtolnay/rust-toolchain@stable 69 | - name: cargo package -p eric-bindings 70 | run: cargo package -p eric-bindings --features docs-rs 71 | - name: cargo package -p eric-sdk 72 | run: cargo package -p eric-sdk --features docs-rs 73 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Rust 2 | /target 3 | 4 | # Eric 5 | **/eric.log 6 | **/*.pdf 7 | 8 | # Environment 9 | **/.env 10 | 11 | # Keys 12 | **/*.jks 13 | **/*.p8 14 | **/*.pem 15 | **/*.pfx 16 | 17 | # VS Code 18 | .vscode 19 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anyhow" 16 | version = "1.0.86" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" 19 | 20 | [[package]] 21 | name = "bindgen" 22 | version = "0.69.4" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" 25 | dependencies = [ 26 | "bitflags", 27 | "cexpr", 28 | "clang-sys", 29 | "itertools", 30 | "lazy_static", 31 | "lazycell", 32 | "log", 33 | "prettyplease", 34 | "proc-macro2", 35 | "quote", 36 | "regex", 37 | "rustc-hash", 38 | "shlex", 39 | "syn", 40 | "which", 41 | ] 42 | 43 | [[package]] 44 | name = "bitflags" 45 | version = "2.6.0" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 48 | 49 | [[package]] 50 | name = "cexpr" 51 | version = "0.6.0" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" 54 | dependencies = [ 55 | "nom", 56 | ] 57 | 58 | [[package]] 59 | name = "cfg-if" 60 | version = "1.0.0" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 63 | 64 | [[package]] 65 | name = "clang-sys" 66 | version = "1.8.1" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" 69 | dependencies = [ 70 | "glob", 71 | "libc", 72 | "libloading", 73 | ] 74 | 75 | [[package]] 76 | name = "either" 77 | version = "1.13.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 80 | 81 | [[package]] 82 | name = "eric-bindings" 83 | version = "0.4.1" 84 | dependencies = [ 85 | "anyhow", 86 | "bindgen", 87 | ] 88 | 89 | [[package]] 90 | name = "eric-sdk" 91 | version = "0.3.1" 92 | dependencies = [ 93 | "anyhow", 94 | "eric-bindings", 95 | "roxmltree", 96 | ] 97 | 98 | [[package]] 99 | name = "errno" 100 | version = "0.3.9" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 103 | dependencies = [ 104 | "libc", 105 | "windows-sys", 106 | ] 107 | 108 | [[package]] 109 | name = "glob" 110 | version = "0.3.1" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 113 | 114 | [[package]] 115 | name = "home" 116 | version = "0.5.9" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" 119 | dependencies = [ 120 | "windows-sys", 121 | ] 122 | 123 | [[package]] 124 | name = "itertools" 125 | version = "0.12.1" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" 128 | dependencies = [ 129 | "either", 130 | ] 131 | 132 | [[package]] 133 | name = "lazy_static" 134 | version = "1.5.0" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 137 | 138 | [[package]] 139 | name = "lazycell" 140 | version = "1.3.0" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 143 | 144 | [[package]] 145 | name = "libc" 146 | version = "0.2.155" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 149 | 150 | [[package]] 151 | name = "libloading" 152 | version = "0.8.5" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" 155 | dependencies = [ 156 | "cfg-if", 157 | "windows-targets", 158 | ] 159 | 160 | [[package]] 161 | name = "linux-raw-sys" 162 | version = "0.4.14" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 165 | 166 | [[package]] 167 | name = "log" 168 | version = "0.4.22" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 171 | 172 | [[package]] 173 | name = "memchr" 174 | version = "2.7.4" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 177 | 178 | [[package]] 179 | name = "minimal-lexical" 180 | version = "0.2.1" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 183 | 184 | [[package]] 185 | name = "nom" 186 | version = "7.1.3" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 189 | dependencies = [ 190 | "memchr", 191 | "minimal-lexical", 192 | ] 193 | 194 | [[package]] 195 | name = "once_cell" 196 | version = "1.19.0" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 199 | 200 | [[package]] 201 | name = "prettyplease" 202 | version = "0.2.20" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" 205 | dependencies = [ 206 | "proc-macro2", 207 | "syn", 208 | ] 209 | 210 | [[package]] 211 | name = "proc-macro2" 212 | version = "1.0.86" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 215 | dependencies = [ 216 | "unicode-ident", 217 | ] 218 | 219 | [[package]] 220 | name = "quote" 221 | version = "1.0.36" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 224 | dependencies = [ 225 | "proc-macro2", 226 | ] 227 | 228 | [[package]] 229 | name = "regex" 230 | version = "1.10.6" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" 233 | dependencies = [ 234 | "aho-corasick", 235 | "memchr", 236 | "regex-automata", 237 | "regex-syntax", 238 | ] 239 | 240 | [[package]] 241 | name = "regex-automata" 242 | version = "0.4.7" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" 245 | dependencies = [ 246 | "aho-corasick", 247 | "memchr", 248 | "regex-syntax", 249 | ] 250 | 251 | [[package]] 252 | name = "regex-syntax" 253 | version = "0.8.4" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" 256 | 257 | [[package]] 258 | name = "roxmltree" 259 | version = "0.20.0" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" 262 | 263 | [[package]] 264 | name = "rustc-hash" 265 | version = "1.1.0" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 268 | 269 | [[package]] 270 | name = "rustix" 271 | version = "0.38.34" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 274 | dependencies = [ 275 | "bitflags", 276 | "errno", 277 | "libc", 278 | "linux-raw-sys", 279 | "windows-sys", 280 | ] 281 | 282 | [[package]] 283 | name = "shlex" 284 | version = "1.3.0" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 287 | 288 | [[package]] 289 | name = "syn" 290 | version = "2.0.72" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" 293 | dependencies = [ 294 | "proc-macro2", 295 | "quote", 296 | "unicode-ident", 297 | ] 298 | 299 | [[package]] 300 | name = "unicode-ident" 301 | version = "1.0.12" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 304 | 305 | [[package]] 306 | name = "which" 307 | version = "4.4.2" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" 310 | dependencies = [ 311 | "either", 312 | "home", 313 | "once_cell", 314 | "rustix", 315 | ] 316 | 317 | [[package]] 318 | name = "windows-sys" 319 | version = "0.52.0" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 322 | dependencies = [ 323 | "windows-targets", 324 | ] 325 | 326 | [[package]] 327 | name = "windows-targets" 328 | version = "0.52.6" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 331 | dependencies = [ 332 | "windows_aarch64_gnullvm", 333 | "windows_aarch64_msvc", 334 | "windows_i686_gnu", 335 | "windows_i686_gnullvm", 336 | "windows_i686_msvc", 337 | "windows_x86_64_gnu", 338 | "windows_x86_64_gnullvm", 339 | "windows_x86_64_msvc", 340 | ] 341 | 342 | [[package]] 343 | name = "windows_aarch64_gnullvm" 344 | version = "0.52.6" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 347 | 348 | [[package]] 349 | name = "windows_aarch64_msvc" 350 | version = "0.52.6" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 353 | 354 | [[package]] 355 | name = "windows_i686_gnu" 356 | version = "0.52.6" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 359 | 360 | [[package]] 361 | name = "windows_i686_gnullvm" 362 | version = "0.52.6" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 365 | 366 | [[package]] 367 | name = "windows_i686_msvc" 368 | version = "0.52.6" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 371 | 372 | [[package]] 373 | name = "windows_x86_64_gnu" 374 | version = "0.52.6" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 377 | 378 | [[package]] 379 | name = "windows_x86_64_gnullvm" 380 | version = "0.52.6" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 383 | 384 | [[package]] 385 | name = "windows_x86_64_msvc" 386 | version = "0.52.6" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 389 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "eric-bindings", 4 | "eric-sdk", 5 | ] 6 | resolver = "2" 7 | 8 | [workspace.package] 9 | authors = ["quambene "] 10 | edition = "2021" 11 | readme = "README.md" 12 | license = "Apache-2.0" 13 | homepage = "https://github.com/quambene/eric-rs" 14 | repository = "https://github.com/quambene/eric-rs" 15 | 16 | [workspace.dependencies] 17 | anyhow = "1.0.86" 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Eric 2 | 3 | [![latest version](https://img.shields.io/crates/v/eric-bindings.svg?label=eric-bindings)](https://crates.io/crates/eric-bindings) 4 | [![documentation](https://img.shields.io/docsrs/eric-bindings?label=eric-bindings)](https://docs.rs/eric-bindings) 5 | [![latest version](https://img.shields.io/crates/v/eric-sdk.svg?label=eric-sdk)](https://crates.io/crates/eric-sdk) 6 | [![documentation](https://img.shields.io/docsrs/eric-sdk?label=eric-sdk)](https://docs.rs/eric-sdk) 7 | [![build status](https://github.com/quambene/eric-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/quambene/eric-rs/actions/workflows/ci.yml) 8 | 9 | Rust bindings and SDK for the ELSTER Rich Client (ERiC) 10 | 11 | - [What is ELSTER?](#what-is-elster) 12 | - [What is ERiC?](#what-is-eric) 13 | - [Requirements](#requirements) 14 | - [Rust bindings](#rust-bindings) 15 | - [Select bindings](#select-bindings) 16 | - [Generate bindings](#generate-bindings) 17 | - [Test bindings](#test-bindings) 18 | - [Eric SDK](#eric-sdk) 19 | - [Usage](#usage) 20 | - [Supported Eric versions](#supported-eric-versions) 21 | - [Test SDK](#test-sdk) 22 | - [Changelog](#changelog) 23 | 24 | ## What is ELSTER? 25 | 26 | Elster (short for _Elektronische Steuererklärung_) is a project by the German tax administration to process tax returns and declarations. 27 | 28 | ## What is ERiC? 29 | 30 | ERiC (short for _Elster Rich Client_) is a shared C library that is integrated into a tax application. ERiC checks the data provided by the tax application for plausibility, and transmits the validated data in encrypted form to the computing center of the respective tax administration. 31 | 32 | ## Requirements 33 | 34 | You need to have the shared library `libericapi.so` and the header file `ericapi.h` available on your system which can be downloaded from [ELSTER for developers](https://www.elster.de/elsterweb/entwickler/login) after access has been requested [here](https://www.elster.de/elsterweb/registrierung-entwickler/form). 35 | 36 | ## Rust bindings 37 | 38 | ### Select bindings 39 | 40 | The bindings are selected from the pre-generated bindings by specifying the 41 | environment variables `PATH_VENDOR`, `LIBRARY_NAME`, `LIBRARY_PATH`, `HEADER_FILE`, and 42 | `PLUGIN_PATH`. For example: 43 | 44 | ``` bash 45 | PATH_VENDOR="ERiC-40.2.10.0-Linux-x86_64/ERiC-40.2.10.0/Linux-x86_64" 46 | LIBRARY_NAME=ericapi 47 | LIBRARY_PATH="$PATH_VENDOR/lib" 48 | HEADER_FILE="$PATH_VENDOR/include/ericapi.h" 49 | PLUGIN_PATH="$PATH_VENDOR/lib/plugins2" 50 | ``` 51 | 52 | ### Generate bindings 53 | 54 | You can also generate bindings on-the-fly for your specific platform and 55 | architecture by using feature flag `generate-bindings`: 56 | 57 | ``` bash 58 | cargo build -p eric-bindings --features generate-bindings 59 | ``` 60 | 61 | The bindings are generated in 62 | `target/debug/build/eric-bindings-/out/bindings.rs`. 63 | 64 | To generate the bindings on your platform and architecture, you need `libclang` as well. For example, on Debian/Ubuntu install: 65 | 66 | ``` bash 67 | apt install llvm-dev libclang-dev clang 68 | ``` 69 | 70 | ### Test bindings 71 | 72 | The bindings are included in `src/lib.rs` via `include!` macro and tested by: 73 | 74 | ``` bash 75 | cargo test -p eric-bindings --lib 76 | ``` 77 | 78 | Logs are written to `eric.log` in the current directory. 79 | 80 | ## Eric SDK 81 | 82 | `eric-sdk` supports single-threaded Eric instances. 83 | 84 | ### Usage 85 | 86 | To use `eric-sdk`, add the shared C library to your path (e.g. to `LD_LIBRARY_PATH` on Linux). 87 | 88 | To send the xml file, the path and password of the Elster certificate have to be provided via environment variables `CERTIFICATE_PATH` and `CERTIFICATE_PASSWORD`. 89 | 90 | ### Supported Eric versions 91 | 92 | | Rust SDK | Eric | 93 | | -------- | -------- | 94 | | 0.1.0 | 38.1.6.0 | 95 | | 0.2.0 | 39.6.4.0 | 96 | | 0.3.0 | 40.1.8.0 | 97 | 98 | ### Test SDK 99 | 100 | ``` bash 101 | # Run unit tests 102 | cargo test -p eric-sdk --lib 103 | 104 | # Run integration tests 105 | cargo test -p eric-sdk --test '*' -- --test-threads=1 106 | 107 | # Run external tests 108 | cargo test -p eric-sdk --test '*' --features external-test -- --test-threads=1 109 | ``` 110 | 111 | ## Changelog 112 | 113 | The `eric-rs` repository contains multiple crates with separate changelogs: 114 | 115 | - `eric-bindings`: [view changelog](https://github.com/quambene/eric-rs/blob/main/eric-bindings/CHANGELOG.md) 116 | - `eric-sdk`: [view changelog](https://github.com/quambene/eric-rs/blob/main/eric-sdk/CHANGELOG.md) 117 | -------------------------------------------------------------------------------- /eric-bindings/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Unreleased 4 | 5 | - added 6 | - changed 7 | - removed 8 | 9 | ## v0.4.2 (unreleased) 10 | 11 | - added 12 | - Test `cargo package` in CI pipeline 13 | 14 | ## v0.4.1 (2024-08-07) 15 | 16 | - added 17 | - Add feature flag `docs-rs` 18 | - changed 19 | - Fix publishing on docs.rs 20 | 21 | ## v0.4.0 (2024-08-07) 22 | 23 | - added 24 | - Add bindings for Eric v40.1.8.0 25 | - Add feature flag `generate-bindings` 26 | - changed 27 | - Select existing bindings 28 | - removed 29 | - Remove feature flag `no-build` 30 | 31 | ## v0.3.0 (2024-08-04) 32 | 33 | - changed 34 | - Support documentation for Eric v39.6.4.0 35 | 36 | ## v0.2.0 (2024-08-04) 37 | 38 | - changed 39 | - Support documentation for Eric v38.1.6.0 40 | - Rename feature from `docs-rs` to `no-build` 41 | 42 | ## v0.1.2 (2024-08-03) 43 | 44 | - changed 45 | - Disable `build.rs` on docs.rs 46 | 47 | ## v0.1.1 (2024-08-03) 48 | 49 | - added 50 | - Add feature flag `docs-rs` 51 | - changed 52 | - Fix documentation on docs.rs 53 | 54 | ## v0.1.0 (2024-08-03) 55 | 56 | - added 57 | - Generate bindings on-the-fly 58 | -------------------------------------------------------------------------------- /eric-bindings/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eric-bindings" 3 | version = "0.4.1" 4 | authors.workspace = true 5 | edition.workspace = true 6 | readme.workspace = true 7 | license.workspace = true 8 | homepage.workspace = true 9 | repository.workspace = true 10 | description = "Rust bindings for the ELSTER Rich Client (ERiC)" 11 | documentation = "https://docs.rs/eric-bindings" 12 | keywords = ["eric", "bindings", "taxes", "accounting"] 13 | categories = ["external-ffi-bindings"] 14 | build = "build.rs" 15 | 16 | [lib] 17 | path = "src/lib.rs" 18 | name = "eric_bindings" 19 | 20 | [package.metadata.docs.rs] 21 | features = ["docs-rs"] 22 | 23 | [features] 24 | default = [] 25 | generate-bindings = ["dep:bindgen"] 26 | # This feature is used in CI pipeline for unit tests. 27 | no-linking = [] 28 | # This feature is used to publish the documentation for `eric-bindings`. 29 | docs-rs = [] 30 | 31 | [dependencies] 32 | anyhow = { workspace = true } 33 | 34 | [build-dependencies] 35 | anyhow = { workspace = true } 36 | bindgen = { version = "0.69.4", optional = true } 37 | -------------------------------------------------------------------------------- /eric-bindings/bindings/bindings_eric_40_2_10_0_linux_x86_64.rs: -------------------------------------------------------------------------------- 1 | /* automatically generated by rust-bindgen 0.69.4 */ 2 | 3 | #[repr(C)] 4 | #[derive(Debug, Copy, Clone)] 5 | pub struct EricInstanz { 6 | _unused: [u8; 0], 7 | } 8 | pub type EricInstanzHandle = *mut EricInstanz; 9 | pub type byteChar = ::std::os::raw::c_char; 10 | pub type BYTE = ::std::os::raw::c_uchar; 11 | pub type EricZertifikatHandle = u32; 12 | pub type EricTransferHandle = u32; 13 | pub const eric_bearbeitung_flag_t_ERIC_VALIDIERE: eric_bearbeitung_flag_t = 2; 14 | pub const eric_bearbeitung_flag_t_ERIC_SENDE: eric_bearbeitung_flag_t = 4; 15 | pub const eric_bearbeitung_flag_t_ERIC_DRUCKE: eric_bearbeitung_flag_t = 32; 16 | pub const eric_bearbeitung_flag_t_ERIC_PRUEFE_HINWEISE: eric_bearbeitung_flag_t = 128; 17 | pub const eric_bearbeitung_flag_t_ERIC_VALIDIERE_OHNE_FREIGABEDATUM: eric_bearbeitung_flag_t = 256; 18 | pub type eric_bearbeitung_flag_t = ::std::os::raw::c_uint; 19 | #[repr(C)] 20 | #[derive(Debug, Copy, Clone)] 21 | pub struct EricReturnBufferApi { 22 | _unused: [u8; 0], 23 | } 24 | pub type EricRueckgabepufferHandle = *mut EricReturnBufferApi; 25 | pub type EricPdfCallback = ::std::option::Option< 26 | unsafe extern "C" fn( 27 | pdfBezeichner: *const ::std::os::raw::c_char, 28 | pdfDaten: *const BYTE, 29 | pdfGroesse: u32, 30 | benutzerDaten: *mut ::std::os::raw::c_void, 31 | ) -> ::std::os::raw::c_int, 32 | >; 33 | #[repr(C)] 34 | #[derive(Debug, Copy, Clone)] 35 | pub struct eric_druck_parameter_t { 36 | pub version: u32, 37 | pub vorschau: u32, 38 | pub duplexDruck: u32, 39 | pub pdfName: *const byteChar, 40 | pub fussText: *const ::std::os::raw::c_char, 41 | pub pdfCallback: EricPdfCallback, 42 | pub pdfCallbackBenutzerdaten: *mut ::std::os::raw::c_void, 43 | } 44 | #[test] 45 | fn bindgen_test_layout_eric_druck_parameter_t() { 46 | const UNINIT: ::std::mem::MaybeUninit = 47 | ::std::mem::MaybeUninit::uninit(); 48 | let ptr = UNINIT.as_ptr(); 49 | assert_eq!( 50 | ::std::mem::size_of::(), 51 | 48usize, 52 | concat!("Size of: ", stringify!(eric_druck_parameter_t)) 53 | ); 54 | assert_eq!( 55 | ::std::mem::align_of::(), 56 | 8usize, 57 | concat!("Alignment of ", stringify!(eric_druck_parameter_t)) 58 | ); 59 | assert_eq!( 60 | unsafe { ::std::ptr::addr_of!((*ptr).version) as usize - ptr as usize }, 61 | 0usize, 62 | concat!( 63 | "Offset of field: ", 64 | stringify!(eric_druck_parameter_t), 65 | "::", 66 | stringify!(version) 67 | ) 68 | ); 69 | assert_eq!( 70 | unsafe { ::std::ptr::addr_of!((*ptr).vorschau) as usize - ptr as usize }, 71 | 4usize, 72 | concat!( 73 | "Offset of field: ", 74 | stringify!(eric_druck_parameter_t), 75 | "::", 76 | stringify!(vorschau) 77 | ) 78 | ); 79 | assert_eq!( 80 | unsafe { ::std::ptr::addr_of!((*ptr).duplexDruck) as usize - ptr as usize }, 81 | 8usize, 82 | concat!( 83 | "Offset of field: ", 84 | stringify!(eric_druck_parameter_t), 85 | "::", 86 | stringify!(duplexDruck) 87 | ) 88 | ); 89 | assert_eq!( 90 | unsafe { ::std::ptr::addr_of!((*ptr).pdfName) as usize - ptr as usize }, 91 | 16usize, 92 | concat!( 93 | "Offset of field: ", 94 | stringify!(eric_druck_parameter_t), 95 | "::", 96 | stringify!(pdfName) 97 | ) 98 | ); 99 | assert_eq!( 100 | unsafe { ::std::ptr::addr_of!((*ptr).fussText) as usize - ptr as usize }, 101 | 24usize, 102 | concat!( 103 | "Offset of field: ", 104 | stringify!(eric_druck_parameter_t), 105 | "::", 106 | stringify!(fussText) 107 | ) 108 | ); 109 | assert_eq!( 110 | unsafe { ::std::ptr::addr_of!((*ptr).pdfCallback) as usize - ptr as usize }, 111 | 32usize, 112 | concat!( 113 | "Offset of field: ", 114 | stringify!(eric_druck_parameter_t), 115 | "::", 116 | stringify!(pdfCallback) 117 | ) 118 | ); 119 | assert_eq!( 120 | unsafe { ::std::ptr::addr_of!((*ptr).pdfCallbackBenutzerdaten) as usize - ptr as usize }, 121 | 40usize, 122 | concat!( 123 | "Offset of field: ", 124 | stringify!(eric_druck_parameter_t), 125 | "::", 126 | stringify!(pdfCallbackBenutzerdaten) 127 | ) 128 | ); 129 | } 130 | #[repr(C)] 131 | #[derive(Debug, Copy, Clone)] 132 | pub struct eric_verschluesselungs_parameter_t { 133 | pub version: u32, 134 | pub zertifikatHandle: EricZertifikatHandle, 135 | pub pin: *const ::std::os::raw::c_char, 136 | } 137 | #[test] 138 | fn bindgen_test_layout_eric_verschluesselungs_parameter_t() { 139 | const UNINIT: ::std::mem::MaybeUninit = 140 | ::std::mem::MaybeUninit::uninit(); 141 | let ptr = UNINIT.as_ptr(); 142 | assert_eq!( 143 | ::std::mem::size_of::(), 144 | 16usize, 145 | concat!("Size of: ", stringify!(eric_verschluesselungs_parameter_t)) 146 | ); 147 | assert_eq!( 148 | ::std::mem::align_of::(), 149 | 8usize, 150 | concat!( 151 | "Alignment of ", 152 | stringify!(eric_verschluesselungs_parameter_t) 153 | ) 154 | ); 155 | assert_eq!( 156 | unsafe { ::std::ptr::addr_of!((*ptr).version) as usize - ptr as usize }, 157 | 0usize, 158 | concat!( 159 | "Offset of field: ", 160 | stringify!(eric_verschluesselungs_parameter_t), 161 | "::", 162 | stringify!(version) 163 | ) 164 | ); 165 | assert_eq!( 166 | unsafe { ::std::ptr::addr_of!((*ptr).zertifikatHandle) as usize - ptr as usize }, 167 | 4usize, 168 | concat!( 169 | "Offset of field: ", 170 | stringify!(eric_verschluesselungs_parameter_t), 171 | "::", 172 | stringify!(zertifikatHandle) 173 | ) 174 | ); 175 | assert_eq!( 176 | unsafe { ::std::ptr::addr_of!((*ptr).pin) as usize - ptr as usize }, 177 | 8usize, 178 | concat!( 179 | "Offset of field: ", 180 | stringify!(eric_verschluesselungs_parameter_t), 181 | "::", 182 | stringify!(pin) 183 | ) 184 | ); 185 | } 186 | #[repr(C)] 187 | #[derive(Debug, Copy, Clone)] 188 | pub struct eric_zertifikat_parameter_t { 189 | pub version: u32, 190 | pub name: *const ::std::os::raw::c_char, 191 | pub land: *const ::std::os::raw::c_char, 192 | pub ort: *const ::std::os::raw::c_char, 193 | pub adresse: *const ::std::os::raw::c_char, 194 | pub email: *const ::std::os::raw::c_char, 195 | pub organisation: *const ::std::os::raw::c_char, 196 | pub abteilung: *const ::std::os::raw::c_char, 197 | pub beschreibung: *const ::std::os::raw::c_char, 198 | } 199 | #[test] 200 | fn bindgen_test_layout_eric_zertifikat_parameter_t() { 201 | const UNINIT: ::std::mem::MaybeUninit = 202 | ::std::mem::MaybeUninit::uninit(); 203 | let ptr = UNINIT.as_ptr(); 204 | assert_eq!( 205 | ::std::mem::size_of::(), 206 | 72usize, 207 | concat!("Size of: ", stringify!(eric_zertifikat_parameter_t)) 208 | ); 209 | assert_eq!( 210 | ::std::mem::align_of::(), 211 | 8usize, 212 | concat!("Alignment of ", stringify!(eric_zertifikat_parameter_t)) 213 | ); 214 | assert_eq!( 215 | unsafe { ::std::ptr::addr_of!((*ptr).version) as usize - ptr as usize }, 216 | 0usize, 217 | concat!( 218 | "Offset of field: ", 219 | stringify!(eric_zertifikat_parameter_t), 220 | "::", 221 | stringify!(version) 222 | ) 223 | ); 224 | assert_eq!( 225 | unsafe { ::std::ptr::addr_of!((*ptr).name) as usize - ptr as usize }, 226 | 8usize, 227 | concat!( 228 | "Offset of field: ", 229 | stringify!(eric_zertifikat_parameter_t), 230 | "::", 231 | stringify!(name) 232 | ) 233 | ); 234 | assert_eq!( 235 | unsafe { ::std::ptr::addr_of!((*ptr).land) as usize - ptr as usize }, 236 | 16usize, 237 | concat!( 238 | "Offset of field: ", 239 | stringify!(eric_zertifikat_parameter_t), 240 | "::", 241 | stringify!(land) 242 | ) 243 | ); 244 | assert_eq!( 245 | unsafe { ::std::ptr::addr_of!((*ptr).ort) as usize - ptr as usize }, 246 | 24usize, 247 | concat!( 248 | "Offset of field: ", 249 | stringify!(eric_zertifikat_parameter_t), 250 | "::", 251 | stringify!(ort) 252 | ) 253 | ); 254 | assert_eq!( 255 | unsafe { ::std::ptr::addr_of!((*ptr).adresse) as usize - ptr as usize }, 256 | 32usize, 257 | concat!( 258 | "Offset of field: ", 259 | stringify!(eric_zertifikat_parameter_t), 260 | "::", 261 | stringify!(adresse) 262 | ) 263 | ); 264 | assert_eq!( 265 | unsafe { ::std::ptr::addr_of!((*ptr).email) as usize - ptr as usize }, 266 | 40usize, 267 | concat!( 268 | "Offset of field: ", 269 | stringify!(eric_zertifikat_parameter_t), 270 | "::", 271 | stringify!(email) 272 | ) 273 | ); 274 | assert_eq!( 275 | unsafe { ::std::ptr::addr_of!((*ptr).organisation) as usize - ptr as usize }, 276 | 48usize, 277 | concat!( 278 | "Offset of field: ", 279 | stringify!(eric_zertifikat_parameter_t), 280 | "::", 281 | stringify!(organisation) 282 | ) 283 | ); 284 | assert_eq!( 285 | unsafe { ::std::ptr::addr_of!((*ptr).abteilung) as usize - ptr as usize }, 286 | 56usize, 287 | concat!( 288 | "Offset of field: ", 289 | stringify!(eric_zertifikat_parameter_t), 290 | "::", 291 | stringify!(abteilung) 292 | ) 293 | ); 294 | assert_eq!( 295 | unsafe { ::std::ptr::addr_of!((*ptr).beschreibung) as usize - ptr as usize }, 296 | 64usize, 297 | concat!( 298 | "Offset of field: ", 299 | stringify!(eric_zertifikat_parameter_t), 300 | "::", 301 | stringify!(beschreibung) 302 | ) 303 | ); 304 | } 305 | #[doc = " Fehler, der zum Programmabbruch führt."] 306 | pub const eric_log_level_t_ERIC_LOG_ERROR: eric_log_level_t = 4; 307 | #[doc = " Hinweise auf Zustände, die zu Fehlern führen können."] 308 | pub const eric_log_level_t_ERIC_LOG_WARN: eric_log_level_t = 3; 309 | #[doc = " Grobe Informationen über den Programmablauf und Werte."] 310 | pub const eric_log_level_t_ERIC_LOG_INFO: eric_log_level_t = 2; 311 | #[doc = " Feingranulare Informationen über den Programmablauf und Werte."] 312 | pub const eric_log_level_t_ERIC_LOG_DEBUG: eric_log_level_t = 1; 313 | #[doc = " Sehr feingranulare Informationen über den Programmablauf und Werte."] 314 | pub const eric_log_level_t_ERIC_LOG_TRACE: eric_log_level_t = 0; 315 | pub type eric_log_level_t = ::std::os::raw::c_uint; 316 | pub type EricLogCallback = ::std::option::Option< 317 | unsafe extern "C" fn( 318 | kategorie: *const ::std::os::raw::c_char, 319 | loglevel: eric_log_level_t, 320 | nachricht: *const ::std::os::raw::c_char, 321 | benutzerdaten: *mut ::std::os::raw::c_void, 322 | ), 323 | >; 324 | pub const ERIC_FORTSCHRITTCALLBACK_ID_EINLESEN: _bindgen_ty_1 = 10; 325 | pub const ERIC_FORTSCHRITTCALLBACK_ID_VORBEREITEN: _bindgen_ty_1 = 20; 326 | pub const ERIC_FORTSCHRITTCALLBACK_ID_VALIDIEREN: _bindgen_ty_1 = 30; 327 | pub const ERIC_FORTSCHRITTCALLBACK_ID_SENDEN: _bindgen_ty_1 = 40; 328 | pub const ERIC_FORTSCHRITTCALLBACK_ID_DRUCKEN: _bindgen_ty_1 = 50; 329 | pub type _bindgen_ty_1 = ::std::os::raw::c_uint; 330 | pub type EricFortschrittCallback = ::std::option::Option< 331 | unsafe extern "C" fn(id: u32, pos: u32, max: u32, benutzerdaten: *mut ::std::os::raw::c_void), 332 | >; 333 | extern "C" { 334 | pub fn EricBearbeiteVorgang( 335 | datenpuffer: *const ::std::os::raw::c_char, 336 | datenartVersion: *const ::std::os::raw::c_char, 337 | bearbeitungsFlags: u32, 338 | druckParameter: *const eric_druck_parameter_t, 339 | cryptoParameter: *const eric_verschluesselungs_parameter_t, 340 | transferHandle: *mut EricTransferHandle, 341 | rueckgabeXmlPuffer: EricRueckgabepufferHandle, 342 | serverantwortXmlPuffer: EricRueckgabepufferHandle, 343 | ) -> ::std::os::raw::c_int; 344 | } 345 | extern "C" { 346 | pub fn EricBeende() -> ::std::os::raw::c_int; 347 | } 348 | extern "C" { 349 | pub fn EricChangePassword( 350 | psePath: *const byteChar, 351 | oldPin: *const byteChar, 352 | newPin: *const byteChar, 353 | ) -> ::std::os::raw::c_int; 354 | } 355 | extern "C" { 356 | pub fn EricPruefeBuFaNummer(steuernummer: *const byteChar) -> ::std::os::raw::c_int; 357 | } 358 | extern "C" { 359 | pub fn EricCheckXML( 360 | xml: *const ::std::os::raw::c_char, 361 | datenartVersion: *const ::std::os::raw::c_char, 362 | fehlertextPuffer: EricRueckgabepufferHandle, 363 | ) -> ::std::os::raw::c_int; 364 | } 365 | extern "C" { 366 | pub fn EricCloseHandleToCertificate(hToken: EricZertifikatHandle) -> ::std::os::raw::c_int; 367 | } 368 | extern "C" { 369 | pub fn EricCreateKey( 370 | pin: *const byteChar, 371 | pfad: *const byteChar, 372 | zertifikatInfo: *const eric_zertifikat_parameter_t, 373 | ) -> ::std::os::raw::c_int; 374 | } 375 | extern "C" { 376 | pub fn EricCreateTH( 377 | xml: *const ::std::os::raw::c_char, 378 | verfahren: *const ::std::os::raw::c_char, 379 | datenart: *const ::std::os::raw::c_char, 380 | vorgang: *const ::std::os::raw::c_char, 381 | testmerker: *const ::std::os::raw::c_char, 382 | herstellerId: *const ::std::os::raw::c_char, 383 | datenLieferant: *const ::std::os::raw::c_char, 384 | versionClient: *const ::std::os::raw::c_char, 385 | publicKey: *const byteChar, 386 | xmlRueckgabePuffer: EricRueckgabepufferHandle, 387 | ) -> ::std::os::raw::c_int; 388 | } 389 | extern "C" { 390 | pub fn EricCreateUUID(uuidRueckgabePuffer: EricRueckgabepufferHandle) -> ::std::os::raw::c_int; 391 | } 392 | extern "C" { 393 | pub fn EricDekodiereDaten( 394 | zertifikatHandle: EricZertifikatHandle, 395 | pin: *const byteChar, 396 | base64Eingabe: *const byteChar, 397 | rueckgabePuffer: EricRueckgabepufferHandle, 398 | ) -> ::std::os::raw::c_int; 399 | } 400 | extern "C" { 401 | pub fn EricEinstellungAlleZuruecksetzen() -> ::std::os::raw::c_int; 402 | } 403 | extern "C" { 404 | pub fn EricEinstellungLesen( 405 | name: *const ::std::os::raw::c_char, 406 | rueckgabePuffer: EricRueckgabepufferHandle, 407 | ) -> ::std::os::raw::c_int; 408 | } 409 | extern "C" { 410 | pub fn EricEinstellungSetzen( 411 | name: *const ::std::os::raw::c_char, 412 | wert: *const ::std::os::raw::c_char, 413 | ) -> ::std::os::raw::c_int; 414 | } 415 | extern "C" { 416 | pub fn EricEinstellungZuruecksetzen( 417 | name: *const ::std::os::raw::c_char, 418 | ) -> ::std::os::raw::c_int; 419 | } 420 | extern "C" { 421 | pub fn EricEntladePlugins() -> ::std::os::raw::c_int; 422 | } 423 | extern "C" { 424 | pub fn EricFormatEWAz( 425 | ewAzElster: *const byteChar, 426 | ewAzBescheidPuffer: EricRueckgabepufferHandle, 427 | ) -> ::std::os::raw::c_int; 428 | } 429 | extern "C" { 430 | pub fn EricFormatStNr( 431 | eingabeSteuernummer: *const byteChar, 432 | rueckgabePuffer: EricRueckgabepufferHandle, 433 | ) -> ::std::os::raw::c_int; 434 | } 435 | extern "C" { 436 | pub fn EricGetAuswahlListen( 437 | datenartVersion: *const ::std::os::raw::c_char, 438 | feldkennung: *const ::std::os::raw::c_char, 439 | rueckgabeXmlPuffer: EricRueckgabepufferHandle, 440 | ) -> ::std::os::raw::c_int; 441 | } 442 | extern "C" { 443 | pub fn EricGetErrormessagesFromXMLAnswer( 444 | xml: *const ::std::os::raw::c_char, 445 | transferticketPuffer: EricRueckgabepufferHandle, 446 | returncodeTHPuffer: EricRueckgabepufferHandle, 447 | fehlertextTHPuffer: EricRueckgabepufferHandle, 448 | returncodesUndFehlertexteNDHXmlPuffer: EricRueckgabepufferHandle, 449 | ) -> ::std::os::raw::c_int; 450 | } 451 | extern "C" { 452 | pub fn EricGetHandleToCertificate( 453 | hToken: *mut EricZertifikatHandle, 454 | iInfoPinSupport: *mut u32, 455 | pathToKeystore: *const byteChar, 456 | ) -> ::std::os::raw::c_int; 457 | } 458 | extern "C" { 459 | pub fn EricGetPinStatus( 460 | hToken: EricZertifikatHandle, 461 | pinStatus: *mut u32, 462 | keyType: u32, 463 | ) -> ::std::os::raw::c_int; 464 | } 465 | extern "C" { 466 | pub fn EricGetPublicKey( 467 | cryptoParameter: *const eric_verschluesselungs_parameter_t, 468 | rueckgabePuffer: EricRueckgabepufferHandle, 469 | ) -> ::std::os::raw::c_int; 470 | } 471 | extern "C" { 472 | pub fn EricHoleFehlerText( 473 | fehlerkode: ::std::os::raw::c_int, 474 | rueckgabePuffer: EricRueckgabepufferHandle, 475 | ) -> ::std::os::raw::c_int; 476 | } 477 | extern "C" { 478 | pub fn EricHoleFinanzaemter( 479 | finanzamtLandNummer: *const byteChar, 480 | rueckgabeXmlPuffer: EricRueckgabepufferHandle, 481 | ) -> ::std::os::raw::c_int; 482 | } 483 | extern "C" { 484 | pub fn EricHoleFinanzamtLandNummern( 485 | rueckgabeXmlPuffer: EricRueckgabepufferHandle, 486 | ) -> ::std::os::raw::c_int; 487 | } 488 | extern "C" { 489 | pub fn EricHoleFinanzamtsdaten( 490 | bufaNr: *const byteChar, 491 | rueckgabeXmlPuffer: EricRueckgabepufferHandle, 492 | ) -> ::std::os::raw::c_int; 493 | } 494 | extern "C" { 495 | pub fn EricHoleTestfinanzaemter( 496 | rueckgabeXmlPuffer: EricRueckgabepufferHandle, 497 | ) -> ::std::os::raw::c_int; 498 | } 499 | extern "C" { 500 | pub fn EricHoleZertifikatEigenschaften( 501 | hToken: EricZertifikatHandle, 502 | pin: *const byteChar, 503 | rueckgabeXmlPuffer: EricRueckgabepufferHandle, 504 | ) -> ::std::os::raw::c_int; 505 | } 506 | extern "C" { 507 | pub fn EricHoleZertifikatFingerabdruck( 508 | cryptoParameter: *const eric_verschluesselungs_parameter_t, 509 | fingerabdruckPuffer: EricRueckgabepufferHandle, 510 | signaturPuffer: EricRueckgabepufferHandle, 511 | ) -> ::std::os::raw::c_int; 512 | } 513 | extern "C" { 514 | pub fn EricInitialisiere( 515 | pluginPfad: *const byteChar, 516 | logPfad: *const byteChar, 517 | ) -> ::std::os::raw::c_int; 518 | } 519 | extern "C" { 520 | pub fn EricMakeElsterStnr( 521 | steuernrBescheid: *const byteChar, 522 | landesnr: *const byteChar, 523 | bundesfinanzamtsnr: *const byteChar, 524 | steuernrPuffer: EricRueckgabepufferHandle, 525 | ) -> ::std::os::raw::c_int; 526 | } 527 | extern "C" { 528 | pub fn EricMakeElsterEWAz( 529 | ewAzBescheid: *const byteChar, 530 | landeskuerzel: *const byteChar, 531 | ewAzElsterPuffer: EricRueckgabepufferHandle, 532 | ) -> ::std::os::raw::c_int; 533 | } 534 | extern "C" { 535 | pub fn EricPruefeBIC(bic: *const byteChar) -> ::std::os::raw::c_int; 536 | } 537 | extern "C" { 538 | pub fn EricPruefeIBAN(iban: *const byteChar) -> ::std::os::raw::c_int; 539 | } 540 | extern "C" { 541 | pub fn EricPruefeEWAz(einheitswertAz: *const byteChar) -> ::std::os::raw::c_int; 542 | } 543 | extern "C" { 544 | pub fn EricPruefeIdentifikationsMerkmal(steuerId: *const byteChar) -> ::std::os::raw::c_int; 545 | } 546 | extern "C" { 547 | pub fn EricPruefeSteuernummer(steuernummer: *const byteChar) -> ::std::os::raw::c_int; 548 | } 549 | extern "C" { 550 | pub fn EricPruefeZertifikatPin( 551 | pathToKeystore: *const byteChar, 552 | pin: *const byteChar, 553 | keyType: u32, 554 | ) -> ::std::os::raw::c_int; 555 | } 556 | extern "C" { 557 | pub fn EricRegistriereFortschrittCallback( 558 | funktion: EricFortschrittCallback, 559 | benutzerdaten: *mut ::std::os::raw::c_void, 560 | ) -> ::std::os::raw::c_int; 561 | } 562 | extern "C" { 563 | pub fn EricRegistriereGlobalenFortschrittCallback( 564 | funktion: EricFortschrittCallback, 565 | benutzerdaten: *mut ::std::os::raw::c_void, 566 | ) -> ::std::os::raw::c_int; 567 | } 568 | extern "C" { 569 | pub fn EricRegistriereLogCallback( 570 | funktion: EricLogCallback, 571 | schreibeEricLogDatei: u32, 572 | benutzerdaten: *mut ::std::os::raw::c_void, 573 | ) -> ::std::os::raw::c_int; 574 | } 575 | extern "C" { 576 | pub fn EricRueckgabepufferErzeugen() -> EricRueckgabepufferHandle; 577 | } 578 | extern "C" { 579 | pub fn EricRueckgabepufferFreigeben(handle: EricRueckgabepufferHandle) 580 | -> ::std::os::raw::c_int; 581 | } 582 | extern "C" { 583 | pub fn EricRueckgabepufferInhalt( 584 | handle: EricRueckgabepufferHandle, 585 | ) -> *const ::std::os::raw::c_char; 586 | } 587 | extern "C" { 588 | pub fn EricRueckgabepufferLaenge(handle: EricRueckgabepufferHandle) -> u32; 589 | } 590 | extern "C" { 591 | pub fn EricSystemCheck() -> ::std::os::raw::c_int; 592 | } 593 | extern "C" { 594 | pub fn EricVersion(rueckgabeXmlPuffer: EricRueckgabepufferHandle) -> ::std::os::raw::c_int; 595 | } 596 | -------------------------------------------------------------------------------- /eric-bindings/build.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | env, fmt, io, 3 | path::{Path, PathBuf}, 4 | }; 5 | 6 | #[derive(Debug)] 7 | pub enum EricVersion { 8 | Eric38_1_6_0, 9 | Eric39_6_4_0, 10 | Eric40_1_8_0, 11 | Eric40_2_10_0, 12 | } 13 | 14 | impl fmt::Display for EricVersion { 15 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 16 | let request_method = match self { 17 | Self::Eric38_1_6_0 => "38.1.6.0", 18 | Self::Eric39_6_4_0 => "39.6.4.0", 19 | Self::Eric40_1_8_0 => "40.1.8.0", 20 | Self::Eric40_2_10_0 => "40.2.10.0", 21 | }; 22 | 23 | write!(f, "{}", request_method) 24 | } 25 | } 26 | 27 | pub fn main() -> io::Result<()> { 28 | #[cfg(feature = "generate-bindings")] 29 | generate_bindings()?; 30 | 31 | #[cfg(not(feature = "generate-bindings"))] 32 | { 33 | #[cfg(not(feature = "docs-rs"))] 34 | select_bindings()?; 35 | 36 | #[cfg(feature = "docs-rs")] 37 | select_bindings_for_docs_rs()?; 38 | } 39 | 40 | Ok(()) 41 | } 42 | 43 | /// Select existing bindings 44 | #[cfg(not(feature = "generate-bindings"))] 45 | #[cfg(not(feature = "docs-rs"))] 46 | fn select_bindings() -> io::Result<()> { 47 | let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").expect("Set by cargo"); 48 | let is_windows = std::env::var("CARGO_CFG_WINDOWS").is_ok(); 49 | let library_name = 50 | env::var("LIBRARY_NAME").expect("Missing environment variable 'LIBRARY_NAME'"); 51 | let library_path = 52 | env::var("LIBRARY_PATH").expect("Missing environment variable 'LIBRARY_PATH'"); 53 | let header_file = env::var("HEADER_FILE").expect("Missing environment variable 'HEADER_FILE'"); 54 | let out_dir = env::var("OUT_DIR").expect("Can't read environment variable 'OUT_DIR'"); 55 | let bindings_target = PathBuf::from(out_dir).join("bindings.rs"); 56 | 57 | #[cfg(not(feature = "no-linking"))] 58 | { 59 | println!("cargo:rustc-link-search={}", library_path); 60 | println!("cargo:rustc-link-lib={}", library_name); 61 | println!("cargo:rerun-if-changed={}", header_file); 62 | println!("cargo:rustc-env=LD_LIBRARY_PATH={}", library_path); 63 | } 64 | 65 | let eric_version = if library_path.contains("38.1.6.0") { 66 | EricVersion::Eric38_1_6_0 67 | } else if library_path.contains("39.6.4.0") { 68 | EricVersion::Eric39_6_4_0 69 | } else if library_path.contains("40.1.8.0") { 70 | EricVersion::Eric40_1_8_0 71 | } else if library_path.contains("40.2.10.0") { 72 | EricVersion::Eric40_2_10_0 73 | } else { 74 | panic!("Missing bindings: Unknown Eric version"); 75 | }; 76 | let bindings_file = match (&eric_version, target_arch.as_ref(), is_windows) { 77 | (EricVersion::Eric38_1_6_0, "x86_64", false) => "bindings_eric_38_1_6_0_linux_x86_64.rs", 78 | (EricVersion::Eric39_6_4_0, "x86_64", false) => "bindings_eric_39_6_4_0_linux_x86_64.rs", 79 | (EricVersion::Eric40_1_8_0, "x86_64", false) => "bindings_eric_40_1_8_0_linux_x86_64.rs", 80 | (EricVersion::Eric40_2_10_0, "x86_64", false) => "bindings_eric_40_2_10_0_linux_x86_64.rs", 81 | _ => { 82 | panic!("Missing bindings for Eric version {eric_version} and target {target_arch}"); 83 | } 84 | }; 85 | 86 | println!("Select bindings for Eric version {eric_version} and target {target_arch}"); 87 | 88 | let root_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Set by cargo"); 89 | let bindings_path = Path::new(&root_dir).join("bindings").join(bindings_file); 90 | 91 | std::fs::copy(bindings_path.clone(), bindings_target.clone()).unwrap_or_else(|_| { 92 | panic!( 93 | "Can't copy file from {} to {}", 94 | bindings_path.display(), 95 | bindings_target.display(), 96 | ) 97 | }); 98 | 99 | Ok(()) 100 | } 101 | 102 | /// Generate bindings on-the-fly 103 | #[cfg(feature = "generate-bindings")] 104 | fn generate_bindings() -> io::Result<()> { 105 | let library_name = 106 | env::var("LIBRARY_NAME").expect("Missing environment variable 'LIBRARY_NAME'"); 107 | let library_path = 108 | env::var("LIBRARY_PATH").expect("Missing environment variable 'LIBRARY_PATH'"); 109 | let header_file = env::var("HEADER_FILE").expect("Missing environment variable 'HEADER_FILE'"); 110 | 111 | let library_path = Path::new(&library_path); 112 | let header_file = Path::new(&header_file); 113 | 114 | println!("cargo:rustc-link-search={}", library_path.display()); 115 | println!("cargo:rustc-link-lib={}", library_name); 116 | println!("cargo:rerun-if-changed={}", header_file.display()); 117 | println!("cargo:rustc-env=LD_LIBRARY_PATH={}", library_path.display()); 118 | 119 | let header = header_file.to_str().expect("Can't convert path to string"); 120 | 121 | let bindings = bindgen::Builder::default() 122 | .header(header) 123 | .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) 124 | .generate() 125 | .expect("Can't generate bindings"); 126 | 127 | let out_dir = env::var("OUT_DIR").expect("Can't read environment variable 'OUT_DIR'"); 128 | let output_path = PathBuf::from(out_dir); 129 | 130 | bindings 131 | .write_to_file(output_path.join("bindings.rs")) 132 | .expect("Can't write bindings"); 133 | 134 | Ok(()) 135 | } 136 | 137 | /// Select latest bindings for documentation on docs.rs 138 | #[cfg(feature = "docs-rs")] 139 | fn select_bindings_for_docs_rs() -> io::Result<()> { 140 | let bindings_file = "bindings_eric_40_1_8_0_linux_x86_64.rs"; 141 | 142 | let root_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Set by cargo"); 143 | let bindings_path = Path::new(&root_dir).join("bindings").join(bindings_file); 144 | 145 | let out_dir = env::var("OUT_DIR").expect("Can't read environment variable 'OUT_DIR'"); 146 | let bindings_target = PathBuf::from(out_dir).join("bindings.rs"); 147 | 148 | std::fs::copy(bindings_path.clone(), bindings_target.clone()).unwrap_or_else(|_| { 149 | panic!( 150 | "Can't copy file from {} to {}", 151 | bindings_path.display(), 152 | bindings_target.display(), 153 | ) 154 | }); 155 | Ok(()) 156 | } 157 | -------------------------------------------------------------------------------- /eric-bindings/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals)] 2 | #![allow(non_camel_case_types)] 3 | #![allow(non_snake_case)] 4 | #![allow(dead_code)] 5 | // TODO: extern block uses type u128, which is not FFI-safe 6 | #![allow(improper_ctypes)] 7 | 8 | include!(concat!(env!("OUT_DIR"), "/bindings.rs")); 9 | 10 | #[cfg(test)] 11 | mod tests { 12 | use super::*; 13 | use anyhow::Context; 14 | use std::{env, ffi::CString}; 15 | 16 | #[test] 17 | fn test_ericapi() { 18 | let plugin_path = 19 | env::var("PLUGIN_PATH").expect("Missing environment variable 'PLUGIN_PATH'"); 20 | let plugin_path = CString::new(plugin_path) 21 | .context("Can't convert to CString") 22 | .unwrap(); 23 | 24 | let log_path = 25 | env::current_dir().expect("Missing environment variable for current directory"); 26 | let log_path = CString::new(log_path.to_str().unwrap()) 27 | .context("Can't convert to CString") 28 | .unwrap(); 29 | 30 | unsafe { 31 | let error_code = EricInitialisiere(plugin_path.as_ptr(), log_path.as_ptr()); 32 | assert_eq!(error_code, 0); 33 | 34 | let buffer = EricRueckgabepufferErzeugen(); 35 | let error_code = EricVersion(buffer); 36 | assert_eq!(error_code, 0); 37 | 38 | let error_code = EricBeende(); 39 | assert_eq!(error_code, 0); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /eric-sdk/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Unreleased 4 | 5 | - added 6 | - changed 7 | - removed 8 | 9 | ## v0.3.2 (unreleased) 10 | 11 | - added 12 | - Test `cargo package` in CI pipeline 13 | 14 | ## v0.3.1 (2024-08-07) 15 | 16 | - added 17 | - Add feature flag `docs-rs` 18 | - changed 19 | - Fix publishing on docs.rs 20 | 21 | ## v0.3.0 (2024-08-07) 22 | 23 | - added 24 | - Support ERiC v40.1.8.0 25 | 26 | ## v0.2.0 (2024-08-05) 27 | 28 | - added 29 | - Support Eric v39.6.4.0 30 | 31 | ## v0.1.0 (2024-08-05) 32 | 33 | - added 34 | - Validate and send xml 35 | - Support Eric v38.1.6.0 36 | -------------------------------------------------------------------------------- /eric-sdk/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eric-sdk" 3 | version = "0.3.1" 4 | authors.workspace = true 5 | edition.workspace = true 6 | readme.workspace = true 7 | license.workspace = true 8 | homepage.workspace = true 9 | repository.workspace = true 10 | description = "Rust SDK for the ELSTER Rich Client (ERiC)" 11 | documentation = "https://docs.rs/eric-sdk" 12 | keywords = ["eric", "sdk", "taxes", "accounting"] 13 | categories = ["finance"] 14 | 15 | [lib] 16 | path = "src/lib.rs" 17 | name = "eric_sdk" 18 | 19 | [package.metadata.docs.rs] 20 | features = ["docs-rs"] 21 | 22 | [features] 23 | default = [] 24 | external-test = [] 25 | # This feature is used in CI pipeline for unit tests. 26 | no-linking = ["eric-bindings/no-linking"] 27 | # This feature is used to publish the documentation for `eric-sdk`. 28 | docs-rs = ["eric-bindings/docs-rs"] 29 | 30 | [dependencies] 31 | eric-bindings = { version = "0.4.1", path = "../eric-bindings" } 32 | anyhow = { workspace = true } 33 | 34 | [dev-dependencies] 35 | roxmltree = "0.20.0" 36 | -------------------------------------------------------------------------------- /eric-sdk/src/certificate.rs: -------------------------------------------------------------------------------- 1 | use crate::error_code::ErrorCode; 2 | use anyhow::anyhow; 3 | use eric_bindings::{EricCloseHandleToCertificate, EricGetHandleToCertificate}; 4 | use std::{ffi::CStr, ptr}; 5 | 6 | pub struct Certificate { 7 | pub handle: u32, 8 | } 9 | 10 | impl Certificate { 11 | pub fn new(path: &CStr) -> Result { 12 | println!("Preparing certificate '{}'", path.to_str()?); 13 | 14 | let mut handle = 0; 15 | let pin_support = ptr::null::() as *mut u32; 16 | 17 | // SAFETY: path.as_ptr() is not dangling as path is allocated in struct CertificateConfig and path is not moved as a reference to the CString is given 18 | let error_code = 19 | unsafe { EricGetHandleToCertificate(&mut handle, pin_support, path.as_ptr()) }; 20 | 21 | match error_code { 22 | x if x == ErrorCode::ERIC_OK as i32 => Ok(Certificate { handle }), 23 | error_code => Err(anyhow!("Can't create certificate: {}", error_code)), 24 | } 25 | } 26 | 27 | // TODO: check validity of certificate 28 | // unsafe { EricHoleZertifikatseigenschaften() } 29 | } 30 | 31 | impl Drop for Certificate { 32 | fn drop(&mut self) { 33 | println!("Cleaning up certificate"); 34 | 35 | let error_code = unsafe { EricCloseHandleToCertificate(self.handle) }; 36 | 37 | match error_code { 38 | x if x == ErrorCode::ERIC_OK as i32 => (), 39 | error_code => panic!("Can't drop certificate handle: {}", error_code), 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /eric-sdk/src/config.rs: -------------------------------------------------------------------------------- 1 | use crate::{certificate::Certificate, utils::ToCString, Preview, ProcessingFlag}; 2 | use eric_bindings::{eric_druck_parameter_t, eric_verschluesselungs_parameter_t, EricPdfCallback}; 3 | use std::{ 4 | ffi::{c_void, CStr, CString}, 5 | path::Path, 6 | ptr, 7 | }; 8 | 9 | pub struct CertificateConfig { 10 | // allocate path as CString 11 | _path: CString, 12 | // allocate password as CString 13 | pub(crate) password: CString, 14 | pub(crate) certificate: Certificate, 15 | pub(crate) certificate_parameter: CertificateParameter, 16 | } 17 | 18 | impl CertificateConfig { 19 | pub fn new(path: &str, password: &str) -> Result { 20 | let path = Path::new(path).try_to_cstring()?; 21 | let password = password.try_to_cstring()?; 22 | let certificate = Certificate::new(&path)?; 23 | let certificate_parameter = CertificateParameter::new(&certificate, &password); 24 | 25 | Ok(Self { 26 | _path: path, 27 | password, 28 | certificate, 29 | certificate_parameter, 30 | }) 31 | } 32 | } 33 | 34 | // CertificateParameter is a wrapper type to keep C memory alignment for eric_verschluesselungs_parameter_t 35 | #[derive(Debug)] 36 | #[repr(C)] 37 | pub(crate) struct CertificateParameter { 38 | inner: eric_verschluesselungs_parameter_t, 39 | } 40 | 41 | impl CertificateParameter { 42 | pub(crate) fn new(certificate: &Certificate, password: &CStr) -> Self { 43 | let certificate_parameter = eric_verschluesselungs_parameter_t { 44 | // SAFETY: password.as_ptr() is not dangling as password is allocated in struct CertificateConfig and password is not moved as a reference to the CString is given 45 | pin: password.as_ptr(), 46 | version: 3, 47 | zertifikatHandle: certificate.handle, 48 | abrufCode: ptr::null(), 49 | }; 50 | 51 | Self { 52 | inner: certificate_parameter, 53 | } 54 | } 55 | 56 | pub fn as_ptr(&self) -> *const eric_verschluesselungs_parameter_t { 57 | &self.inner 58 | } 59 | } 60 | 61 | #[derive(Debug)] 62 | pub struct PrintConfig { 63 | // allocate pdf path as CString 64 | pub(crate) pdf_path: CString, 65 | pub(crate) print_parameter: PrintParameter, 66 | } 67 | 68 | impl PrintConfig { 69 | pub fn new(pdf_path: &str, processing_flag: &ProcessingFlag) -> Result { 70 | let pdf_path = Path::new(pdf_path).try_to_cstring()?; 71 | let print_parameter = PrintParameter::new(&pdf_path, processing_flag); 72 | 73 | Ok(Self { 74 | pdf_path, 75 | print_parameter, 76 | }) 77 | } 78 | } 79 | 80 | // PrintParameter is a wrapper type to keep C memory alignment for eric_druck_parameter_t 81 | #[derive(Debug)] 82 | #[repr(C)] 83 | pub(crate) struct PrintParameter { 84 | inner: eric_druck_parameter_t, 85 | } 86 | 87 | impl PrintParameter { 88 | pub(crate) fn new(pdf_path: &CStr, processing_flag: &ProcessingFlag) -> Self { 89 | let mut user_data: EricPdfCallback = None; 90 | let user_data_ptr: *mut c_void = &mut user_data as *mut _ as *mut c_void; 91 | let print_parameter = eric_druck_parameter_t { 92 | version: 4, 93 | vorschau: match processing_flag { 94 | ProcessingFlag::Validate => Preview::Yes as u32, 95 | ProcessingFlag::Print => Preview::Yes as u32, 96 | _ => Preview::No as u32, 97 | }, 98 | ersteSeite: 0, 99 | duplexDruck: 0, 100 | // SAFETY: pdf_path.as_ptr() is not dangling as pdf_path is 101 | // allocated in struct PrintConfig and pdf_path is not moved as a 102 | // reference to the CString is given. 103 | pdfName: pdf_path.as_ptr(), 104 | fussText: ptr::null(), 105 | pdfCallback: None, 106 | pdfCallbackBenutzerdaten: user_data_ptr, 107 | }; 108 | 109 | Self { 110 | inner: print_parameter, 111 | } 112 | } 113 | 114 | pub fn as_ptr(&self) -> *const eric_druck_parameter_t { 115 | &self.inner 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /eric-sdk/src/eric.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | config::{CertificateConfig, PrintConfig}, 3 | error_code::ErrorCode, 4 | response::{EricResponse, ResponseBuffer}, 5 | utils::ToCString, 6 | ProcessingFlag, 7 | }; 8 | use anyhow::{anyhow, Context}; 9 | use eric_bindings::{EricBearbeiteVorgang, EricBeende, EricDekodiereDaten, EricInitialisiere}; 10 | use std::{ 11 | env::{self}, 12 | path::Path, 13 | ptr, 14 | }; 15 | 16 | /// A structure to manage the Eric instance from the shared C library. 17 | /// 18 | /// Use [`Eric::new`] to initialize Eric. Closes Eric when dropped. 19 | pub struct Eric; 20 | 21 | impl Eric { 22 | /// Initializes a single-threaded Eric instance. 23 | pub fn new(log_path: &Path) -> Result { 24 | println!("Initializing eric"); 25 | 26 | let plugin_path = 27 | env::var("PLUGIN_PATH").context("Missing environment variable 'PLUGIN_PATH'")?; 28 | let plugin_path = Path::new(&plugin_path); 29 | 30 | println!("Setting plugin path '{}'", plugin_path.display()); 31 | println!("Setting log path '{}'", log_path.display()); 32 | println!("Logging to '{}'", log_path.join("eric.log").display()); 33 | 34 | let plugin_path = plugin_path.try_to_cstring()?; 35 | let log_path = log_path.try_to_cstring()?; 36 | 37 | let error_code = unsafe { EricInitialisiere(plugin_path.as_ptr(), log_path.as_ptr()) }; 38 | 39 | match error_code { 40 | x if x == ErrorCode::ERIC_OK as i32 => Ok(Eric), 41 | error_code => Err(anyhow!("Can't init eric: {}", error_code)), 42 | } 43 | } 44 | 45 | /// Validates an XML file for a specific taxonomy. 46 | /// 47 | /// Optionally, a confirmation is printed to `pdf_path`. 48 | pub fn validate( 49 | &self, 50 | xml: String, 51 | taxonomy_type: &str, 52 | taxonomy_version: &str, 53 | pdf_path: Option<&str>, 54 | ) -> Result { 55 | let processing_flag: ProcessingFlag; 56 | let type_version = format!("{}_{}", taxonomy_type, taxonomy_version); 57 | let print_config = if let Some(pdf_path) = pdf_path { 58 | processing_flag = ProcessingFlag::Print; 59 | Some(PrintConfig::new(pdf_path, &processing_flag)?) 60 | } else { 61 | processing_flag = ProcessingFlag::Validate; 62 | None 63 | }; 64 | Self::process(xml, type_version, processing_flag, print_config, None, None) 65 | } 66 | 67 | /// Sends an XML file for a specific taxonomy to the tax authorities. 68 | /// 69 | /// The Elster certificate is provided via environment variables 70 | /// `CERTIFICATE_PATH` and `CERTIFICATE_PASSWORD`. 71 | /// 72 | /// Optionally, a confirmation is printed to `pdf_path`. 73 | pub fn send( 74 | &self, 75 | xml: String, 76 | taxonomy_type: &str, 77 | taxonomy_version: &str, 78 | pdf_path: Option<&str>, 79 | ) -> Result { 80 | let certificate_path = env::var("CERTIFICATE_PATH") 81 | .context("Missing environment variable 'CERTIFICATE_PATH'")?; 82 | let certificate_password = env::var("CERTIFICATE_PASSWORD") 83 | .context("Missing environment variable 'CERTIFICATE_PASSWORD'")?; 84 | 85 | let processing_flag: ProcessingFlag; 86 | let type_version = format!("{}_{}", taxonomy_type, taxonomy_version); 87 | let print_config = if let Some(pdf_path) = pdf_path { 88 | processing_flag = ProcessingFlag::SendAndPrint; 89 | Some(PrintConfig::new(pdf_path, &processing_flag)?) 90 | } else { 91 | processing_flag = ProcessingFlag::Send; 92 | None 93 | }; 94 | let certificate_config = CertificateConfig::new(&certificate_path, &certificate_password)?; 95 | Self::process( 96 | xml, 97 | type_version, 98 | processing_flag, 99 | print_config, 100 | Some(certificate_config), 101 | None, 102 | ) 103 | } 104 | 105 | #[allow(dead_code)] 106 | fn decrypt( 107 | &self, 108 | encrypted_file: &str, 109 | certificate_config: CertificateConfig, 110 | ) -> Result { 111 | let encrypted_data = encrypted_file.try_to_cstring()?; 112 | let response_buffer = ResponseBuffer::new()?; 113 | 114 | let error_code = unsafe { 115 | EricDekodiereDaten( 116 | certificate_config.certificate.handle, 117 | certificate_config.password.as_ptr(), 118 | encrypted_data.as_ptr(), 119 | response_buffer.as_ptr(), 120 | ) 121 | }; 122 | 123 | Ok(error_code) 124 | } 125 | 126 | fn process( 127 | xml: String, 128 | type_version: String, 129 | processing_flag: ProcessingFlag, 130 | print_config: Option, 131 | certificate_config: Option, 132 | transfer_code: Option, 133 | ) -> Result { 134 | println!("Processing xml file"); 135 | 136 | match processing_flag { 137 | ProcessingFlag::Validate => println!("Validating xml file"), 138 | ProcessingFlag::Print => println!("Validating xml file"), 139 | ProcessingFlag::Send => println!("Sending xml file"), 140 | ProcessingFlag::SendAndPrint => println!("Send and print"), 141 | ProcessingFlag::CheckHints => println!("Check hints"), 142 | ProcessingFlag::ValidateWithoutDate => { 143 | println!("Validate without release date (German: Validiere ohne Freigabadatum)") 144 | } 145 | } 146 | 147 | let xml = xml.try_to_cstring()?; 148 | let type_version = type_version.try_to_cstring()?; 149 | 150 | // Transfer_code should be NULL except for data retrieval; if 151 | // transfer_code is not NULL in the other cases, it will be ignored 152 | let transfer_code = match transfer_code { 153 | Some(mut code) => &mut code, 154 | None => ptr::null::() as *mut u32, 155 | }; 156 | 157 | match &print_config { 158 | Some(print_config) => println!( 159 | "Printing confirmation to file '{}'", 160 | print_config.pdf_path.to_str()? 161 | ), 162 | None => (), 163 | } 164 | 165 | let validation_response_buffer = ResponseBuffer::new()?; 166 | let server_response_buffer = ResponseBuffer::new()?; 167 | 168 | let error_code = unsafe { 169 | EricBearbeiteVorgang( 170 | xml.as_ptr(), 171 | type_version.as_ptr(), 172 | processing_flag.into_u32(), 173 | // SAFETY: match a reference of print_config; otherwise 174 | // print_config is moved, and print_parameter.as_ptr() would be 175 | // dangling 176 | match &print_config { 177 | Some(el) => el.print_parameter.as_ptr(), 178 | None => ptr::null(), 179 | }, 180 | // SAFETY: match a reference of certificate_config; otherwise 181 | // certificate_config is moved, and 182 | // certificate_parameter.as_ptr() would be dangling 183 | match &certificate_config { 184 | Some(el) => el.certificate_parameter.as_ptr(), 185 | None => ptr::null(), 186 | }, 187 | transfer_code, 188 | validation_response_buffer.as_ptr(), 189 | server_response_buffer.as_ptr(), 190 | ) 191 | }; 192 | 193 | // TODO: EricHoleFehlerText() for error code 194 | 195 | let transfer_code = unsafe { transfer_code.as_ref() }; 196 | 197 | if let Some(code) = transfer_code { 198 | println!("Transfer code: {}", code) 199 | } 200 | 201 | let validation_response = validation_response_buffer.read()?; 202 | // TODO: parse server response via EricGetErrormessagesFromXMLAnswer() 203 | let server_response = server_response_buffer.read()?; 204 | let response = EricResponse::new( 205 | error_code, 206 | validation_response.to_string(), 207 | server_response.to_string(), 208 | ); 209 | 210 | Ok(response) 211 | } 212 | } 213 | 214 | impl Drop for Eric { 215 | fn drop(&mut self) { 216 | println!("Closing eric"); 217 | 218 | // TODO: implement EricEntladePlugins 219 | 220 | let error_code = unsafe { EricBeende() }; 221 | 222 | match error_code { 223 | x if x == ErrorCode::ERIC_OK as i32 => (), 224 | error_code => panic!("Can't close eric: {}", error_code), 225 | } 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /eric-sdk/src/error_code.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types)] 2 | 3 | /// Represents the available error codes. 4 | pub enum ErrorCode { 5 | /** 6 | * [0] Verarbeitung fehlerfrei. 7 | */ 8 | ERIC_OK = 0, 9 | 10 | /** 11 | * [610001001] Verarbeitung fehlerhaft, keine genaueren Informationen vorhanden. Details stehen ggf. im Logfile (eric.log). 12 | */ 13 | ERIC_GLOBAL_UNKNOWN = 610001001, 14 | 15 | /** 16 | * [610001002] Fehler während der Plausibilitätsprüfung, Datensatz nicht plausibel. Zur Ermittlung der fehlgeschlagenen Plausibiltätsprüfungen muss der Rückgabepuffer (Parameter "rueckgabeXmlPuffer") ausgewertet werden. 17 | */ 18 | ERIC_GLOBAL_PRUEF_FEHLER = 610001002, 19 | 20 | /** 21 | * [610001003] Hinweise während der Plausibilitätsprüfung, Datensatz ist aber plausibel. Zur Ermittlung der anzuzeigenden Hinweise muss der Rückgabepuffer (Parameter "rueckgabeXmlPuffer") ausgewertet werden. 22 | */ 23 | ERIC_GLOBAL_HINWEISE = 610001003, 24 | 25 | /** 26 | * [610001007] Keine Klartextfehlermeldung vorhanden. 27 | */ 28 | ERIC_GLOBAL_FEHLERMELDUNG_NICHT_VORHANDEN = 610001007, 29 | 30 | /* 31 | * [610001008] Für den übergebenen Wert sind keine Daten vorhanden. 32 | */ 33 | ERIC_GLOBAL_KEINE_DATEN_VORHANDEN = 610001008, 34 | 35 | /** 36 | * [610001013] Es ist nicht genügend Arbeitsspeicher vorhanden. 37 | */ 38 | ERIC_GLOBAL_NICHT_GENUEGEND_ARBEITSSPEICHER = 610001013, 39 | 40 | /** 41 | * [610001014] Datei nicht gefunden. 42 | */ 43 | ERIC_GLOBAL_DATEI_NICHT_GEFUNDEN = 610001014, 44 | 45 | /** 46 | * [610001016] Für dieses Verfahren/diese Datenart ist eine Bearbeitung mit der angegebenen HerstellerID nicht erlaubt. 47 | */ 48 | ERIC_GLOBAL_HERSTELLER_ID_NICHT_ERLAUBT = 610001016, 49 | 50 | /** 51 | * [610001017] Ungültiger Zustand. 52 | */ 53 | ERIC_GLOBAL_ILLEGAL_STATE = 610001017, 54 | 55 | /** 56 | * [610001018] Die aufgerufene Funktion ist nicht erlaubt. 57 | */ 58 | ERIC_GLOBAL_FUNKTION_NICHT_ERLAUBT = 610001018, 59 | 60 | /** 61 | * [610001019] Für dieses Verfahren/diese Datenart/diese Test-HerstellerID/diese ERiC-Einstellungen sind Echtfälle nicht erlaubt. 62 | */ 63 | ERIC_GLOBAL_ECHTFALL_NICHT_ERLAUBT = 610001019, 64 | 65 | /** 66 | * [610001020] Der Versand von Echtfällen (= Fällen ohne gesetzten Testmerker) ist mit einer BETA-Version nicht möglich. 67 | */ 68 | ERIC_GLOBAL_NO_VERSAND_IN_BETA_VERSION = 610001020, 69 | 70 | /** 71 | * [610001025] Der übergebene Testmerker ist für das angegebene Verfahren nicht zulässig. 72 | */ 73 | ERIC_GLOBAL_TESTMERKER_UNGUELTIG = 610001025, 74 | 75 | /** 76 | * [610001026] Der zu versendende Datensatz ist zu groß. 77 | */ 78 | ERIC_GLOBAL_DATENSATZ_ZU_GROSS = 610001026, 79 | 80 | /** 81 | * [610001027] Der Verschlüsselungsparameter darf nur bei authentifiziertem Versand angegeben werden. 82 | */ 83 | ERIC_GLOBAL_VERSCHLUESSELUNGS_PARAMETER_NICHT_ERLAUBT = 610001027, 84 | 85 | /** 86 | * [610001028] Bei der angegebenen Versandart sind nur Portal-Zertifikate erlaubt. 87 | */ 88 | ERIC_GLOBAL_NUR_PORTALZERTIFIKAT_ERLAUBT = 610001028, 89 | 90 | /** 91 | * [610001029] Für die übermittelte Datenart ist die Angabe eines Abrufcodes nicht zulässig, daher muss für den Abrufcode der Wert NULL übergeben werden. 92 | */ 93 | ERIC_GLOBAL_ABRUFCODE_NICHT_ERLAUBT = 610001029, 94 | 95 | /** 96 | * [610001030] Es ist ein Fehler bei der Umwandlung nach XML aufgetreten. 97 | */ 98 | ERIC_GLOBAL_ERROR_XML_CREATE = 610001030, 99 | 100 | /** 101 | * [610001031] Die Größe des Textpuffers kann nicht verändert werden. 102 | */ 103 | ERIC_GLOBAL_TEXTPUFFERGROESSE_FIX = 610001031, 104 | 105 | /** 106 | * [610001032] Interner Fehler aufgetreten. Details stehen ggf. im Logfile (eric.log). 107 | */ 108 | ERIC_GLOBAL_INTERNER_FEHLER = 610001032, 109 | 110 | /** 111 | * [610001033] Bei einer arithmetischen Operation ist ein Fehler aufgetreten. Details stehen im Logile (eric.log) 112 | */ 113 | ERIC_GLOBAL_ARITHMETIKFEHLER = 610001033, 114 | 115 | /** 116 | * [610001034] Ungültige Steuernummer. 117 | */ 118 | ERIC_GLOBAL_STEUERNUMMER_UNGUELTIG = 610001034, 119 | 120 | /** 121 | * [610001035] Ungültige Steuernummer: Es werden 13 Stellen erwartet. 122 | */ 123 | ERIC_GLOBAL_STEUERNUMMER_FALSCHE_LAENGE = 610001035, 124 | 125 | /** 126 | * [610001036] Ungültige Steuernummer: Es werden nur Ziffern erwartet. 127 | */ 128 | ERIC_GLOBAL_STEUERNUMMER_NICHT_NUMERISCH = 610001036, 129 | 130 | /** 131 | * [610001037] Ungültige Landesnummer. 132 | */ 133 | ERIC_GLOBAL_LANDESNUMMER_UNBEKANNT = 610001037, 134 | 135 | /** 136 | * [610001038] Ungültige Bundesfinanzamtsnummer. 137 | */ 138 | ERIC_GLOBAL_BUFANR_UNBEKANNT = 610001038, 139 | 140 | /** 141 | * [610001039] Ungültige Bundesfinanzamtsnummer. 142 | */ 143 | ERIC_GLOBAL_LANDESNUMMER_BUFANR = 610001039, 144 | 145 | /** 146 | * [610001040] Ein Puffer-Handle wurde mehrfach übergeben. 147 | */ 148 | ERIC_GLOBAL_PUFFER_ZUGRIFFSKONFLIKT = 610001040, 149 | 150 | /** 151 | * [610001041] Es wurde versucht, einen Puffer über die maximal mögliche Länge hinaus zu beschreiben. 152 | */ 153 | ERIC_GLOBAL_PUFFER_UEBERLAUF = 610001041, 154 | 155 | /** 156 | * [610001042] Die übergebene Datenartversion ist unbekannt. Beachten Sie bitte, dass die Datenartversion case-sensitive ist. 157 | */ 158 | ERIC_GLOBAL_DATENARTVERSION_UNBEKANNT = 610001042, 159 | 160 | /** 161 | * [610001044] Die übergebene Datenartversion passt nicht zum Eingangs-XML. Details stehen ggf. im Logfile (eric.log). 162 | */ 163 | ERIC_GLOBAL_DATENARTVERSION_XML_INKONSISTENT = 610001044, 164 | 165 | /** 166 | * [610001045] Das Plugin 'commonData' konnte nicht geladen werden oder bietet einen benötigten Service nicht an. Details stehen im Logfile (eric.log). 167 | */ 168 | ERIC_GLOBAL_COMMONDATA_NICHT_VERFUEGBAR = 610001045, 169 | 170 | /** 171 | * [610001046] Beim Schreiben in die Protokolldatei ist eine Ausnahme aufgetreten. 172 | */ 173 | ERIC_GLOBAL_LOG_EXCEPTION = 610001046, 174 | 175 | /** 176 | * [610001047] Für diese Datenart darf im TransferHeader kein TransportSchluessel angegeben werden. 177 | */ 178 | ERIC_GLOBAL_TRANSPORTSCHLUESSEL_NICHT_ERLAUBT = 610001047, 179 | 180 | /** 181 | * [610001048] Der übergebene öffentliche Schlüssel kann nicht eingelesen werden. 182 | */ 183 | ERIC_GLOBAL_OEFFENTLICHER_SCHLUESSEL_UNGUELTIG = 610001048, 184 | 185 | /** 186 | * [610001049] Der Typ des im TransferHeader angegebenen Transportschlüssels ist für diese Datenart nicht erlaubt. 187 | */ 188 | ERIC_GLOBAL_TRANSPORTSCHLUESSEL_TYP_FALSCH = 610001049, 189 | 190 | /** 191 | * [610001050] Das übergebene Puffer-Handle wurde nicht mit der vorliegenden Instanz erzeugt. 192 | */ 193 | ERIC_GLOBAL_PUFFER_UNGLEICHER_INSTANZ = 610001050, 194 | 195 | /** 196 | * [610001051] Das Element "Vorsatz" enthält ungültige Werte, Details stehen im Logfile (eric.log). 197 | */ 198 | ERIC_GLOBAL_VORSATZ_UNGUELTIG = 610001051, 199 | 200 | /** 201 | * [610001053] Auf eine Datei konnte nicht in gewünschter Weise zugegriffen werden. Details stehen im Logile (eric.log) 202 | */ 203 | ERIC_GLOBAL_DATEIZUGRIFF_VERWEIGERT = 610001053, 204 | 205 | /** 206 | * [610001080] Die übergebene Instanz ist gleich NULL oder bereits freigegeben worden. 207 | */ 208 | ERIC_GLOBAL_UNGUELTIGE_INSTANZ = 610001080, 209 | 210 | /** 211 | * [610001081] Der Singlethread-ERiC wurde nicht mit EricInitialisiere initialisiert. 212 | */ 213 | ERIC_GLOBAL_NICHT_INITIALISIERT = 610001081, 214 | 215 | /** 216 | * [610001082] Der Singlethread-ERiC wurde bereits mit EricInitialisiere initialisiert. 217 | */ 218 | ERIC_GLOBAL_MEHRFACHE_INITIALISIERUNG = 610001082, 219 | 220 | /** 221 | * [610001083] Der angeforderte ERiC-Instanz konnte nicht erstellt werden. Details stehen ggf. im Logfile (eric.log). 222 | */ 223 | ERIC_GLOBAL_FEHLER_INITIALISIERUNG = 610001083, 224 | 225 | /** 226 | * [610001102] Unbekannter Parameterfehler. 227 | */ 228 | ERIC_GLOBAL_UNKNOWN_PARAMETER_ERROR = 610001102, 229 | 230 | /** 231 | * [610001108] Defekter Nutzdatensatz. 232 | */ 233 | ERIC_GLOBAL_CHECK_CORRUPTED_NDS = 610001108, 234 | 235 | /** 236 | * [610001206] Verschlüsselter/authentifizierter Versand gewünscht, aber keine notwendigen Verschlüsselungsparameter angegeben. 237 | */ 238 | ERIC_GLOBAL_VERSCHLUESSELUNGS_PARAMETER_NICHT_ANGEGEBEN = 610001206, 239 | 240 | /** 241 | * [610001209] Es ist mehr als ein Versandflag angegeben. 242 | */ 243 | ERIC_GLOBAL_SEND_FLAG_MEHR_ALS_EINES = 610001209, 244 | 245 | /** 246 | * [610001218] Die übergebene Kombination von Bearbeitungsflags ist nicht erlaubt. 247 | */ 248 | ERIC_GLOBAL_UNGUELTIGE_FLAG_KOMBINATION = 610001218, 249 | 250 | /** 251 | * [610001220] Der Erste-Seite-Druck ist nur für Steuerberater bei nicht-authentifizierten Einkommenssteuerfällen ab Veranlagungszeitraum 2010 ohne Versandanforderung erlaubt. 252 | */ 253 | ERIC_GLOBAL_ERSTE_SEITE_DRUCK_NICHT_UNTERSTUETZT = 610001220, 254 | 255 | /** 256 | * [610001222] Die angegebenen Parameter sind ungültig oder unvollständig. 257 | */ 258 | ERIC_GLOBAL_UNGUELTIGER_PARAMETER = 610001222, 259 | 260 | /** 261 | * [610001224] Für das angegebene Verfahren wird der Druck nicht unterstützt. 262 | */ 263 | ERIC_GLOBAL_DRUCK_FUER_VERFAHREN_NICHT_ERLAUBT = 610001224, 264 | 265 | /** 266 | * [610001225] Die Versandart ist für die angegebene Datenartversion nicht erlaubt. 267 | */ 268 | ERIC_GLOBAL_VERSAND_ART_NICHT_UNTERSTUETZT = 610001225, 269 | 270 | /** 271 | * [610001226] Die Version eines der angegebenen Parameter ist ungültig. 272 | */ 273 | ERIC_GLOBAL_UNGUELTIGE_PARAMETER_VERSION = 610001226, 274 | 275 | /** 276 | * [610001227] Für das Verfahren Datenabholung wurde ein illegales Transferhandle angegeben. 277 | */ 278 | ERIC_GLOBAL_TRANSFERHANDLE = 610001227, 279 | 280 | /** 281 | * [610001228] Die Initialisierung eines Plugins ist fehlgeschlagen. 282 | */ 283 | ERIC_GLOBAL_PLUGININITIALISIERUNG = 610001228, 284 | 285 | /** 286 | * [610001229] Die Versionen der im Logfile genannten ERiC-Dateien sind nicht kompatibel. (Siehe eric.log.) 287 | */ 288 | ERIC_GLOBAL_INKOMPATIBLE_VERSIONEN = 610001229, 289 | 290 | /** 291 | * [610001230] Das im XML-Element "" angegebene Verschlüsselungsverfahren wird vom ERiC nicht unterstützt. 292 | */ 293 | ERIC_GLOBAL_VERSCHLUESSELUNGSVERFAHREN_NICHT_UNTERSTUETZT = 610001230, 294 | 295 | /** 296 | * [610001231] Der Aufruf eine API-Funktion des ERiCs darf erst dann erfolgen, wenn ein vorheriger Aufruf zurückgekehrt ist. 297 | */ 298 | ERIC_GLOBAL_MEHRFACHAUFRUFE_NICHT_UNTERSTUETZT = 610001231, 299 | 300 | /** 301 | * [610001404] Das Bundesland/Finanzamt mit der angegebenen Nummer nimmt bei der angegebenen Steuerart am ELSTER-Verfahren nicht teil. 302 | */ 303 | ERIC_GLOBAL_UTI_COUNTRY_NOT_SUPPORTED = 610001404, 304 | 305 | /** 306 | * [610001501] Ungültige IBAN: IBAN muss aus zweistelligem Ländercode gefolgt von zweistelliger Prüfziffer gefolgt von der Basic Bank Account Number bestehen. 307 | */ 308 | ERIC_GLOBAL_IBAN_FORMALER_FEHLER = 610001501, 309 | 310 | /** 311 | * [610001502] Ungültige IBAN: Der angegebene Ländercode ist ungültig oder wird aktuell im ELSTER-Verfahren nicht unterstützt. 312 | */ 313 | ERIC_GLOBAL_IBAN_LAENDERCODE_FEHLER = 610001502, 314 | 315 | /** 316 | * [610001503] Ungültige IBAN: Die angegebene IBAN entspricht nicht dem für das angegebene Land definierten formalen Aufbau der IBAN oder die IBAN ist unzulässig. 317 | */ 318 | ERIC_GLOBAL_IBAN_LANDESFORMAT_FEHLER = 610001503, 319 | 320 | /** 321 | * [610001504] Ungültige IBAN: Die Prüfziffernberechnung zur angegebenen IBAN führt zu einer abweichenden Prüfziffer. 322 | */ 323 | ERIC_GLOBAL_IBAN_PRUEFZIFFER_FEHLER = 610001504, 324 | 325 | /** 326 | * [610001510] Ungültiger BIC: Der formale Aufbau des angegeben BIC ist ungültig. 327 | */ 328 | ERIC_GLOBAL_BIC_FORMALER_FEHLER = 610001510, 329 | 330 | /** 331 | * [610001511] Ungültiger BIC: Der angegebene Ländercode ist ungültig oder wird aktuell im ELSTER-Verfahren nicht unterstützt. 332 | */ 333 | ERIC_GLOBAL_BIC_LAENDERCODE_FEHLER = 610001511, 334 | 335 | /** 336 | * [610001519] Die angegebene Zulassungsnummer entspricht nicht den Längenvorgaben. Es sind maximal 6 Stellen erlaubt. 337 | */ 338 | ERIC_GLOBAL_ZULASSUNGSNUMMER_ZU_LANG = 610001519, 339 | 340 | /** 341 | * [610001525] Die übergebene IDNummer ist ungültig. 342 | */ 343 | ERIC_GLOBAL_IDNUMMER_UNGUELTIG = 610001525, 344 | 345 | /** 346 | * [610001526] Es wurde der Parameter NULL übergeben. 347 | */ 348 | ERIC_GLOBAL_NULL_PARAMETER = 610001526, 349 | 350 | /** 351 | * [610001527] Das übergebene Einheitswert-Aktenzeichen ist ungültig. 352 | */ 353 | ERIC_GLOBAL_EWAZ_UNGUELTIG = 610001527, 354 | 355 | /** 356 | * [610001528] Das übergebene Landeskürzel ist unbekannt oder leer. 357 | */ 358 | ERIC_GLOBAL_EWAZ_LANDESKUERZEL_UNBEKANNT = 610001528, 359 | 360 | /** 361 | * [610001851] Update des ERiC erforderlich. Starten Sie nun das Update. 362 | */ 363 | ERIC_GLOBAL_UPDATE_NECESSARY = 610001851, 364 | 365 | /** 366 | * [610001860] Ungültiger Name für Einstellung. 367 | */ 368 | ERIC_GLOBAL_EINSTELLUNG_NAME_UNGUELTIG = 610001860, 369 | 370 | /** 371 | * [610001861] Ungültiger Wert für Einstellung. 372 | */ 373 | ERIC_GLOBAL_EINSTELLUNG_WERT_UNGUELTIG = 610001861, 374 | 375 | /** 376 | * [610001862] Fehler beim Dekodieren. 377 | */ 378 | ERIC_GLOBAL_ERR_DEKODIEREN = 610001862, 379 | 380 | /** 381 | * [610001863] Die aufgerufene Funktion wird nicht unterstützt. 382 | */ 383 | ERIC_GLOBAL_FUNKTION_NICHT_UNTERSTUETZT = 610001863, 384 | 385 | /** 386 | * [610001865] Fehler im übergebenen EDS-XML: In den Sammeldaten wurde ein Nutzdatenticket für mehrere Steuerfälle verwendet. Für jeden Steuerfall muss jedoch ein eigenes Nutzdatenticket angegeben werden. 387 | */ 388 | ERIC_GLOBAL_NUTZDATENTICKETS_NICHT_EINDEUTIG = 610001865, 389 | 390 | /** 391 | * [610001866] Fehler im übergebenen EDS-XML: Bei den Sammeldaten wurden unterschiedliche Versionen des Nutzdaten-Headers verwendet. Innerhalb einer Datenlieferung ist jedoch nur eine Nutzdaten-Header-Version zulässig. 392 | */ 393 | ERIC_GLOBAL_NUTZDATENHEADERVERSIONEN_UNEINHEITLICH = 610001866, 394 | 395 | /** 396 | * [610001867] Fehler im übergebenen EDS-XML: Es wurden Fälle für mehrere Bundesländer angegeben. Innerhalb einer Datenlieferung dürfen jedoch nur Fälle für ein Bundesland angegeben werden. 397 | */ 398 | ERIC_GLOBAL_BUNDESLAENDER_UNEINHEITLICH = 610001867, 399 | 400 | /** 401 | * [610001868] Fehler im übergebenen EDS-XML: Es wurden Fälle für unterschiedliche Jahre angegeben. Innerhalb einer Datenlieferung dürfen jedoch nur Fälle für ein und dasselbe Jahr angegeben werden. 402 | */ 403 | ERIC_GLOBAL_ZEITRAEUME_UNEINHEITLICH = 610001868, 404 | 405 | /** 406 | * [610001869] Fehler im übergebenen EDS-XML: Der Inhalt des Nutzdaten-Elements "" ist für diese Datenart nicht korrekt. 407 | */ 408 | ERIC_GLOBAL_NUTZDATENHEADER_EMPFAENGER_NICHT_KORREKT = 610001869, 409 | 410 | /** 411 | * [610101200] Allgemeiner Kommunikationsfehler. 412 | */ 413 | ERIC_TRANSFER_COM_ERROR = 610101200, 414 | 415 | /** 416 | * [610101201] Dieser Vorgang wird von der aufgerufenen Funktion nicht unterstützt. 417 | */ 418 | ERIC_TRANSFER_VORGANG_NICHT_UNTERSTUETZT = 610101201, 419 | 420 | /** 421 | * [610101210] Fehler im Transferheader. Der ELSTER-Annahmeserver hat einen Fehler zurückgemeldet. Bitte werten Sie die Serverantwort aus. 422 | */ 423 | ERIC_TRANSFER_ERR_XML_THEADER = 610101210, 424 | 425 | /** 426 | * [610101251] Es wurden ungültige Parameter übergeben. 427 | */ 428 | ERIC_TRANSFER_ERR_PARAM = 610101251, 429 | 430 | /** 431 | * [610101253] Im XML-String konnte der Text "" nicht gefunden werden. 432 | */ 433 | ERIC_TRANSFER_ERR_DATENTEILENDNOTFOUND = 610101253, 434 | 435 | /** 436 | * [610101255] Im XML-String konnte der Text "" nicht gefunden werden. 437 | */ 438 | ERIC_TRANSFER_ERR_BEGINDATENLIEFERANT = 610101255, 439 | 440 | /** 441 | * [610101256] Im XML-String konnte der Text "" nicht gefunden werden. 442 | */ 443 | ERIC_TRANSFER_ERR_ENDDATENLIEFERANT = 610101256, 444 | 445 | /** 446 | * [610101257] Im XML-String konnte der Text "" nicht gefunden werden. 447 | */ 448 | ERIC_TRANSFER_ERR_BEGINTRANSPORTSCHLUESSEL = 610101257, 449 | 450 | /** 451 | * [610101258] Im XML-String konnte der Text "" nicht gefunden werden. 452 | */ 453 | ERIC_TRANSFER_ERR_ENDTRANSPORTSCHLUESSEL = 610101258, 454 | 455 | /** 456 | * [610101259] Im XML-String konnte der Text "" nicht gefunden werden. 457 | */ 458 | ERIC_TRANSFER_ERR_BEGINDATENGROESSE = 610101259, 459 | 460 | /** 461 | * [610101260] Im XML-String konnte der Text "" nicht gefunden werden. 462 | */ 463 | ERIC_TRANSFER_ERR_ENDDATENGROESSE = 610101260, 464 | 465 | /** 466 | * [610101271] Beim Datenaustausch ist ein Fehler aufgetreten. 467 | */ 468 | ERIC_TRANSFER_ERR_SEND = 610101271, 469 | 470 | /** 471 | * [610101274] Die Antwortdaten waren nicht PKCS#7-verschlüsselt. 472 | */ 473 | ERIC_TRANSFER_ERR_NOTENCRYPTED = 610101274, 474 | 475 | /** 476 | * [610101276] Verbindung zum ProxyServer konnte nicht aufgebaut werden. 477 | */ 478 | ERIC_TRANSFER_ERR_PROXYCONNECT = 610101276, 479 | 480 | /** 481 | * [610101278] Zu den Servern konnte keine Verbindung aufgebaut werden. 482 | */ 483 | ERIC_TRANSFER_ERR_CONNECTSERVER = 610101278, 484 | 485 | /** 486 | * [610101279] Von der Clearingstelle konnte keine Antwort empfangen werden. 487 | */ 488 | ERIC_TRANSFER_ERR_NORESPONSE = 610101279, 489 | 490 | /** 491 | * [610101280] Der Proxyserver erwartet Anmeldedaten. 492 | */ 493 | ERIC_TRANSFER_ERR_PROXYAUTH = 610101280, 494 | 495 | /** 496 | * [610101282] Fehler bei der Initialisierung des Versands, Details stehen ggf. im Logfile (eric.log). 497 | */ 498 | ERIC_TRANSFER_ERR_SEND_INIT = 610101282, 499 | 500 | /** 501 | * [610101283] Bei der Kommunikation mit dem Server kam es zu einer Zeitüberschreitung. 502 | */ 503 | ERIC_TRANSFER_ERR_TIMEOUT = 610101283, 504 | 505 | /** 506 | * [610101284] Es wurde kein gültiger Port für den Proxy angegeben. 507 | */ 508 | ERIC_TRANSFER_ERR_PROXYPORT_INVALID = 610101284, 509 | 510 | /** 511 | * [610101291] Sonstiger, nicht definierter Fehler aufgetreten. 512 | */ 513 | ERIC_TRANSFER_ERR_OTHER = 610101291, 514 | 515 | /** 516 | * [610101292] Fehler im NutzdatenHeader. Der ELSTER-Annahmeserver hat einen Fehler zurückgemeldet. Bitte werten Sie die Serverantwort aus. Bei Sammeldaten sind alle Nutzdatenblöcke zu prüfen, um den fehlerhaften Datensatz identifizieren zu können. 517 | */ 518 | ERIC_TRANSFER_ERR_XML_NHEADER = 610101292, 519 | 520 | /** 521 | * [610101293] Das XML liegt im falschen Encoding vor. 522 | */ 523 | ERIC_TRANSFER_ERR_XML_ENCODING = 610101293, 524 | 525 | /** 526 | * [610101294] Im XML-String konnte der Text "" nicht gefunden werden. 527 | */ 528 | ERIC_TRANSFER_ERR_ENDSIGUSER = 610101294, 529 | 530 | /** 531 | * [610101295] Im XML-String konnte ein Tag nicht gefunden werden. 532 | */ 533 | ERIC_TRANSFER_ERR_XMLTAG_NICHT_GEFUNDEN = 610101295, 534 | 535 | /** 536 | * [610101297] Das XML-Element "" konnte nicht gelesen werden. 537 | */ 538 | ERIC_TRANSFER_ERR_DATENTEILFEHLER = 610101297, 539 | 540 | /** 541 | * [610101500] Es konnte kein Ad Hoc-Zertifikat fuer den Personalausweis oder den Aufenthaltstitel erzeugt bzw. gefunden werden, Details stehen ggf. im Logfile (eric.log). 542 | */ 543 | ERIC_TRANSFER_EID_ZERTIFIKATFEHLER = 610101500, 544 | 545 | /** 546 | * [610101510] Für die Identifikationsnummer des Benutzers existiert kein Konto bei ELSTER. 547 | */ 548 | ERIC_TRANSFER_EID_KEINKONTO = 610101510, 549 | 550 | /** 551 | * [610101511] Dem Benutzer konnte keine eindeutige Identifikationsnummer zugeordnet werden. 552 | */ 553 | ERIC_TRANSFER_EID_IDNRNICHTEINDEUTIG = 610101511, 554 | 555 | /** 556 | * [610101512] Das nPA-Servlet konnte keine Verbindung zum eID-Server aufbauen. 557 | */ 558 | ERIC_TRANSFER_EID_SERVERFEHLER = 610101512, 559 | 560 | /** 561 | * [610101520] Der eID-Client ist nicht erreichbar. Wahrscheinlich wurde er nicht gestartet oder die übergebene lokale URL ist nicht korrekt 562 | */ 563 | ERIC_TRANSFER_EID_KEINCLIENT = 610101520, 564 | 565 | /** 566 | * [610101521] Der eID-Client hat einen Fehler gemeldet. Details zu dem Fehler finden Sie im Log des eID-Clients oder ggf. im ERiC Logfile (eric.log). 567 | */ 568 | ERIC_TRANSFER_EID_CLIENTFEHLER = 610101521, 569 | 570 | /** 571 | * [610101522] Es konnten nicht alle benötigten Datenfelder des Personalausweises ausgelesen werden. Bitte prüfen Sie über die Funktion "Selbstauskunft" des eID-Clients, ob folgende Daten von Ihrem Personalausweis korrekt bereitgestellt werden: Familienname, Vorname(n), Geburtsdatum, Anschrift (mit Postleitzahl) und Dokumentenart. 572 | */ 573 | ERIC_TRANSFER_EID_FEHLENDEFELDER = 610101522, 574 | 575 | /** 576 | * [610101523] Das Auslesen der Daten aus dem Personalausweis wurde vom Anwender abgebrochen. 577 | */ 578 | ERIC_TRANSFER_EID_IDENTIFIKATIONABGEBROCHEN = 610101523, 579 | 580 | /** 581 | * [610101524] Der Personalausweis wird von einem anderen Vorgang blockiert. Beenden Sie den anderen Vorgang und versuchen Sie es dann erneut. 582 | */ 583 | ERIC_TRANSFER_EID_NPABLOCKIERT = 610101524, 584 | 585 | /** 586 | * [610201016] Fehler bei der Schlüsselerzeugung. 587 | */ 588 | ERIC_CRYPT_ERROR_CREATE_KEY = 610201016, 589 | 590 | /** 591 | * [610201101] eSigner: Ungültiges Token Handle. 592 | */ 593 | ERIC_CRYPT_E_INVALID_HANDLE = 610201101, 594 | 595 | /** 596 | * [610201102] eSigner: Zu viele Sessions geöffnet. 597 | */ 598 | ERIC_CRYPT_E_MAX_SESSION = 610201102, 599 | 600 | /** 601 | * [610201103] eSigner: Überlastung. 602 | */ 603 | ERIC_CRYPT_E_BUSY = 610201103, 604 | 605 | /** 606 | * [610201104] eSigner: Speicherzuordnungsfehler. 607 | */ 608 | ERIC_CRYPT_E_OUT_OF_MEM = 610201104, 609 | 610 | /** 611 | * [610201105] eSigner: Ungültiger PSE Pfad. 612 | */ 613 | ERIC_CRYPT_E_PSE_PATH = 610201105, 614 | 615 | /** 616 | * [610201106] eSigner: Es wurde ein falsches Passwort bzw. eine falsche PIN angegeben. 617 | */ 618 | ERIC_CRYPT_E_PIN_WRONG = 610201106, 619 | 620 | /** 621 | * [610201107] eSigner: Das Passwort bzw. die PIN ist gesperrt. 622 | */ 623 | ERIC_CRYPT_E_PIN_LOCKED = 610201107, 624 | 625 | /** 626 | * [610201108] eSigner: Fehler beim Lesen des PKCS#7-Objekts. 627 | */ 628 | ERIC_CRYPT_E_P7_READ = 610201108, 629 | 630 | /** 631 | * [610201109] eSigner: Fehler beim PKCS#7 Dekodieren. 632 | */ 633 | ERIC_CRYPT_E_P7_DECODE = 610201109, 634 | 635 | /** 636 | * [610201110] eSigner: Entschlüsselungszertifikat nicht in Empfängerliste enthalten. 637 | */ 638 | ERIC_CRYPT_E_P7_RECIPIENT = 610201110, 639 | 640 | /** 641 | * [610201111] eSigner: Fehler beim Lesen des PKCS#12-Objekts. 642 | */ 643 | ERIC_CRYPT_E_P12_READ = 610201111, 644 | 645 | /** 646 | * [610201112] eSigner: Fehler beim Dekodieren des PKCS#12-Objekts. 647 | */ 648 | ERIC_CRYPT_E_P12_DECODE = 610201112, 649 | 650 | /** 651 | * [610201113] eSigner: Fehler beim Zugriff auf Soft-PSE-Signaturschlüssel. 652 | */ 653 | ERIC_CRYPT_E_P12_SIG_KEY = 610201113, 654 | 655 | /** 656 | * [610201114] eSigner: Fehler beim Zugriff auf Soft-PSE Entschlüsselungsschlüssel. 657 | */ 658 | ERIC_CRYPT_E_P12_ENC_KEY = 610201114, 659 | 660 | /** 661 | * [610201115] eSigner: Fehler beim Zugriff auf Hard-Token Signaturschlüssel. 662 | */ 663 | ERIC_CRYPT_E_P11_SIG_KEY = 610201115, 664 | 665 | /** 666 | * [610201116] eSigner: Fehler beim Zugriff auf Hard-Token Entschlüsselungsschlüssel. 667 | */ 668 | ERIC_CRYPT_E_P11_ENC_KEY = 610201116, 669 | 670 | /** 671 | * [610201117] eSigner: Fehler beim Parsen der XML-Eingabedatei. 672 | */ 673 | ERIC_CRYPT_E_XML_PARSE = 610201117, 674 | 675 | /** 676 | * [610201118] eSigner: Fehler beim Erzeugen des XML-Signaturasts. 677 | */ 678 | ERIC_CRYPT_E_XML_SIG_ADD = 610201118, 679 | 680 | /** 681 | * [610201119] eSigner: XML-Signaturtag nicht vorhanden. 682 | */ 683 | ERIC_CRYPT_E_XML_SIG_TAG = 610201119, 684 | 685 | /** 686 | * [610201120] eSigner: Fehler bei XML-Signaturerzeugung. 687 | */ 688 | ERIC_CRYPT_E_XML_SIG_SIGN = 610201120, 689 | 690 | /** 691 | * [610201121] eSigner: Parameter-Fehler, unbekanntes Encoding. 692 | */ 693 | ERIC_CRYPT_E_ENCODE_UNKNOWN = 610201121, 694 | 695 | /** 696 | * [610201122] eSigner: Encoding-Fehler. 697 | */ 698 | ERIC_CRYPT_E_ENCODE_ERROR = 610201122, 699 | 700 | /** 701 | * [610201123] eSigner: XML Initialisierungsfehler. 702 | */ 703 | ERIC_CRYPT_E_XML_INIT = 610201123, 704 | 705 | /** 706 | * [610201124] eSigner: Fehler beim Verschlüsseln. 707 | */ 708 | ERIC_CRYPT_E_ENCRYPT = 610201124, 709 | 710 | /** 711 | * [610201125] eSigner: Fehler beim Entschlüsseln. 712 | */ 713 | ERIC_CRYPT_E_DECRYPT = 610201125, 714 | 715 | /** 716 | * [610201126] eSigner: Keine Signaturkarte eingesteckt (PKCS#11). 717 | */ 718 | ERIC_CRYPT_E_P11_SLOT_EMPTY = 610201126, 719 | 720 | /** 721 | * [610201127] eSigner: Keine Signatur-/Verschlüsselungs-Zertifikate/-Schlüssel gefunden (PKCS#11). 722 | */ 723 | ERIC_CRYPT_E_NO_SIG_ENC_KEY = 610201127, 724 | 725 | /** 726 | * [610201128] eSigner: PKCS11 bzw. PC/SC Library fehlt oder ist nicht ausführbar. 727 | */ 728 | ERIC_CRYPT_E_LOAD_DLL = 610201128, 729 | 730 | /** 731 | * [610201129] eSigner: Der PC/SC Dienst ist nicht gestartet. 732 | */ 733 | ERIC_CRYPT_E_NO_SERVICE = 610201129, 734 | 735 | /** 736 | * [610201130] eSigner: Unbekannte Ausnahme aufgetreten. 737 | */ 738 | ERIC_CRYPT_E_ESICL_EXCEPTION = 610201130, 739 | 740 | /** 741 | * [610201144] eSigner: CA Tokentyp und interner Tokentyp stimmen nicht überein. 742 | */ 743 | ERIC_CRYPT_E_TOKEN_TYPE_MISMATCH = 610201144, 744 | 745 | /** 746 | * [610201146] eSigner: Temporäres PKCS#12-Token kann nicht erzeugt werden. 747 | */ 748 | ERIC_CRYPT_E_P12_CREATE = 610201146, 749 | 750 | /** 751 | * [610201147] eSigner: Zertifikatskette konnte nicht verifiziert werden. 752 | */ 753 | ERIC_CRYPT_E_VERIFY_CERT_CHAIN = 610201147, 754 | 755 | /** 756 | * [610201148] eSigner: PKCS#11 Engine mit anderer Bibliothek belegt. 757 | */ 758 | ERIC_CRYPT_E_P11_ENGINE_LOADED = 610201148, 759 | 760 | /** 761 | * [610201149] eSigner: Aktion vom Benutzer abgebrochen. 762 | */ 763 | ERIC_CRYPT_E_USER_CANCEL = 610201149, 764 | 765 | /** 766 | * [610201200] Fehler beim Zugriff auf Zertifikat. 767 | */ 768 | ERIC_CRYPT_ZERTIFIKAT = 610201200, 769 | 770 | /** 771 | * [610201201] Fehler bei Signaturerzeugung. 772 | */ 773 | ERIC_CRYPT_SIGNATUR = 610201201, 774 | 775 | /** 776 | * [610201203] Das Format der PSE wird nicht unterstützt. 777 | */ 778 | ERIC_CRYPT_NICHT_UNTERSTUETZTES_PSE_FORMAT = 610201203, 779 | 780 | /** 781 | * [610201205] Für die ausgewählte Operation muss ein Passwort bzw. eine PIN angegeben werden. 782 | */ 783 | ERIC_CRYPT_PIN_BENOETIGT = 610201205, 784 | 785 | /** 786 | * [610201206] Das gewünschte Passwort ist nicht sicher genug (z.B. zu kurz). 787 | */ 788 | ERIC_CRYPT_PIN_STAERKE_NICHT_AUSREICHEND = 610201206, 789 | 790 | /** 791 | * [610201208] Interner Fehler aufgetreten. Details stehen ggf. im Logfile (eric.log). 792 | */ 793 | ERIC_CRYPT_E_INTERN = 610201208, 794 | 795 | /** 796 | * [610201209] Der angegebene Zertifikatspfad ist kein Verzeichnis. 797 | */ 798 | ERIC_CRYPT_ZERTIFIKATSPFAD_KEIN_VERZEICHNIS = 610201209, 799 | 800 | /** 801 | * [610201210] Im angegebenen Verzeichnis existiert bereits ein Bestandteil eines ERiC-Zertifikats. 802 | */ 803 | ERIC_CRYPT_ZERTIFIKATSDATEI_EXISTIERT_BEREITS = 610201210, 804 | 805 | /** 806 | * [610201211] Das gewünschte Passwort enthält ungültige Zeichen (z.B. Umlaute). 807 | */ 808 | ERIC_CRYPT_PIN_ENTHAELT_UNGUELTIGE_ZEICHEN = 610201211, 809 | 810 | /** 811 | * [610201212] eSigner: Der Abrufcode besitzt eine falsche Struktur oder enthält ungültige Zeichen. 812 | */ 813 | ERIC_CRYPT_E_INVALID_PARAM_ABC = 610201212, 814 | 815 | /** 816 | * [610201213] Das übergebene Zertifikat weist Inkonsistenzen auf und kann deswegen nicht verwendet werden. Bitte verwenden Sie ein anderes oder erzeugen und verwenden Sie ein neues Zertifikat. 817 | */ 818 | ERIC_CRYPT_CORRUPTED = 610201213, 819 | 820 | /** 821 | * [610201214] Die aufgerufene Funktion unterstützt den neuen Personalausweis (nPA) und den elektronischen Aufenthaltstitel (eAT) nicht. 822 | */ 823 | ERIC_CRYPT_EIDKARTE_NICHT_UNTERSTUETZT = 610201214, 824 | 825 | /** 826 | * [610201215] Es ist keine Karte/kein Stick eingesteckt 827 | */ 828 | ERIC_CRYPT_E_SC_SLOT_EMPTY = 610201215, 829 | 830 | /** 831 | * [610201216] Kein unterstütztes Applet gefunden 832 | */ 833 | ERIC_CRYPT_E_SC_NO_APPLET = 610201216, 834 | 835 | /** 836 | * [610201217] Fehler in der Kartensession 837 | */ 838 | ERIC_CRYPT_E_SC_SESSION = 610201217, 839 | 840 | /** 841 | * [610201218] P11 Signaturzertifikat fehlt 842 | */ 843 | ERIC_CRYPT_E_P11_NO_SIG_CERT = 610201218, 844 | 845 | /** 846 | * [610201219] P11 Der initiale Tokenzugriff ist fehlgeschlagen 847 | */ 848 | ERIC_CRYPT_E_P11_INIT_FAILED = 610201219, 849 | 850 | /** 851 | * [610201220] P11 Verschlüsselungszertifikat fehlt 852 | */ 853 | ERIC_CRYPT_E_P11_NO_ENC_CERT = 610201220, 854 | 855 | /** 856 | * [610201221] P12 Signaturzertifikat fehlt 857 | */ 858 | ERIC_CRYPT_E_P12_NO_SIG_CERT = 610201221, 859 | 860 | /** 861 | * [610201222] P12 Verschlüsselungszertifikat fehlt 862 | */ 863 | ERIC_CRYPT_E_P12_NO_ENC_CERT = 610201222, 864 | 865 | /** 866 | * [610201223] PC/SC Der Zugriff auf den Entschlüsselungsschlüssel ist fehlgeschlagen 867 | */ 868 | ERIC_CRYPT_E_SC_ENC_KEY = 610201223, 869 | 870 | /** 871 | * [610201224] PC/SC Signaturzertifikat fehlt 872 | */ 873 | ERIC_CRYPT_E_SC_NO_SIG_CERT = 610201224, 874 | 875 | /** 876 | * [610201225] PC/SC Verschlüsselungszertifikat fehlt 877 | */ 878 | ERIC_CRYPT_E_SC_NO_ENC_CERT = 610201225, 879 | 880 | /** 881 | * [610201226] PC/SC Der initiale Tokenzugriff ist fehlgeschlagen 882 | */ 883 | ERIC_CRYPT_E_SC_INIT_FAILED = 610201226, 884 | 885 | /** 886 | * [610201227] PC/SC Der Zugriff auf den Signaturschlüssel ist fehlgeschlagen 887 | */ 888 | ERIC_CRYPT_E_SC_SIG_KEY = 610201227, 889 | 890 | /** 891 | * [610301001] Verarbeitung fehlerhaft, keine genaueren Informationen vorhanden. 892 | */ 893 | ERIC_IO_FEHLER = 610301001, 894 | 895 | /** 896 | * [610301005] Der Dateiaufbau ist nicht korrekt. 897 | */ 898 | ERIC_IO_DATEI_INKORREKT = 610301005, 899 | 900 | /** 901 | * [610301006] Fehler beim Parsen der Eingabedaten. Details stehen im Logfile (eric.log). 902 | */ 903 | ERIC_IO_PARSE_FEHLER = 610301006, 904 | 905 | /** 906 | * [610301007] Die Generierung des Nutzdatensatzes ist fehlgeschlagen. 907 | */ 908 | ERIC_IO_NDS_GENERIERUNG_FEHLGESCHLAGEN = 610301007, 909 | 910 | /** 911 | * [610301010] Interner Fehler, der Masterdatenservice ist nicht verfügbar. 912 | */ 913 | ERIC_IO_MASTERDATENSERVICE_NICHT_VERFUEGBAR = 610301010, 914 | 915 | /** 916 | * [610301014] Es wurden ungültige Steuerzeichen im Nutzdatensatz gefunden. 917 | */ 918 | ERIC_IO_STEUERZEICHEN_IM_NDS = 610301014, 919 | 920 | /** 921 | * [610301031] Die Versionsinformationen der ERiC-Bibliotheken konnten nicht ausgelesen werden. 922 | */ 923 | ERIC_IO_VERSIONSINFORMATIONEN_NICHT_GEFUNDEN = 610301031, 924 | 925 | /** 926 | * [610301104] Der Wert im Transferheader-Element "Verfahren" wird vom verwendeten Reader nicht unterstützt. 927 | */ 928 | ERIC_IO_FALSCHES_VERFAHREN = 610301104, 929 | 930 | /** 931 | * [610301105] Es wurde mehr als ein Steuerfall in der Eingabedatei gefunden. 932 | */ 933 | ERIC_IO_READER_MEHRFACHE_STEUERFAELLE = 610301105, 934 | 935 | /** 936 | * [610301106] Es wurden unerwartete Elemente in der Eingabedatei gefunden, Details stehen ggf. im Logfile (eric.log). 937 | */ 938 | ERIC_IO_READER_UNERWARTETE_ELEMENTE = 610301106, 939 | 940 | /** 941 | * [610301107] Es wurden formale Fehler in der Eingabedatei gefunden, Details stehen ggf. im Logfile (eric.log). 942 | */ 943 | ERIC_IO_READER_FORMALE_FEHLER = 610301107, 944 | 945 | /** 946 | * [610301108] Die Eingabedaten lagen nicht im Encoding UTF-8 vor, oder es war kein Encoding spezifiziert. 947 | */ 948 | ERIC_IO_READER_FALSCHES_ENCODING = 610301108, 949 | 950 | /** 951 | * [610301109] Es wurde mehr als ein "Nutzdaten"-Element in der Eingabedatei gefunden. 952 | */ 953 | ERIC_IO_READER_MEHRFACHE_NUTZDATEN_ELEMENTE = 610301109, 954 | 955 | /** 956 | * [610301110] Es wurde mehr als ein Nutzdatenblock in der Eingabedatei gefunden. 957 | */ 958 | ERIC_IO_READER_MEHRFACHE_NUTZDATENBLOCK_ELEMENTE = 610301110, 959 | 960 | /** 961 | * [610301111] Der im Transferheader-Element "Datenart" angegebene Wert ist unbekannt. 962 | */ 963 | ERIC_IO_UNBEKANNTE_DATENART = 610301111, 964 | 965 | /** 966 | * [610301114] Ungültiger oder fehlender Wert für den Untersachbereich. 967 | */ 968 | ERIC_IO_READER_UNTERSACHBEREICH_UNGUELTIG = 610301114, 969 | 970 | /** 971 | * [610301115] Es wurden zu viele Nutzdatenblöcke in der Eingabedatei gefunden. 972 | */ 973 | ERIC_IO_READER_ZU_VIELE_NUTZDATENBLOCK_ELEMENTE = 610301115, 974 | 975 | /** 976 | * [610301150] Es wurden ungültige Steuerzeichen im TransferHeader-Element gefunden. 977 | */ 978 | ERIC_IO_READER_STEUERZEICHEN_IM_TRANSFERHEADER = 610301150, 979 | 980 | /** 981 | * [610301151] Es wurden ungültige Steuerzeichen im NutzdatenHeader-Element gefunden. 982 | */ 983 | ERIC_IO_READER_STEUERZEICHEN_IM_NUTZDATENHEADER = 610301151, 984 | 985 | /** 986 | * [610301152] Es wurden ungültige Steuerzeichen im Nutzdaten-Element gefunden. 987 | */ 988 | ERIC_IO_READER_STEUERZEICHEN_IN_DEN_NUTZDATEN = 610301152, 989 | 990 | /** 991 | * [610301190] Ein Nutzdatenblock enthält zu viele Anhänge. Details stehen im Logfile (eric.log). 992 | */ 993 | ERIC_IO_READER_ZU_VIELE_ANHAENGE = 610301190, 994 | 995 | /** 996 | * [610301191] Ein Anhang ist zu groß. Details stehen im Logfile (eric.log). 997 | */ 998 | ERIC_IO_READER_ANHANG_ZU_GROSS = 610301191, 999 | 1000 | /** 1001 | * [610301192] Die Gesamtgröße aller Anhange in einem Nutzdatenblock ist zu groß. Details stehen im Logfile (eric.log). 1002 | */ 1003 | ERIC_IO_READER_ANHAENGE_ZU_GROSS = 610301192, 1004 | 1005 | /** 1006 | * [610301200] Es traten Fehler beim Validieren des XML auf. Details stehen im Logfile (eric.log). 1007 | */ 1008 | ERIC_IO_READER_SCHEMA_VALIDIERUNGSFEHLER = 610301200, 1009 | 1010 | /** 1011 | * [610301201] Eine XML-Entity konnte nicht aufgelöst werden. 1012 | */ 1013 | ERIC_IO_READER_UNBEKANNTE_XML_ENTITY = 610301201, 1014 | 1015 | /** 1016 | * [610301252] Im XML-String konnte der Text "" nicht gefunden werden. 1017 | */ 1018 | ERIC_IO_DATENTEILNOTFOUND = 610301252, 1019 | 1020 | /** 1021 | * [610301253] Im XML-String konnte der Text "" nicht gefunden werden. 1022 | */ 1023 | ERIC_IO_DATENTEILENDNOTFOUND = 610301253, 1024 | 1025 | /** 1026 | * [610301300] Falsche Übergabeparameter für die Funktion. 1027 | */ 1028 | ERIC_IO_UEBERGABEPARAMETER_FEHLERHAFT = 610301300, 1029 | 1030 | /** 1031 | * [610301400] Der Parameter enthält ungültige UTF-8 Multibytesequenzen. 1032 | */ 1033 | ERIC_IO_UNGUELTIGE_UTF8_SEQUENZ = 610301400, 1034 | 1035 | /** 1036 | * [610301401] Der Parameter enthält mindestens ein unzulässiges Zeichen. 1037 | */ 1038 | ERIC_IO_UNGUELTIGE_ZEICHEN_IN_PARAMETER = 610301401, 1039 | 1040 | /** 1041 | * [610501001] Verarbeitung fehlerhaft, keine genaueren Informationen vorhanden. 1042 | */ 1043 | ERIC_PRINT_INTERNER_FEHLER = 610501001, 1044 | 1045 | /** 1046 | * [610501002] Keine Druckvorlage für die angegebene Kombination aus Unterfallart und Veranlagungszeitraum gefunden. Bitte prüfen Sie die installierten Druckvorlagen. 1047 | */ 1048 | ERIC_PRINT_DRUCKVORLAGE_NICHT_GEFUNDEN = 610501002, 1049 | 1050 | /** 1051 | * [610501004] Es wurde ein falscher Dateipfad angegeben, es fehlen Zugriffsrechte oder die Datei wird aktuell von einer anderen Anwendung verwendet. 1052 | */ 1053 | ERIC_PRINT_UNGUELTIGER_DATEI_PFAD = 610501004, 1054 | 1055 | /** 1056 | * [610501007] ERiCPrint wurde nicht richtig initialisiert. Eventuell wurde ERiC nicht richtig initialisiert? 1057 | */ 1058 | ERIC_PRINT_INITIALISIERUNG_FEHLERHAFT = 610501007, 1059 | 1060 | /** 1061 | * [610501008] Das zu verwendende Format bzw. der Zielklient sind nicht bekannt. 1062 | */ 1063 | ERIC_PRINT_AUSGABEZIEL_UNBEKANNT = 610501008, 1064 | 1065 | /** 1066 | * [610501009] Der Beginn des Ausdruckprozesses schlug fehl. Eventuell konnten notwendige Ressourcen nicht allokiert werden. 1067 | */ 1068 | ERIC_PRINT_ABBRUCH_DRUCKVORBEREITUNG = 610501009, 1069 | 1070 | /** 1071 | * [610501010] Während der Ausgabe der Inhalte ist ein Fehler aufgetreten. 1072 | */ 1073 | ERIC_PRINT_ABBRUCH_GENERIERUNG = 610501010, 1074 | 1075 | /** 1076 | * [610501011] Die Kombination aus Unterfallart und Veranlagungszeitraum wird nicht unterstützt. 1077 | */ 1078 | ERIC_PRINT_STEUERFALL_NICHT_UNTERSTUETZT = 610501011, 1079 | 1080 | /** 1081 | * [610501012] Der übergebene Fußtext ist zu lang. 1082 | */ 1083 | ERIC_PRINT_FUSSTEXT_ZU_LANG = 610501012, 1084 | } 1085 | -------------------------------------------------------------------------------- /eric-sdk/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod certificate; 2 | mod config; 3 | mod eric; 4 | mod error_code; 5 | mod response; 6 | mod utils; 7 | 8 | pub use eric::Eric; 9 | pub use error_code::ErrorCode; 10 | pub use response::EricResponse; 11 | 12 | #[derive(Debug, Clone, Copy)] 13 | pub(crate) enum ProcessingFlag { 14 | Validate = 1 << 1, 15 | Send = 1 << 2, 16 | Print = 1 << 5, 17 | SendAndPrint = 1 << 2 | 1 << 5, 18 | #[allow(dead_code)] 19 | CheckHints = 1 << 7, 20 | #[allow(dead_code)] 21 | ValidateWithoutDate = 1 << 8, 22 | } 23 | 24 | impl ProcessingFlag { 25 | pub fn into_u32(self) -> u32 { 26 | self as u32 27 | } 28 | } 29 | 30 | pub(crate) enum Preview { 31 | Yes = 1, 32 | No = 0, 33 | } 34 | -------------------------------------------------------------------------------- /eric-sdk/src/response.rs: -------------------------------------------------------------------------------- 1 | use crate::error_code::ErrorCode; 2 | use eric_bindings::{ 3 | EricReturnBufferApi, EricRueckgabepufferErzeugen, EricRueckgabepufferFreigeben, 4 | EricRueckgabepufferInhalt, 5 | }; 6 | use std::ffi::CStr; 7 | 8 | /// A structure which summarizes the response from the Eric instance. 9 | #[derive(Debug)] 10 | pub struct EricResponse { 11 | /// The error code returned by the Eric instance. 12 | pub error_code: i32, 13 | /// The response when validating an XML file. 14 | pub validation_response: String, 15 | /// The response when an XML file is send to the tax authorities. 16 | pub server_response: String, 17 | } 18 | 19 | impl EricResponse { 20 | pub fn new(error_code: i32, validation_response: String, server_response: String) -> Self { 21 | Self { 22 | error_code, 23 | validation_response, 24 | server_response, 25 | } 26 | } 27 | } 28 | 29 | pub struct ResponseBuffer { 30 | ctx: *mut EricReturnBufferApi, 31 | } 32 | 33 | impl ResponseBuffer { 34 | pub fn new() -> Result { 35 | let response_buffer = unsafe { EricRueckgabepufferErzeugen() }; 36 | 37 | Ok(ResponseBuffer { 38 | ctx: response_buffer, 39 | }) 40 | } 41 | 42 | pub fn as_ptr(&self) -> *mut EricReturnBufferApi { 43 | self.ctx 44 | } 45 | 46 | pub fn read(&self) -> Result<&str, anyhow::Error> { 47 | let buffer = unsafe { 48 | let ptr = EricRueckgabepufferInhalt(self.ctx); 49 | CStr::from_ptr(ptr) 50 | }; 51 | 52 | Ok(buffer.to_str()?) 53 | } 54 | } 55 | 56 | impl Drop for ResponseBuffer { 57 | fn drop(&mut self) { 58 | println!("Cleaning up response buffer"); 59 | 60 | let error_code = unsafe { EricRueckgabepufferFreigeben(self.ctx) }; 61 | 62 | match error_code { 63 | x if x == ErrorCode::ERIC_OK as i32 => (), 64 | error_code => panic!("Can't drop reponse buffer: {}", error_code), 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /eric-sdk/src/utils.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Context; 2 | use std::{ 3 | ffi::{CString, OsStr}, 4 | os::unix::prelude::OsStrExt, 5 | path::{Path, PathBuf}, 6 | }; 7 | 8 | pub trait ToCString { 9 | fn try_to_cstring(self) -> Result; 10 | } 11 | 12 | impl ToCString for String { 13 | fn try_to_cstring(self) -> Result { 14 | CString::new(self).context("Can't convert to CString") 15 | } 16 | } 17 | 18 | impl ToCString for &str { 19 | fn try_to_cstring(self) -> Result { 20 | CString::new(self).context("Can't convert to CString") 21 | } 22 | } 23 | 24 | impl ToCString for PathBuf { 25 | fn try_to_cstring(self) -> Result { 26 | self.to_str() 27 | .context("Can't convert path to CString")? 28 | .try_to_cstring() 29 | } 30 | } 31 | 32 | impl ToCString for &Path { 33 | fn try_to_cstring(self) -> Result { 34 | self.to_str() 35 | .context("Can't convert path to CString")? 36 | .try_to_cstring() 37 | } 38 | } 39 | 40 | impl ToCString for &OsStr { 41 | fn try_to_cstring(self) -> Result { 42 | // TODO: implement conversion for Windows and macOS 43 | CString::new(self.as_bytes()).context("Can't convert OsStr to CString") 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /eric-sdk/tests/test_send.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Context; 2 | use eric_sdk::{Eric, ErrorCode}; 3 | use roxmltree::Document; 4 | use std::{env::current_dir, fs, path::Path}; 5 | 6 | #[test] 7 | #[cfg_attr(not(feature = "external-test"), ignore)] 8 | fn test_send() { 9 | let log_path = current_dir().unwrap(); 10 | let xml_path = Path::new("./test_data/taxonomy/v6.5/SteuerbilanzAutoverkaeufer_PersG.xml"); 11 | let xml = fs::read_to_string(xml_path) 12 | .context(format!("Can't read file: {}", xml_path.display())) 13 | .unwrap(); 14 | let taxonomy_type = "Bilanz"; 15 | let taxonomy_version = "6.5"; 16 | let pdf_path = None; 17 | 18 | let eric = Eric::new(&log_path).unwrap(); 19 | 20 | let res = eric.send(xml, taxonomy_type, taxonomy_version, pdf_path); 21 | println!("{:#?}", res); 22 | assert!(res.is_ok(), "{}", res.unwrap_err()); 23 | 24 | let response = res.unwrap(); 25 | assert_eq!(response.error_code, ErrorCode::ERIC_OK as i32); 26 | 27 | let doc = Document::parse(&response.validation_response).unwrap(); 28 | println!("Doc: {:#?}", doc); 29 | let node = doc.descendants().find(|node| node.has_tag_name("Erfolg")); 30 | assert!(node.is_some()); 31 | let node = node.unwrap(); 32 | assert_eq!(node.tag_name().name(), "Erfolg"); 33 | } 34 | 35 | #[test] 36 | #[cfg_attr(not(feature = "external-test"), ignore)] 37 | fn test_send_and_print() { 38 | let log_path = current_dir().unwrap(); 39 | let xml_path = Path::new("./test_data/taxonomy/v6.5/SteuerbilanzAutoverkaeufer_PersG.xml"); 40 | let xml = fs::read_to_string(xml_path) 41 | .context(format!("Can't read file: {}", xml_path.display())) 42 | .unwrap(); 43 | let taxonomy_type = "Bilanz"; 44 | let taxonomy_version = "6.5"; 45 | let pdf_path = "ebilanz.pdf"; 46 | 47 | let eric = Eric::new(&log_path).unwrap(); 48 | 49 | let res = eric.send(xml, taxonomy_type, taxonomy_version, Some(pdf_path)); 50 | println!("{:#?}", res); 51 | assert!(res.is_ok(), "{}", res.unwrap_err()); 52 | 53 | let response = res.unwrap(); 54 | assert_eq!(response.error_code, ErrorCode::ERIC_OK as i32); 55 | 56 | let doc = Document::parse(&response.validation_response).unwrap(); 57 | println!("Doc: {:#?}", doc); 58 | let node = doc.descendants().find(|node| node.has_tag_name("Erfolg")); 59 | assert!(node.is_some()); 60 | let node = node.unwrap(); 61 | assert_eq!(node.tag_name().name(), "Erfolg"); 62 | } 63 | -------------------------------------------------------------------------------- /eric-sdk/tests/test_validate.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Context; 2 | use eric_sdk::{Eric, ErrorCode}; 3 | use roxmltree::Document; 4 | use std::{env::current_dir, fs, path::Path}; 5 | 6 | #[test] 7 | #[cfg_attr(feature = "external-test", ignore)] 8 | fn test_validate() { 9 | let log_path = current_dir().unwrap(); 10 | let xml_path = Path::new("./test_data/taxonomy/v6.5/SteuerbilanzAutoverkaeufer_PersG.xml"); 11 | let xml = fs::read_to_string(xml_path) 12 | .context(format!("Can't read file: {}", xml_path.display())) 13 | .unwrap(); 14 | let taxonomy_type = "Bilanz"; 15 | let taxonomy_version = "6.5"; 16 | let pdf_path = None; 17 | 18 | let eric = Eric::new(&log_path).unwrap(); 19 | 20 | let res = eric.validate(xml, taxonomy_type, taxonomy_version, pdf_path); 21 | println!("{:#?}", res); 22 | assert!(res.is_ok(), "{}", res.unwrap_err()); 23 | 24 | let response = res.unwrap(); 25 | assert_eq!(response.error_code, ErrorCode::ERIC_OK as i32); 26 | 27 | let doc = Document::parse(&response.validation_response).unwrap(); 28 | println!("Doc: {:#?}", doc); 29 | let node = doc.descendants().find(|node| node.has_tag_name("Erfolg")); 30 | assert!(node.is_some()); 31 | let node = node.unwrap(); 32 | assert_eq!(node.tag_name().name(), "Erfolg"); 33 | 34 | assert!(response.server_response.is_empty()); 35 | } 36 | 37 | #[test] 38 | #[cfg_attr(feature = "external-test", ignore)] 39 | fn test_validate_and_print() { 40 | let log_path = current_dir().unwrap(); 41 | let xml_path = Path::new("./test_data/taxonomy/v6.5/SteuerbilanzAutoverkaeufer_PersG.xml"); 42 | let xml = fs::read_to_string(xml_path) 43 | .context(format!("Can't read file: {}", xml_path.display())) 44 | .unwrap(); 45 | let taxonomy_type = "Bilanz"; 46 | let taxonomy_version = "6.5"; 47 | let pdf_path = "ebilanz.pdf"; 48 | 49 | let eric = Eric::new(&log_path).unwrap(); 50 | 51 | let res = eric.validate(xml, taxonomy_type, taxonomy_version, Some(pdf_path)); 52 | println!("{:#?}", res); 53 | assert!(res.is_ok(), "{}", res.unwrap_err()); 54 | 55 | let response = res.unwrap(); 56 | assert_eq!(response.error_code, ErrorCode::ERIC_OK as i32); 57 | 58 | let doc = Document::parse(&response.validation_response).unwrap(); 59 | println!("Doc: {:#?}", doc); 60 | let node = doc.descendants().find(|node| node.has_tag_name("Erfolg")); 61 | assert!(node.is_some()); 62 | let node = node.unwrap(); 63 | assert_eq!(node.tag_name().name(), "Erfolg"); 64 | 65 | assert!(response.server_response.is_empty()); 66 | } 67 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.80" 3 | profile = "default" -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | unstable_features = true 2 | imports_granularity = "Crate" 3 | group_imports = "One" 4 | format_code_in_doc_comments = true 5 | --------------------------------------------------------------------------------