diff --git a/.design/README.md b/.design/README.md index 601d3c7e..53687235 100644 --- a/.design/README.md +++ b/.design/README.md @@ -1,5 +1,5 @@
-

Sniffnet

+

Sniffnet

Design Guidelines & Resources

A collection of design contribution guidelines and resources for Sniffnet.

@@ -32,7 +32,7 @@ with many additional functionalities planned for the future releases. 1. Check out open [issues](https://github.com/gyulyvgc/sniffnet/issues) here on GitHub (we label them with `design: 💅required`) 2. Feel free to open an issue on your own if you find something you would like to contribute to the project and use the `design: 💡idea` label for it. 3. Clone the public Figma files if available or create new ones and share them publicly -4. Add your contributions to an issue and I promise I will review your contribution carefully and foster discussions +4. Add your contributions to an issue, and I promise I will review your contribution carefully and foster discussions **We encourage you to:** @@ -50,7 +50,7 @@ All users with a decent amount of technological knowledge. Typical users' age ra ### Design files -> Since I do not have a design team at hand – most of my product does not have any Design files and you'll be forced to browse through the product itself and propose improvements. +> Since I do not have a design team at hand – most of my product does not have any Design files, and you'll be forced to browse through the product itself and propose improvements. ## 💅 Design relevant materials @@ -66,7 +66,7 @@ For info on the used RGB colors, I suggest you to give a look at the file [style ### Logos -You can find a set of logos [here](https://github.com/GyulyVGC/sniffnet/tree/main/resources) +You can find a set of logos [here](https://github.com/GyulyVGC/sniffnet/tree/main/resources/logos) ## 🎓 License diff --git a/.gitignore b/.gitignore index 968c0e34..d40bed68 100644 --- a/.gitignore +++ b/.gitignore @@ -179,10 +179,6 @@ Temporary Items debug/ target/ -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock - # These are backup files generated by rustfmt **/*.rs.bk @@ -220,7 +216,6 @@ $RECYCLE.BIN/ # report file generated by the application and country database *.txt *.csv -/country_db #folder with reports /sniffnet_* diff --git a/CHANGELOG.md b/CHANGELOG.md index bbfff174..65276fae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,27 @@ All Sniffnet releases with the relative changes are documented in this file. +## [1.1.0] - 2023-02-07 + +- Added Custom Notifications to inform the user when defined network events occur: + * data intensity exceeded a defined packets per second rate + * data intensity exceeded a defined bytes per second rate + * new data are exchanged from one of the favorite connections +- Added Settings pages to configure the state of the application (persistently stored in a configuration file): + * customise notifications + * choose between 4 different application styles + * set the application language (this release introduces the Italian language 🇮🇹, and more languages will be supported soon) +- Added Geolocation of the remote IP addresses (consult the README for more information) +- Implemented the possibility of marking a group of connections as favorites and added favorites view to the report +- Added modal to ask the user for confirmation before leaving the current analysis +- Added Tooltips to help the user better understand the function of some buttons +- Partially implemented support for broadcast IP addresses (still missing IPv4 directed broadcast) +- The application window is now maximized after start +- All the GUI text fonts have been replaced with 'Inconsolata' +- Fixed issue [#48](https://github.com/GyulyVGC/sniffnet/issues/48) adding a horizontal scrollable to the report view + + + ## [1.0.1] - 2022-11-30 - Substituted command `open` with command `xdg-open` on Linux systems to solve the problem described in issues [#13](https://github.com/GyulyVGC/sniffnet/issues/13) and [#23](https://github.com/GyulyVGC/sniffnet/issues/23) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7d4972a6..18cd8ccc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -

Sniffnet

+

Sniffnet

# How can you contribute to the Sniffnet project? diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..522fb5a5 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,3631 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ab_glyph" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcdbc68024b653943864d436fe8a24b028095bc1cf91a8926f8241e4aaffe59" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330223a1aecc308757b9926e9391c9b47f8ef2dbd8aea9df88312aea18c5e8d6" + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "alsa" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5915f52fe2cf65e83924d037b6c5290b7cee097c6b5c8700746e6168a343fd6b" +dependencies = [ + "alsa-sys", + "bitflags", + "libc", + "nix 0.23.2", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "ash" +version = "0.37.1+1.3.235" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "911015c962d56e2e4052f40182ca5462ba60a3d2ff04e827c365a0ab3d65726d" +dependencies = [ + "libloading 0.7.4", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + +[[package]] +name = "bindgen" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a022e58a142a46fea340d68012b9201c094e93ec3d033a944a24f8fd4a4f09a" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bit_field" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "bumpalo" +version = "3.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" + +[[package]] +name = "bytemuck" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fe233b960f12f8007e3db2d136e3cb1c291bfd7396e384ee76025fc1a3932b4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" + +[[package]] +name = "calloop" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19457a0da465234abd76134a5c2a910c14bd3c5558463e4396ab9a37a328e465" +dependencies = [ + "log", + "nix 0.25.1", + "slotmap", + "thiserror", + "vec_map", +] + +[[package]] +name = "cc" +version = "1.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "chrono" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +dependencies = [ + "iana-time-zone", + "num-integer", + "num-traits", + "winapi", +] + +[[package]] +name = "clang-sys" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" +dependencies = [ + "glob", + "libc", + "libloading 0.7.4", +] + +[[package]] +name = "clipboard-win" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4ab1b92798304eedc095b53942963240037c0516452cb11aeba709d420b2219" +dependencies = [ + "error-code", + "str-buf", + "winapi", +] + +[[package]] +name = "clipboard_macos" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145a7f9e9b89453bc0a5e32d166456405d389cea5b578f57f1274b1397588a95" +dependencies = [ + "objc", + "objc-foundation", + "objc_id", +] + +[[package]] +name = "clipboard_wayland" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f6364a9f7a66f2ac1a1a098aa1c7f6b686f2496c6ac5e5c0d773445df912747" +dependencies = [ + "smithay-clipboard", +] + +[[package]] +name = "clipboard_x11" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "983a7010836ecd04dde2c6d27a0cb56ec5d21572177e782bdcb24a600124e921" +dependencies = [ + "thiserror", + "x11rb", +] + +[[package]] +name = "cmake" +version = "0.1.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db34956e100b30725f2eb215f90d4871051239535632f84fea3bc92722c66b7c" +dependencies = [ + "cc", +] + +[[package]] +name = "cocoa" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" +dependencies = [ + "bitflags", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types 0.3.2", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" +dependencies = [ + "bitflags", + "block", + "core-foundation", + "core-graphics-types", + "foreign-types 0.3.2", + "libc", + "objc", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "confy" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37668cb35145dcfaa1931a5f37fde375eeae8068b4c0d2f289da28a270b2d2c" +dependencies = [ + "directories", + "serde", + "thiserror", + "toml", +] + +[[package]] +name = "const_panic" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58baae561b85ca19b3122a9ddd35c8ec40c3bcd14fe89921824eae73f7baffbf" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags", + "core-foundation", + "core-graphics-types", + "foreign-types 0.3.2", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation", + "foreign-types 0.3.2", + "libc", +] + +[[package]] +name = "core-text" +version = "19.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25" +dependencies = [ + "core-foundation", + "core-graphics", + "foreign-types 0.3.2", + "libc", +] + +[[package]] +name = "coreaudio-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88" +dependencies = [ + "bitflags", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a9444b94b8024feecc29e01a9706c69c1e26bfee480221c90764200cfd778fb" +dependencies = [ + "bindgen", +] + +[[package]] +name = "cpal" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f342c1b63e185e9953584ff2199726bf53850d96610a310e3aca09e9405a2d0b" +dependencies = [ + "alsa", + "core-foundation-sys", + "coreaudio-rs", + "jni", + "js-sys", + "libc", + "mach", + "ndk 0.7.0", + "ndk-context", + "oboe", + "once_cell", + "parking_lot 0.12.1", + "stdweb", + "thiserror", + "web-sys", + "windows", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset 0.7.1", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossfont" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21fd3add36ea31aba1520aa5288714dd63be506106753226d0eb387a93bc9c45" +dependencies = [ + "cocoa", + "core-foundation", + "core-foundation-sys", + "core-graphics", + "core-text", + "dwrote", + "foreign-types 0.5.0", + "freetype-rs", + "libc", + "log", + "objc", + "once_cell", + "pkg-config", + "servo-fontconfig", + "winapi", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + +[[package]] +name = "cxx" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdf07d07d6531bfcdbe9b8b739b104610c6508dcc4d63b410585faf338241daf" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2eb5b96ecdc99f72657332953d4d9c50135af1bac34277801cc3937906ebd39" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac040a39517fd1674e0f32177648334b0f4074625b5588a64519804ba0553b12" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "d3d12" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "827914e1f53b1e0e025ecd3d967a7836b7bcb54520f90e21ef8df7b4d88a2759" +dependencies = [ + "bitflags", + "libloading 0.7.4", + "winapi", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "directories" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" +dependencies = [ + "libloading 0.7.4", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "dwrote" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" +dependencies = [ + "lazy_static", + "libc", + "serde", + "serde_derive", + "winapi", + "wio", +] + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "encase" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a516181e9a36e8982cb37933c5e7dba638c42938cacde46ee4e5b4156f881b9" +dependencies = [ + "const_panic", + "encase_derive", + "glam", + "thiserror", +] + +[[package]] +name = "encase_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5b802412eea315f29f2bb2da3a5963cd6121f56eaa06aebcdc0c54eea578f22" +dependencies = [ + "encase_derive_impl", +] + +[[package]] +name = "encase_derive_impl" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2f4de457d974f548d2c2a16f709ebd81013579e543bd1a9b19ced88132c2cf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "error-code" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" +dependencies = [ + "libc", + "str-buf", +] + +[[package]] +name = "etherparse" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "827292ea592108849932ad8e30218f8b1f21c0dfd0696698a18b5d0aed62d990" +dependencies = [ + "arrayvec 0.7.2", +] + +[[package]] +name = "euclid" +version = "0.22.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b52c2ef4a78da0ba68fbe1fd920627411096d2ac478f7f4c9f3a54ba6705bade" +dependencies = [ + "num-traits", +] + +[[package]] +name = "expat-sys" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658f19728920138342f68408b7cf7644d90d4784353d8ebc32e7e8663dbe45fa" +dependencies = [ + "cmake", + "pkg-config", +] + +[[package]] +name = "exr" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eb5f255b5980bb0c8cf676b675d1a99be40f316881444f44e0462eaf5df5ded" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "smallvec", + "threadpool", +] + +[[package]] +name = "find-crate" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2" +dependencies = [ + "toml", +] + +[[package]] +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float_next_after" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fc612c5837986b7104a87a0df74a5460931f1c5274be12f8d0f40aa2f30d632" +dependencies = [ + "num-traits", +] + +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "pin-project", + "spin", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8469d0d40519bc608ec6863f1cc88f3f1deee15913f2f3b3e573d81ed38cccc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "freetype-rs" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74eadec9d0a5c28c54bb9882e54787275152a4e36ce206b45d7451384e5bf5fb" +dependencies = [ + "bitflags", + "freetype-sys", + "libc", +] + +[[package]] +name = "freetype-sys" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a" +dependencies = [ + "cmake", + "libc", + "pkg-config", +] + +[[package]] +name = "futures" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" + +[[package]] +name = "futures-executor" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" + +[[package]] +name = "futures-macro" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" + +[[package]] +name = "futures-task" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" + +[[package]] +name = "futures-util" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gif" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "glam" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518faa5064866338b013ff9b2350dc318e14cc4fcd6cb8206d7e7c9886c98815" + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "glow" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8bd5877156a19b8ac83a29b2306fe20537429d318f3ff0a1a2119f8d9c61919" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glow_glyph" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4e62c64947b9a24fe20e2bba9ad819ecb506ef5c8df7ffc4737464c6df9510" +dependencies = [ + "bytemuck", + "glow", + "glyph_brush", + "log", +] + +[[package]] +name = "glyph_brush" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac02497410cdb5062cc056a33f2e1e19ff69fbf26a4be9a02bf29d6e17ea105b" +dependencies = [ + "glyph_brush_draw_cache", + "glyph_brush_layout", + "log", + "ordered-float", + "rustc-hash", + "twox-hash", +] + +[[package]] +name = "glyph_brush_draw_cache" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6010675390f6889e09a21e2c8b575b3ee25667ea8237a8d59423f73cb8c28610" +dependencies = [ + "ab_glyph", + "crossbeam-channel", + "crossbeam-deque", + "linked-hash-map", + "rayon", + "rustc-hash", +] + +[[package]] +name = "glyph_brush_layout" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc32c2334f00ca5ac3695c5009ae35da21da8c62d255b5b96d56e2597a637a38" +dependencies = [ + "ab_glyph", + "approx", + "xi-unicode", +] + +[[package]] +name = "gpu-alloc" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc59e5f710e310e76e6707f86c561dd646f69a8876da9131703b2f717de818d" +dependencies = [ + "bitflags", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5" +dependencies = [ + "bitflags", +] + +[[package]] +name = "gpu-descriptor" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b0c02e1ba0bdb14e965058ca34e09c020f8e507a760df1121728e0aef68d57a" +dependencies = [ + "bitflags", + "gpu-descriptor-types", + "hashbrown", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "363e3677e55ad168fef68cf9de3a4a310b53124c5e784c53a1d70e92d23f2126" +dependencies = [ + "bitflags", +] + +[[package]] +name = "guillotiere" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62d5865c036cb1393e23c50693df631d3f5d7bcca4c04fe4cc0fd592e74a782" +dependencies = [ + "euclid", + "svg_fmt", +] + +[[package]] +name = "half" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +dependencies = [ + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "iana-time-zone" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + +[[package]] +name = "iced" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df71e87f8211b57a439d0764131d2c421a9195036dd4b6608033b05f2f16c196" +dependencies = [ + "iced_core", + "iced_futures", + "iced_glow", + "iced_graphics", + "iced_native", + "iced_wgpu", + "iced_winit", + "image", + "thiserror", +] + +[[package]] +name = "iced_core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ade666613eb8b621971a59cfae9e11ec051f32afc5ed4d8e8915d5abfaf2cee" +dependencies = [ + "bitflags", + "instant", + "palette", +] + +[[package]] +name = "iced_futures" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cc3a9fd79b857228dde2a3e923a04ade4095abeda33248c6230e8c909749366" +dependencies = [ + "futures", + "log", + "tokio", + "wasm-bindgen-futures", + "wasm-timer", +] + +[[package]] +name = "iced_glow" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95755f62fec2ec2c8f8bc2c0be5072b1d0dfed8db250686059ddcce5da530acf" +dependencies = [ + "bytemuck", + "euclid", + "glow", + "glow_glyph", + "glyph_brush", + "iced_graphics", + "iced_native", + "log", +] + +[[package]] +name = "iced_graphics" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54177b85fdae36a8a1a4f052a5c65c5006565dc27f1feead13eeeed10fd0975a" +dependencies = [ + "bitflags", + "bytemuck", + "glam", + "iced_native", + "iced_style", + "image", + "kamadak-exif", + "log", + "lyon", + "raw-window-handle 0.5.0", + "thiserror", +] + +[[package]] +name = "iced_native" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79d57c8e8672e90c55d4f9f55511b03e5a74af9d296be9693e9c07cd9eed4563" +dependencies = [ + "iced_core", + "iced_futures", + "iced_style", + "num-traits", + "twox-hash", + "unicode-segmentation", +] + +[[package]] +name = "iced_style" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b992f5e1828c61af3661fc0e7bf141ef5284007a41fa6667c5e79d047a03daf4" +dependencies = [ + "iced_core", + "once_cell", + "palette", +] + +[[package]] +name = "iced_wgpu" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4bb296363d1b18d4f57e1c69bb19591405e61d47764e43078bba31c6689fca5" +dependencies = [ + "bitflags", + "bytemuck", + "encase", + "futures", + "glam", + "glyph_brush", + "guillotiere", + "iced_graphics", + "iced_native", + "log", + "raw-window-handle 0.5.0", + "wgpu", + "wgpu_glyph", +] + +[[package]] +name = "iced_winit" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d528f882781c5594cb3d2416fe18787b4364e0cdd39f03d077ccc0becac1f9bd" +dependencies = [ + "iced_futures", + "iced_graphics", + "iced_native", + "log", + "thiserror", + "web-sys", + "winapi", + "window_clipboard", + "winit", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "image" +version = "0.24.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b7ea949b537b0fd0af141fff8c77690f2ce96f4f41f042ccb6c69c6c965945" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "jpeg-decoder", + "num-rational", + "num-traits", + "png", + "scoped_threadpool", + "tiff", +] + +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "ipnetwork" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4088d739b183546b239688ddbc79891831df421773df95e236daf7867866d355" +dependencies = [ + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +dependencies = [ + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" +dependencies = [ + "rayon", +] + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kamadak-exif" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef4fc70d0ab7e5b6bafa30216a6b48705ea964cdfc29c050f2412295eba58077" +dependencies = [ + "mutate_once", +] + +[[package]] +name = "khronos-egl" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" +dependencies = [ + "libc", + "libloading 0.7.4", + "pkg-config", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + +[[package]] +name = "libc" +version = "0.2.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" + +[[package]] +name = "libloading" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libm" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" + +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "lyon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7f9cda98b5430809e63ca5197b06c7d191bf7e26dfc467d5a3f0290e2a74f" +dependencies = [ + "lyon_algorithms", + "lyon_tessellation", +] + +[[package]] +name = "lyon_algorithms" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb7a1845c15729d73d25d42cb650b647f73c3494453a5c3cd3aae0df3ac5c6c" +dependencies = [ + "lyon_path", + "num-traits", +] + +[[package]] +name = "lyon_geom" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74df1ff0a0147282eb10699537a03baa7d31972b58984a1d44ce0624043fe8ad" +dependencies = [ + "arrayvec 0.7.2", + "euclid", + "num-traits", +] + +[[package]] +name = "lyon_path" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8358c012e5651e4619cfd0b5b75c0f77866181a01b0909aab4bae14adf660" +dependencies = [ + "lyon_geom", + "num-traits", +] + +[[package]] +name = "lyon_tessellation" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b19b1b39823ddc178d98cbb42c70ffcd3bfbcbde589f38752bedde982269c3" +dependencies = [ + "float_next_after", + "lyon_path", + "thiserror", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "maxminddb" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe2ba61113f9f7a9f0e87c519682d39c43a6f3f79c2cc42c3ba3dda83b1fa334" +dependencies = [ + "ipnetwork", + "log", + "memchr", + "serde", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "metal" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de11355d1f6781482d027a3b4d4de7825dcedb197bf573e0596d00008402d060" +dependencies = [ + "bitflags", + "block", + "core-graphics-types", + "foreign-types 0.3.2", + "log", + "objc", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "minimp3" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985438f75febf74c392071a975a29641b420dd84431135a6e6db721de4b74372" +dependencies = [ + "minimp3-sys", + "slice-deque", + "thiserror", +] + +[[package]] +name = "minimp3-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e21c73734c69dc95696c9ed8926a2b393171d98b3f5f5935686a26a487ab9b90" +dependencies = [ + "cc", +] + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.42.0", +] + +[[package]] +name = "mutate_once" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16cf681a23b4d0a43fc35024c176437f9dcd818db34e0f42ab456a0ee5ad497b" + +[[package]] +name = "naga" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "262d2840e72dbe250e8cf2f522d080988dfca624c4112c096238a4845f591707" +dependencies = [ + "bit-set", + "bitflags", + "codespan-reporting", + "hexf-parse", + "indexmap", + "log", + "num-traits", + "rustc-hash", + "spirv", + "termcolor", + "thiserror", + "unicode-xid", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ndk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.3.0", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.4.1+23.1.7779620", + "num_enum", + "raw-window-handle 0.5.0", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-glue" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0434fabdd2c15e0aab768ca31d5b7b333717f03cf02037d5a0a3ff3c278ed67f" +dependencies = [ + "libc", + "log", + "ndk 0.7.0", + "ndk-context", + "ndk-macro", + "ndk-sys 0.4.1+23.1.7779620", + "once_cell", + "parking_lot 0.12.1", +] + +[[package]] +name = "ndk-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" +dependencies = [ + "darling", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "ndk-sys" +version = "0.4.1+23.1.7779620" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nix" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "nix" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "nix" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "nix" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +dependencies = [ + "autocfg", + "bitflags", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "oboe" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f63c358b4fa0fbcfefd7c8be5cfc39c08ce2389f5325687e7762a48d30a5c1" +dependencies = [ + "jni", + "ndk 0.6.0", + "ndk-context", + "num-derive", + "num-traits", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3370abb7372ed744232c12954d920d1a40f1c4686de9e79e800021ef492294bd" +dependencies = [ + "cc", +] + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "ordered-float" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d84eb1409416d254e4a9c8fa56cc24701755025b458f0fcd8e59e1f5f40c23bf" +dependencies = [ + "num-traits", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18904d3c65493a9f0d7542293d1a7f69bfdc309a6b9ef4f46dc3e58b0577edc5" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "palette" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f9cd68f7112581033f157e56c77ac4a5538ec5836a2e39284e65bd7d7275e49" +dependencies = [ + "approx", + "num-traits", + "palette_derive", + "phf", +] + +[[package]] +name = "palette_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05eedf46a8e7c27f74af0c9cfcdb004ceca158cb1b918c6f68f8d7a549b3e427" +dependencies = [ + "find-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.5", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.5", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys 0.42.0", +] + +[[package]] +name = "pcap" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d536b12f51fa925b590a6681765ed2bd9f1beb1d2953fa5fe5a20f7c1087b994" +dependencies = [ + "bitflags", + "errno", + "libc", + "libloading 0.6.7", + "pkg-config", + "regex", + "windows-sys 0.36.1", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "phf" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "plotters" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +dependencies = [ + "num-traits", + "plotters-backend", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" + +[[package]] +name = "plotters-iced" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ae63a3ff1c23d2f3c9f67bb940494d64efd4e0ece410fe9ff01d8584b11ac6b" +dependencies = [ + "iced_graphics", + "iced_native", + "plotters", + "plotters-backend", +] + +[[package]] +name = "png" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" +dependencies = [ + "bitflags", + "crc32fast", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro-crate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +dependencies = [ + "once_cell", + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74605f360ce573babfe43964cbe520294dcb081afbf8c108fc6e23036b4da2df" + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "range-alloc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6" + +[[package]] +name = "raw-window-handle" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28f55143d0548dad60bb4fbdc835a3d7ac6acc3324506450c5fdd6e42903a76" +dependencies = [ + "libc", + "raw-window-handle 0.4.3", +] + +[[package]] +name = "raw-window-handle" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" +dependencies = [ + "cty", +] + +[[package]] +name = "raw-window-handle" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a" +dependencies = [ + "cty", +] + +[[package]] +name = "rayon" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "renderdoc-sys" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157" + +[[package]] +name = "rodio" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb10b653d5ec0e9411a2e7d46e2c7f4046fd87d35b9955bd73ba4108d69072b5" +dependencies = [ + "cpal", + "minimp3", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "safe_arch" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ff3d6d9696af502cc3110dacce942840fb06ff4514cad92236ecc455f2ce05" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + +[[package]] +name = "sctk-adwaita" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61270629cc6b4d77ec1907db1033d5c2e1a404c412743621981a871dc9c12339" +dependencies = [ + "crossfont", + "log", + "smithay-client-toolkit", + "tiny-skia", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "servo-fontconfig" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e3e22fe5fd73d04ebf0daa049d3efe3eae55369ce38ab16d07ddd9ac5c217c" +dependencies = [ + "libc", + "servo-fontconfig-sys", +] + +[[package]] +name = "servo-fontconfig-sys" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36b879db9892dfa40f95da1c38a835d41634b825fbd8c4c418093d53c24b388" +dependencies = [ + "expat-sys", + "freetype-sys", + "pkg-config", +] + +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slice-deque" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31ef6ee280cdefba6d2d0b4b78a84a1c1a3f3a4cec98c2d4231c8bc225de0f25" +dependencies = [ + "libc", + "mach", + "winapi", +] + +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "smithay-client-toolkit" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f307c47d32d2715eb2e0ece5589057820e0e5e70d07c247d1063e844e107f454" +dependencies = [ + "bitflags", + "calloop", + "dlib", + "lazy_static", + "log", + "memmap2", + "nix 0.24.3", + "pkg-config", + "wayland-client", + "wayland-cursor", + "wayland-protocols", +] + +[[package]] +name = "smithay-clipboard" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a345c870a1fae0b1b779085e81b51e614767c239e93503588e54c5b17f4b0e8" +dependencies = [ + "smithay-client-toolkit", + "wayland-client", +] + +[[package]] +name = "sniffnet" +version = "1.1.0" +dependencies = [ + "chrono", + "confy", + "etherparse", + "iced", + "iced_native", + "indexmap", + "maxminddb", + "pcap", + "plotters", + "plotters-iced", + "rodio", + "serde", + "thousands", +] + +[[package]] +name = "spin" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spirv" +version = "0.2.0+1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830" +dependencies = [ + "bitflags", + "num-traits", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + +[[package]] +name = "str-buf" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "svg_fmt" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb1df15f412ee2e9dfc1c504260fa695c1c3f10fe9f4a6ee2d2184d7d6450e2" + +[[package]] +name = "syn" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thousands" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tiff" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7449334f9ff2baf290d55d73983a7d6fa15e01198faef72af07e2a8db851e471" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[package]] +name = "tiny-skia" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "642680569bb895b16e4b9d181c60be1ed136fa0c9c7f11d004daf053ba89bf82" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "bytemuck", + "cfg-if", + "png", + "safe_arch", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c114d32f0c2ee43d585367cb013dfaba967ab9f62b90d9af0d696e955e70fa6c" +dependencies = [ + "arrayref", + "bytemuck", +] + +[[package]] +name = "tokio" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" +dependencies = [ + "autocfg", + "num_cpus", + "pin-project-lite", + "windows-sys 0.42.0", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "ttf-parser" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff" + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "rand", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "unicode-segmentation" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wayland-client" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" +dependencies = [ + "bitflags", + "downcast-rs", + "libc", + "nix 0.24.3", + "scoped-tls", + "wayland-commons", + "wayland-scanner", + "wayland-sys", +] + +[[package]] +name = "wayland-commons" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" +dependencies = [ + "nix 0.24.3", + "once_cell", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-cursor" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" +dependencies = [ + "nix 0.24.3", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" +dependencies = [ + "bitflags", + "wayland-client", + "wayland-commons", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" +dependencies = [ + "proc-macro2", + "quote", + "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" +dependencies = [ + "dlib", + "lazy_static", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "weezl" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" + +[[package]] +name = "wgpu" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f643110d228fd62a60c5ed2ab56c4d5b3704520bd50561174ec4ec74932937" +dependencies = [ + "arrayvec 0.7.2", + "js-sys", + "log", + "naga", + "parking_lot 0.12.1", + "raw-window-handle 0.5.0", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6000d1284ef8eec6076fd5544a73125fd7eb9b635f18dceeb829d826f41724ca" +dependencies = [ + "arrayvec 0.7.2", + "bit-vec", + "bitflags", + "cfg_aliases", + "codespan-reporting", + "fxhash", + "log", + "naga", + "parking_lot 0.12.1", + "profiling", + "raw-window-handle 0.5.0", + "smallvec", + "thiserror", + "web-sys", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cc320a61acb26be4f549c9b1b53405c10a223fbfea363ec39474c32c348d12f" +dependencies = [ + "android_system_properties", + "arrayvec 0.7.2", + "ash", + "bit-set", + "bitflags", + "block", + "core-graphics-types", + "d3d12", + "foreign-types 0.3.2", + "fxhash", + "glow", + "gpu-alloc", + "gpu-descriptor", + "js-sys", + "khronos-egl", + "libloading 0.7.4", + "log", + "metal", + "naga", + "objc", + "parking_lot 0.12.1", + "profiling", + "range-alloc", + "raw-window-handle 0.5.0", + "renderdoc-sys", + "smallvec", + "thiserror", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "winapi", +] + +[[package]] +name = "wgpu-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb6b28ef22cac17b9109b25b3bf8c9a103eeb293d7c5f78653979b09140375f6" +dependencies = [ + "bitflags", +] + +[[package]] +name = "wgpu_glyph" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cafb82773e0f124a33674dab5de4dff73175aeb921949047ab014efb58fb446" +dependencies = [ + "bytemuck", + "glyph_brush", + "log", + "wgpu", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-wsapoll" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "window_clipboard" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b47d7fb4df5cd1fea61e5ee3841380f54359bac814e227d8f72709f4f193f8cf" +dependencies = [ + "clipboard-win", + "clipboard_macos", + "clipboard_wayland", + "clipboard_x11", + "raw-window-handle 0.3.4", + "thiserror", +] + +[[package]] +name = "windows" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647" +dependencies = [ + "windows_aarch64_msvc 0.37.0", + "windows_i686_gnu 0.37.0", + "windows_i686_msvc 0.37.0", + "windows_x86_64_gnu 0.37.0", + "windows_x86_64_msvc 0.37.0", +] + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_gnu" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_i686_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + +[[package]] +name = "winit" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb796d6fbd86b2fd896c9471e6f04d39d750076ebe5680a3958f00f5ab97657c" +dependencies = [ + "bitflags", + "cocoa", + "core-foundation", + "core-graphics", + "dispatch", + "instant", + "libc", + "log", + "mio", + "ndk 0.7.0", + "ndk-glue", + "objc", + "once_cell", + "parking_lot 0.12.1", + "percent-encoding", + "raw-window-handle 0.4.3", + "raw-window-handle 0.5.0", + "sctk-adwaita", + "smithay-client-toolkit", + "wasm-bindgen", + "wayland-client", + "wayland-protocols", + "web-sys", + "windows-sys 0.36.1", + "x11-dl", +] + +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi", +] + +[[package]] +name = "x11-dl" +version = "2.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1536d6965a5d4e573c7ef73a2c15ebcd0b2de3347bdf526c34c297c00ac40f0" +dependencies = [ + "lazy_static", + "libc", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e99be55648b3ae2a52342f9a870c0e138709a3493261ce9b469afe6e4df6d8a" +dependencies = [ + "gethostname", + "nix 0.22.3", + "winapi", + "winapi-wsapoll", +] + +[[package]] +name = "xcursor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" +dependencies = [ + "nom", +] + +[[package]] +name = "xi-unicode" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" + +[[package]] +name = "xml-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" diff --git a/Cargo.toml b/Cargo.toml index dd21a463..3c3f764f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sniffnet" -version = "1.0.1" +version = "1.1.0" authors = ["Giuliano Bellini"] edition = "2021" description = "Application to comfortably monitor your network traffic" @@ -9,12 +9,13 @@ repository = "https://github.com/GyulyVGC/sniffnet" license = "MIT OR Apache-2.0" keywords = ["filter", "network", "packet", "sniffer", "parser"] categories = ["command-line-utilities", "concurrency", "network-programming"] +include = ["src/**/*", "LICENSE-*", "README.md", "CHANGELOG.md"] [package.metadata.bundle] name = "Sniffnet" identifier = "gyulyvgc.sniffnet" -icon = ["./resources/icon.ico"] +icon = ["./resources/logos/icon.ico"] [profile.release] @@ -24,11 +25,15 @@ lto = true [dependencies] pcap = "1.0.0" -etherparse = "0.12.0" -chrono = "0.4.22" +etherparse = "0.13.0" +chrono = { version = "0.4.23", default_features = false, features = ["clock"] } thousands = "0.2.0" -plotters = "0.3.4" -indexmap = "1.9.1" -plotters-iced = "0.3.3" -iced = { version = "0.4.2", features = ["tokio"] } -iced_style = "0.4.0" \ No newline at end of file +indexmap = "1.9.2" +plotters = { version = "0.3.4", default_features = false, features = ["area_series"] } +iced = { version = "0.7.0", features = ["tokio", "image"] } +iced_native = "0.8.0" +plotters-iced = "0.6.0" +maxminddb = "0.23.0" +confy = "0.5.1" +serde = { version = "1.0.152", default_features = false, features = ["derive"] } +rodio = { version = "0.16.0", default_features = false, features = ["mp3"] } diff --git a/README.md b/README.md index f447e7c5..e4f26856 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,17 @@ Multithreaded, cross-platform, reliable
-

+

-
-

Sniffnet is a simple yet insightful application to analyse your network traffic -in a straightforward and appealing way

-
+

+ + +

+ +

+Application translated in: 🇬🇧 - 🇮🇹
+More languages will be supported in the upcoming releases +


@@ -46,11 +51,12 @@ cargo install sniffnet from GitHub releases  You can install Sniffnet through the installers available in the [latest release](https://github.com/GyulyVGC/sniffnet/releases).
- Choose between a Windows installer, a DEB package, or a MacOS disk image (depending on your operating system). + Choose between a Windows installer, a DEB package, or a macOS disk image (depending on your operating system). + ## Required dependencies @@ -99,6 +106,12 @@ sudo apt-get install libpcap-dev sudo setcap cap_net_raw,cap_net_admin=eip ``` +Most Linux system also need this dependency (required to build the library used to play sounds): + +```sh +sudo apt-get install libasound2-dev +``` + Depending on your Linux environment you may also need `libfontconfig`: ```sh @@ -119,29 +132,38 @@ sudo apt-get install libfontconfig libfontconfig1-dev ## Features -- choose a network adapter to inspect -

- -- select filters to apply to the observed traffic -

- -- view real-time charts about traffic intensity (bytes and packets per second, incoming and outgoing) -

- -- view overall statistics about the filtered traffic -

- -- view most relevant connections (most recent, most packets, most bytes) -

- -- save complete textual report with detailed information for each connection: +- 💻 choose a network adapter to inspect +- 🏷️ select filters to apply to the observed traffic +- 📈 view real-time charts about traffic intensity (bytes and packets per second, incoming and outgoing) +- 🔉 set custom notifications to inform you when defined network events occur (data rate exceeded a specified threshold, or new data have been exchanged from your favorite connections) +- 📖 view overall statistics about the filtered traffic +- ⭐ view most relevant connections in real time (most recent, most packets, most bytes, favorites) +- 🌍 get information about the country of the remote address (IP Geolocation) +- 📁 save complete textual report with detailed information for each connection: * source and destination IP addresses * source and destination ports * carried protocols * amount of exchanged packets and bytes * initial and final timestamp of information exchange +- ... and more! +## IP Geolocation + +
+ + See details + + Geolocation refers to the remote IP address of the connection, and it's performed against a [MMDB file](https://maxmind.github.io/MaxMind-DB/): + + > The MMDB (MaxMind database) format has been developed especially for IP lookup. It is optimized to perform lookups on data indexed by IP network ranges quickly and efficiently. If you want the best performance on your IP lookups for use in a production environment, you should use the MMDB format files. + + This format potentially allows Sniffnet to execute different hundreds of IP lookups in a matter of a few milliseconds. + + Sometimes it is not possible to determine the location of an IP address; this is most likely due to the address being a private IP address. + +
+ ## Supported application layer protocols
@@ -202,6 +224,12 @@ Check the [required dependencies](#required-dependencies) section for instructio For a Windows reference, you can check issue [#1](https://github.com/GyulyVGC/sniffnet/issues/1). +Note that most Linux system also need this dependency (required to build the library used to play sounds): + +```sh +sudo apt-get install libasound2-dev +``` + Some Linux systems also need `libfontconfig`, see issue [#18](https://github.com/GyulyVGC/sniffnet/issues/18) for a reference. ### Installers incompatibilities diff --git a/fonts/CourierPrime.ttf b/fonts/CourierPrime.ttf deleted file mode 100644 index db4e6c14..00000000 Binary files a/fonts/CourierPrime.ttf and /dev/null differ diff --git a/fonts/CourierPrimeBold.ttf b/fonts/CourierPrimeBold.ttf deleted file mode 100644 index 1b0888c2..00000000 Binary files a/fonts/CourierPrimeBold.ttf and /dev/null differ diff --git a/fonts/CourierPrimeBoldItalic.ttf b/fonts/CourierPrimeBoldItalic.ttf deleted file mode 100644 index d4e71869..00000000 Binary files a/fonts/CourierPrimeBoldItalic.ttf and /dev/null differ diff --git a/fonts/CourierPrimeItalic.ttf b/fonts/CourierPrimeItalic.ttf deleted file mode 100644 index 75a1343d..00000000 Binary files a/fonts/CourierPrimeItalic.ttf and /dev/null differ diff --git a/fonts/icons.ttf b/fonts/icons.ttf index e2de2846..7debfad2 100644 Binary files a/fonts/icons.ttf and b/fonts/icons.ttf differ diff --git a/fonts/inconsolata-bold.ttf b/fonts/inconsolata-bold.ttf new file mode 100644 index 00000000..58c9fef3 Binary files /dev/null and b/fonts/inconsolata-bold.ttf differ diff --git a/fonts/inconsolata-regular.ttf b/fonts/inconsolata-regular.ttf new file mode 100644 index 00000000..c3acd3e0 Binary files /dev/null and b/fonts/inconsolata-regular.ttf differ diff --git a/fonts/notosans-bold.ttf b/fonts/notosans-bold.ttf deleted file mode 100644 index 75bfbfa1..00000000 Binary files a/fonts/notosans-bold.ttf and /dev/null differ diff --git a/fonts/notosans-regular.ttf b/fonts/notosans-regular.ttf deleted file mode 100644 index 8195d7fe..00000000 Binary files a/fonts/notosans-regular.ttf and /dev/null differ diff --git a/resources/DB/GeoLite2-Country.mmdb b/resources/DB/GeoLite2-Country.mmdb new file mode 100644 index 00000000..46567a34 Binary files /dev/null and b/resources/DB/GeoLite2-Country.mmdb differ diff --git a/resources/adapters_view.png b/resources/adapters_view.png deleted file mode 100644 index ce9d92d3..00000000 Binary files a/resources/adapters_view.png and /dev/null differ diff --git a/resources/charts_view.png b/resources/charts_view.png deleted file mode 100644 index f263d38f..00000000 Binary files a/resources/charts_view.png and /dev/null differ diff --git a/resources/countries_flags/png-16/afghanistan-16x16-32928.png b/resources/countries_flags/png-16/afghanistan-16x16-32928.png new file mode 100644 index 00000000..0ef15b42 Binary files /dev/null and b/resources/countries_flags/png-16/afghanistan-16x16-32928.png differ diff --git a/resources/countries_flags/png-16/aland-16x16-32908.png b/resources/countries_flags/png-16/aland-16x16-32908.png new file mode 100644 index 00000000..e65ccc6d Binary files /dev/null and b/resources/countries_flags/png-16/aland-16x16-32908.png differ diff --git a/resources/countries_flags/png-16/albania-16x16-32909.png b/resources/countries_flags/png-16/albania-16x16-32909.png new file mode 100644 index 00000000..5b942c8d Binary files /dev/null and b/resources/countries_flags/png-16/albania-16x16-32909.png differ diff --git a/resources/countries_flags/png-16/algeria-16x16-32972.png b/resources/countries_flags/png-16/algeria-16x16-32972.png new file mode 100644 index 00000000..3d4b5eb7 Binary files /dev/null and b/resources/countries_flags/png-16/algeria-16x16-32972.png differ diff --git a/resources/countries_flags/png-16/american-16x16-32917.png b/resources/countries_flags/png-16/american-16x16-32917.png new file mode 100644 index 00000000..2461e4b4 Binary files /dev/null and b/resources/countries_flags/png-16/american-16x16-32917.png differ diff --git a/resources/countries_flags/png-16/andorra-16x16-32921.png b/resources/countries_flags/png-16/andorra-16x16-32921.png new file mode 100644 index 00000000..b3a594b7 Binary files /dev/null and b/resources/countries_flags/png-16/andorra-16x16-32921.png differ diff --git a/resources/countries_flags/png-16/angola-16x16-32914.png b/resources/countries_flags/png-16/angola-16x16-32914.png new file mode 100644 index 00000000..7d3ac2fe Binary files /dev/null and b/resources/countries_flags/png-16/angola-16x16-32914.png differ diff --git a/resources/countries_flags/png-16/anguilla-16x16-32924.png b/resources/countries_flags/png-16/anguilla-16x16-32924.png new file mode 100644 index 00000000..39f5dcf0 Binary files /dev/null and b/resources/countries_flags/png-16/anguilla-16x16-32924.png differ diff --git a/resources/countries_flags/png-16/antarctica-16x16-33151.png b/resources/countries_flags/png-16/antarctica-16x16-33151.png new file mode 100644 index 00000000..af18cffa Binary files /dev/null and b/resources/countries_flags/png-16/antarctica-16x16-33151.png differ diff --git a/resources/countries_flags/png-16/antigua-16x16-32910.png b/resources/countries_flags/png-16/antigua-16x16-32910.png new file mode 100644 index 00000000..e45447ec Binary files /dev/null and b/resources/countries_flags/png-16/antigua-16x16-32910.png differ diff --git a/resources/countries_flags/png-16/argentina-16x16-32919.png b/resources/countries_flags/png-16/argentina-16x16-32919.png new file mode 100644 index 00000000..0a46959a Binary files /dev/null and b/resources/countries_flags/png-16/argentina-16x16-32919.png differ diff --git a/resources/countries_flags/png-16/armenia-16x16-32925.png b/resources/countries_flags/png-16/armenia-16x16-32925.png new file mode 100644 index 00000000..1dae9616 Binary files /dev/null and b/resources/countries_flags/png-16/armenia-16x16-32925.png differ diff --git a/resources/countries_flags/png-16/aruba-16x16-32923.png b/resources/countries_flags/png-16/aruba-16x16-32923.png new file mode 100644 index 00000000..1dc3987f Binary files /dev/null and b/resources/countries_flags/png-16/aruba-16x16-32923.png differ diff --git a/resources/countries_flags/png-16/austallia-16x16-32912.png b/resources/countries_flags/png-16/austallia-16x16-32912.png new file mode 100644 index 00000000..40b641ef Binary files /dev/null and b/resources/countries_flags/png-16/austallia-16x16-32912.png differ diff --git a/resources/countries_flags/png-16/austria-16x16-32920.png b/resources/countries_flags/png-16/austria-16x16-32920.png new file mode 100644 index 00000000..c7e73b59 Binary files /dev/null and b/resources/countries_flags/png-16/austria-16x16-32920.png differ diff --git a/resources/countries_flags/png-16/azerbaijan-16x16-32926.png b/resources/countries_flags/png-16/azerbaijan-16x16-32926.png new file mode 100644 index 00000000..974c3e8d Binary files /dev/null and b/resources/countries_flags/png-16/azerbaijan-16x16-32926.png differ diff --git a/resources/countries_flags/png-16/bahamas-16x16-32915.png b/resources/countries_flags/png-16/bahamas-16x16-32915.png new file mode 100644 index 00000000..f2b89471 Binary files /dev/null and b/resources/countries_flags/png-16/bahamas-16x16-32915.png differ diff --git a/resources/countries_flags/png-16/bahrain-16x16-32974.png b/resources/countries_flags/png-16/bahrain-16x16-32974.png new file mode 100644 index 00000000..a129cb05 Binary files /dev/null and b/resources/countries_flags/png-16/bahrain-16x16-32974.png differ diff --git a/resources/countries_flags/png-16/bangladesh-16x16-32916.png b/resources/countries_flags/png-16/bangladesh-16x16-32916.png new file mode 100644 index 00000000..21a89776 Binary files /dev/null and b/resources/countries_flags/png-16/bangladesh-16x16-32916.png differ diff --git a/resources/countries_flags/png-16/barbados-16x16-32913.png b/resources/countries_flags/png-16/barbados-16x16-32913.png new file mode 100644 index 00000000..bb88e429 Binary files /dev/null and b/resources/countries_flags/png-16/barbados-16x16-32913.png differ diff --git a/resources/countries_flags/png-16/belarus-16x16-32918.png b/resources/countries_flags/png-16/belarus-16x16-32918.png new file mode 100644 index 00000000..de7c46b5 Binary files /dev/null and b/resources/countries_flags/png-16/belarus-16x16-32918.png differ diff --git a/resources/countries_flags/png-16/belgium-16x16-32911.png b/resources/countries_flags/png-16/belgium-16x16-32911.png new file mode 100644 index 00000000..52fd90f0 Binary files /dev/null and b/resources/countries_flags/png-16/belgium-16x16-32911.png differ diff --git a/resources/countries_flags/png-16/belize-16x16-32927.png b/resources/countries_flags/png-16/belize-16x16-32927.png new file mode 100644 index 00000000..dac871d6 Binary files /dev/null and b/resources/countries_flags/png-16/belize-16x16-32927.png differ diff --git a/resources/countries_flags/png-16/benin-16x16-32922.png b/resources/countries_flags/png-16/benin-16x16-32922.png new file mode 100644 index 00000000..7e40d8b2 Binary files /dev/null and b/resources/countries_flags/png-16/benin-16x16-32922.png differ diff --git a/resources/countries_flags/png-16/bermuda-16x16-32929.png b/resources/countries_flags/png-16/bermuda-16x16-32929.png new file mode 100644 index 00000000..0a48c8d2 Binary files /dev/null and b/resources/countries_flags/png-16/bermuda-16x16-32929.png differ diff --git a/resources/countries_flags/png-16/bhutan-16x16-32931.png b/resources/countries_flags/png-16/bhutan-16x16-32931.png new file mode 100644 index 00000000..bd7b602f Binary files /dev/null and b/resources/countries_flags/png-16/bhutan-16x16-32931.png differ diff --git a/resources/countries_flags/png-16/bolivia-16x16-32945.png b/resources/countries_flags/png-16/bolivia-16x16-32945.png new file mode 100644 index 00000000..fb047403 Binary files /dev/null and b/resources/countries_flags/png-16/bolivia-16x16-32945.png differ diff --git a/resources/countries_flags/png-16/bonaire-16x16-32930.png b/resources/countries_flags/png-16/bonaire-16x16-32930.png new file mode 100644 index 00000000..aa98e77f Binary files /dev/null and b/resources/countries_flags/png-16/bonaire-16x16-32930.png differ diff --git a/resources/countries_flags/png-16/bosnia-16x16-32932.png b/resources/countries_flags/png-16/bosnia-16x16-32932.png new file mode 100644 index 00000000..52fd08ea Binary files /dev/null and b/resources/countries_flags/png-16/bosnia-16x16-32932.png differ diff --git a/resources/countries_flags/png-16/bostwana-16x16-32933.png b/resources/countries_flags/png-16/bostwana-16x16-32933.png new file mode 100644 index 00000000..b0a98d8a Binary files /dev/null and b/resources/countries_flags/png-16/bostwana-16x16-32933.png differ diff --git a/resources/countries_flags/png-16/bouvet-16x16-33156.png b/resources/countries_flags/png-16/bouvet-16x16-33156.png new file mode 100644 index 00000000..dc80eefd Binary files /dev/null and b/resources/countries_flags/png-16/bouvet-16x16-33156.png differ diff --git a/resources/countries_flags/png-16/brazil-16x16-32937.png b/resources/countries_flags/png-16/brazil-16x16-32937.png new file mode 100644 index 00000000..1e97fc89 Binary files /dev/null and b/resources/countries_flags/png-16/brazil-16x16-32937.png differ diff --git a/resources/countries_flags/png-16/british-16x16-33159.png b/resources/countries_flags/png-16/british-16x16-33159.png new file mode 100644 index 00000000..baf5df4d Binary files /dev/null and b/resources/countries_flags/png-16/british-16x16-33159.png differ diff --git a/resources/countries_flags/png-16/brunei-16x16-32944.png b/resources/countries_flags/png-16/brunei-16x16-32944.png new file mode 100644 index 00000000..2a14bfdd Binary files /dev/null and b/resources/countries_flags/png-16/brunei-16x16-32944.png differ diff --git a/resources/countries_flags/png-16/bulgaria-16x16-32973.png b/resources/countries_flags/png-16/bulgaria-16x16-32973.png new file mode 100644 index 00000000..66fce142 Binary files /dev/null and b/resources/countries_flags/png-16/bulgaria-16x16-32973.png differ diff --git a/resources/countries_flags/png-16/burkina-16x16-32934.png b/resources/countries_flags/png-16/burkina-16x16-32934.png new file mode 100644 index 00000000..76987a8f Binary files /dev/null and b/resources/countries_flags/png-16/burkina-16x16-32934.png differ diff --git a/resources/countries_flags/png-16/burundi-16x16-32935.png b/resources/countries_flags/png-16/burundi-16x16-32935.png new file mode 100644 index 00000000..3a222f96 Binary files /dev/null and b/resources/countries_flags/png-16/burundi-16x16-32935.png differ diff --git a/resources/countries_flags/png-16/cabo-16x16-32941.png b/resources/countries_flags/png-16/cabo-16x16-32941.png new file mode 100644 index 00000000..0bae93ba Binary files /dev/null and b/resources/countries_flags/png-16/cabo-16x16-32941.png differ diff --git a/resources/countries_flags/png-16/cambodia-16x16-32978.png b/resources/countries_flags/png-16/cambodia-16x16-32978.png new file mode 100644 index 00000000..7709078a Binary files /dev/null and b/resources/countries_flags/png-16/cambodia-16x16-32978.png differ diff --git a/resources/countries_flags/png-16/cameroon-16x16-32936.png b/resources/countries_flags/png-16/cameroon-16x16-32936.png new file mode 100644 index 00000000..a70e0119 Binary files /dev/null and b/resources/countries_flags/png-16/cameroon-16x16-32936.png differ diff --git a/resources/countries_flags/png-16/canada-16x16-32938.png b/resources/countries_flags/png-16/canada-16x16-32938.png new file mode 100644 index 00000000..fb52651e Binary files /dev/null and b/resources/countries_flags/png-16/canada-16x16-32938.png differ diff --git a/resources/countries_flags/png-16/cayman-16x16-32986.png b/resources/countries_flags/png-16/cayman-16x16-32986.png new file mode 100644 index 00000000..2d0b1fb4 Binary files /dev/null and b/resources/countries_flags/png-16/cayman-16x16-32986.png differ diff --git a/resources/countries_flags/png-16/central-16x16-32940.png b/resources/countries_flags/png-16/central-16x16-32940.png new file mode 100644 index 00000000..dffb9e89 Binary files /dev/null and b/resources/countries_flags/png-16/central-16x16-32940.png differ diff --git a/resources/countries_flags/png-16/chad-16x16-32985.png b/resources/countries_flags/png-16/chad-16x16-32985.png new file mode 100644 index 00000000..aecbd1ad Binary files /dev/null and b/resources/countries_flags/png-16/chad-16x16-32985.png differ diff --git a/resources/countries_flags/png-16/chile-16x16-32939.png b/resources/countries_flags/png-16/chile-16x16-32939.png new file mode 100644 index 00000000..120b548e Binary files /dev/null and b/resources/countries_flags/png-16/chile-16x16-32939.png differ diff --git a/resources/countries_flags/png-16/china-16x16-32942.png b/resources/countries_flags/png-16/china-16x16-32942.png new file mode 100644 index 00000000..c9e936c7 Binary files /dev/null and b/resources/countries_flags/png-16/china-16x16-32942.png differ diff --git a/resources/countries_flags/png-16/christmas-16x16-32943.png b/resources/countries_flags/png-16/christmas-16x16-32943.png new file mode 100644 index 00000000..d7359824 Binary files /dev/null and b/resources/countries_flags/png-16/christmas-16x16-32943.png differ diff --git a/resources/countries_flags/png-16/cocos-16x16-32947.png b/resources/countries_flags/png-16/cocos-16x16-32947.png new file mode 100644 index 00000000..4b7e56a2 Binary files /dev/null and b/resources/countries_flags/png-16/cocos-16x16-32947.png differ diff --git a/resources/countries_flags/png-16/colombia-16x16-32946.png b/resources/countries_flags/png-16/colombia-16x16-32946.png new file mode 100644 index 00000000..e3799d69 Binary files /dev/null and b/resources/countries_flags/png-16/colombia-16x16-32946.png differ diff --git a/resources/countries_flags/png-16/comoros-16x16-32981.png b/resources/countries_flags/png-16/comoros-16x16-32981.png new file mode 100644 index 00000000..9b733440 Binary files /dev/null and b/resources/countries_flags/png-16/comoros-16x16-32981.png differ diff --git a/resources/countries_flags/png-16/cook-16x16-32954.png b/resources/countries_flags/png-16/cook-16x16-32954.png new file mode 100644 index 00000000..643c13ae Binary files /dev/null and b/resources/countries_flags/png-16/cook-16x16-32954.png differ diff --git a/resources/countries_flags/png-16/costa-16x16-32948.png b/resources/countries_flags/png-16/costa-16x16-32948.png new file mode 100644 index 00000000..448491f8 Binary files /dev/null and b/resources/countries_flags/png-16/costa-16x16-32948.png differ diff --git a/resources/countries_flags/png-16/cote-16x16-32949.png b/resources/countries_flags/png-16/cote-16x16-32949.png new file mode 100644 index 00000000..320c5266 Binary files /dev/null and b/resources/countries_flags/png-16/cote-16x16-32949.png differ diff --git a/resources/countries_flags/png-16/croatia-16x16-32995.png b/resources/countries_flags/png-16/croatia-16x16-32995.png new file mode 100644 index 00000000..9c9ee214 Binary files /dev/null and b/resources/countries_flags/png-16/croatia-16x16-32995.png differ diff --git a/resources/countries_flags/png-16/cuba-16x16-32951.png b/resources/countries_flags/png-16/cuba-16x16-32951.png new file mode 100644 index 00000000..2cefcab8 Binary files /dev/null and b/resources/countries_flags/png-16/cuba-16x16-32951.png differ diff --git a/resources/countries_flags/png-16/curacao-16x16-32950.png b/resources/countries_flags/png-16/curacao-16x16-32950.png new file mode 100644 index 00000000..8c36b49f Binary files /dev/null and b/resources/countries_flags/png-16/curacao-16x16-32950.png differ diff --git a/resources/countries_flags/png-16/cyprus-16x16-32953.png b/resources/countries_flags/png-16/cyprus-16x16-32953.png new file mode 100644 index 00000000..1818de84 Binary files /dev/null and b/resources/countries_flags/png-16/cyprus-16x16-32953.png differ diff --git a/resources/countries_flags/png-16/czech-16x16-32956.png b/resources/countries_flags/png-16/czech-16x16-32956.png new file mode 100644 index 00000000..ec74c87f Binary files /dev/null and b/resources/countries_flags/png-16/czech-16x16-32956.png differ diff --git a/resources/countries_flags/png-16/democratic-16x16-32952.png b/resources/countries_flags/png-16/democratic-16x16-32952.png new file mode 100644 index 00000000..b8256c2e Binary files /dev/null and b/resources/countries_flags/png-16/democratic-16x16-32952.png differ diff --git a/resources/countries_flags/png-16/denmark-16x16-32955.png b/resources/countries_flags/png-16/denmark-16x16-32955.png new file mode 100644 index 00000000..c6f4305f Binary files /dev/null and b/resources/countries_flags/png-16/denmark-16x16-32955.png differ diff --git a/resources/countries_flags/png-16/djibouti-16x16-32957.png b/resources/countries_flags/png-16/djibouti-16x16-32957.png new file mode 100644 index 00000000..b2935746 Binary files /dev/null and b/resources/countries_flags/png-16/djibouti-16x16-32957.png differ diff --git a/resources/countries_flags/png-16/dominica-16x16-32960.png b/resources/countries_flags/png-16/dominica-16x16-32960.png new file mode 100644 index 00000000..98f88cf7 Binary files /dev/null and b/resources/countries_flags/png-16/dominica-16x16-32960.png differ diff --git a/resources/countries_flags/png-16/dominican-16x16-32993.png b/resources/countries_flags/png-16/dominican-16x16-32993.png new file mode 100644 index 00000000..df83cd0e Binary files /dev/null and b/resources/countries_flags/png-16/dominican-16x16-32993.png differ diff --git a/resources/countries_flags/png-16/ecuador-16x16-32962.png b/resources/countries_flags/png-16/ecuador-16x16-32962.png new file mode 100644 index 00000000..07e7b976 Binary files /dev/null and b/resources/countries_flags/png-16/ecuador-16x16-32962.png differ diff --git a/resources/countries_flags/png-16/egypt-16x16-32961.png b/resources/countries_flags/png-16/egypt-16x16-32961.png new file mode 100644 index 00000000..19da1e73 Binary files /dev/null and b/resources/countries_flags/png-16/egypt-16x16-32961.png differ diff --git a/resources/countries_flags/png-16/el-16x16-33011.png b/resources/countries_flags/png-16/el-16x16-33011.png new file mode 100644 index 00000000..f457a678 Binary files /dev/null and b/resources/countries_flags/png-16/el-16x16-33011.png differ diff --git a/resources/countries_flags/png-16/england-16x16-33157.png b/resources/countries_flags/png-16/england-16x16-33157.png new file mode 100644 index 00000000..c25685e9 Binary files /dev/null and b/resources/countries_flags/png-16/england-16x16-33157.png differ diff --git a/resources/countries_flags/png-16/equatorial-16x16-32971.png b/resources/countries_flags/png-16/equatorial-16x16-32971.png new file mode 100644 index 00000000..224c653c Binary files /dev/null and b/resources/countries_flags/png-16/equatorial-16x16-32971.png differ diff --git a/resources/countries_flags/png-16/eritrea-16x16-32964.png b/resources/countries_flags/png-16/eritrea-16x16-32964.png new file mode 100644 index 00000000..e2a36891 Binary files /dev/null and b/resources/countries_flags/png-16/eritrea-16x16-32964.png differ diff --git a/resources/countries_flags/png-16/estonia-16x16-32959.png b/resources/countries_flags/png-16/estonia-16x16-32959.png new file mode 100644 index 00000000..b647da1d Binary files /dev/null and b/resources/countries_flags/png-16/estonia-16x16-32959.png differ diff --git a/resources/countries_flags/png-16/ethiopia-16x16-32958.png b/resources/countries_flags/png-16/ethiopia-16x16-32958.png new file mode 100644 index 00000000..a249c366 Binary files /dev/null and b/resources/countries_flags/png-16/ethiopia-16x16-32958.png differ diff --git a/resources/countries_flags/png-16/falkland-16x16-32963.png b/resources/countries_flags/png-16/falkland-16x16-32963.png new file mode 100644 index 00000000..0b0614ff Binary files /dev/null and b/resources/countries_flags/png-16/falkland-16x16-32963.png differ diff --git a/resources/countries_flags/png-16/faroe-16x16-32965.png b/resources/countries_flags/png-16/faroe-16x16-32965.png new file mode 100644 index 00000000..b35d3490 Binary files /dev/null and b/resources/countries_flags/png-16/faroe-16x16-32965.png differ diff --git a/resources/countries_flags/png-16/federated-16x16-32969.png b/resources/countries_flags/png-16/federated-16x16-32969.png new file mode 100644 index 00000000..b8c77d85 Binary files /dev/null and b/resources/countries_flags/png-16/federated-16x16-32969.png differ diff --git a/resources/countries_flags/png-16/fiji-16x16-32970.png b/resources/countries_flags/png-16/fiji-16x16-32970.png new file mode 100644 index 00000000..755584a6 Binary files /dev/null and b/resources/countries_flags/png-16/fiji-16x16-32970.png differ diff --git a/resources/countries_flags/png-16/finland-16x16-32966.png b/resources/countries_flags/png-16/finland-16x16-32966.png new file mode 100644 index 00000000..beb9283b Binary files /dev/null and b/resources/countries_flags/png-16/finland-16x16-32966.png differ diff --git a/resources/countries_flags/png-16/former-16x16-33023.png b/resources/countries_flags/png-16/former-16x16-33023.png new file mode 100644 index 00000000..d1bffaed Binary files /dev/null and b/resources/countries_flags/png-16/former-16x16-33023.png differ diff --git a/resources/countries_flags/png-16/france-16x16-32967.png b/resources/countries_flags/png-16/france-16x16-32967.png new file mode 100644 index 00000000..72d22d08 Binary files /dev/null and b/resources/countries_flags/png-16/france-16x16-32967.png differ diff --git a/resources/countries_flags/png-16/french-16x16-32975.png b/resources/countries_flags/png-16/french-16x16-32975.png new file mode 100644 index 00000000..029a43a1 Binary files /dev/null and b/resources/countries_flags/png-16/french-16x16-32975.png differ diff --git a/resources/countries_flags/png-16/french-16x16-32977.png b/resources/countries_flags/png-16/french-16x16-32977.png new file mode 100644 index 00000000..fd1a6fd8 Binary files /dev/null and b/resources/countries_flags/png-16/french-16x16-32977.png differ diff --git a/resources/countries_flags/png-16/french-16x16-33024.png b/resources/countries_flags/png-16/french-16x16-33024.png new file mode 100644 index 00000000..2ad404c5 Binary files /dev/null and b/resources/countries_flags/png-16/french-16x16-33024.png differ diff --git a/resources/countries_flags/png-16/gabon-16x16-32968.png b/resources/countries_flags/png-16/gabon-16x16-32968.png new file mode 100644 index 00000000..1b7d8775 Binary files /dev/null and b/resources/countries_flags/png-16/gabon-16x16-32968.png differ diff --git a/resources/countries_flags/png-16/gambia-16x16-32976.png b/resources/countries_flags/png-16/gambia-16x16-32976.png new file mode 100644 index 00000000..d8de0e29 Binary files /dev/null and b/resources/countries_flags/png-16/gambia-16x16-32976.png differ diff --git a/resources/countries_flags/png-16/georgia-16x16-32979.png b/resources/countries_flags/png-16/georgia-16x16-32979.png new file mode 100644 index 00000000..4fcd5f58 Binary files /dev/null and b/resources/countries_flags/png-16/georgia-16x16-32979.png differ diff --git a/resources/countries_flags/png-16/germany-16x16-32989.png b/resources/countries_flags/png-16/germany-16x16-32989.png new file mode 100644 index 00000000..659bcece Binary files /dev/null and b/resources/countries_flags/png-16/germany-16x16-32989.png differ diff --git a/resources/countries_flags/png-16/ghana-16x16-32990.png b/resources/countries_flags/png-16/ghana-16x16-32990.png new file mode 100644 index 00000000..a3767248 Binary files /dev/null and b/resources/countries_flags/png-16/ghana-16x16-32990.png differ diff --git a/resources/countries_flags/png-16/gibraltar-16x16-32992.png b/resources/countries_flags/png-16/gibraltar-16x16-32992.png new file mode 100644 index 00000000..85de9c5f Binary files /dev/null and b/resources/countries_flags/png-16/gibraltar-16x16-32992.png differ diff --git a/resources/countries_flags/png-16/greece-16x16-32991.png b/resources/countries_flags/png-16/greece-16x16-32991.png new file mode 100644 index 00000000..f9b54e33 Binary files /dev/null and b/resources/countries_flags/png-16/greece-16x16-32991.png differ diff --git a/resources/countries_flags/png-16/greenland-16x16-33003.png b/resources/countries_flags/png-16/greenland-16x16-33003.png new file mode 100644 index 00000000..eef9ed57 Binary files /dev/null and b/resources/countries_flags/png-16/greenland-16x16-33003.png differ diff --git a/resources/countries_flags/png-16/grenada-16x16-33002.png b/resources/countries_flags/png-16/grenada-16x16-33002.png new file mode 100644 index 00000000..71045767 Binary files /dev/null and b/resources/countries_flags/png-16/grenada-16x16-33002.png differ diff --git a/resources/countries_flags/png-16/guadeloupe-16x16-32982.png b/resources/countries_flags/png-16/guadeloupe-16x16-32982.png new file mode 100644 index 00000000..f55d6ba9 Binary files /dev/null and b/resources/countries_flags/png-16/guadeloupe-16x16-32982.png differ diff --git a/resources/countries_flags/png-16/guam-16x16-33006.png b/resources/countries_flags/png-16/guam-16x16-33006.png new file mode 100644 index 00000000..085b65be Binary files /dev/null and b/resources/countries_flags/png-16/guam-16x16-33006.png differ diff --git a/resources/countries_flags/png-16/guatemala-16x16-33009.png b/resources/countries_flags/png-16/guatemala-16x16-33009.png new file mode 100644 index 00000000..bec8a11f Binary files /dev/null and b/resources/countries_flags/png-16/guatemala-16x16-33009.png differ diff --git a/resources/countries_flags/png-16/guernsey-16x16-32980.png b/resources/countries_flags/png-16/guernsey-16x16-32980.png new file mode 100644 index 00000000..55504d5c Binary files /dev/null and b/resources/countries_flags/png-16/guernsey-16x16-32980.png differ diff --git a/resources/countries_flags/png-16/guinea-16x16-32983.png b/resources/countries_flags/png-16/guinea-16x16-32983.png new file mode 100644 index 00000000..b51f5934 Binary files /dev/null and b/resources/countries_flags/png-16/guinea-16x16-32983.png differ diff --git a/resources/countries_flags/png-16/guinea-16x16-33008.png b/resources/countries_flags/png-16/guinea-16x16-33008.png new file mode 100644 index 00000000..e7fd48a3 Binary files /dev/null and b/resources/countries_flags/png-16/guinea-16x16-33008.png differ diff --git a/resources/countries_flags/png-16/guyana-16x16-33007.png b/resources/countries_flags/png-16/guyana-16x16-33007.png new file mode 100644 index 00000000..39b44d67 Binary files /dev/null and b/resources/countries_flags/png-16/guyana-16x16-33007.png differ diff --git a/resources/countries_flags/png-16/haiti-16x16-32984.png b/resources/countries_flags/png-16/haiti-16x16-32984.png new file mode 100644 index 00000000..77e71318 Binary files /dev/null and b/resources/countries_flags/png-16/haiti-16x16-32984.png differ diff --git a/resources/countries_flags/png-16/heard-16x16-33153.png b/resources/countries_flags/png-16/heard-16x16-33153.png new file mode 100644 index 00000000..ce0b4d7f Binary files /dev/null and b/resources/countries_flags/png-16/heard-16x16-33153.png differ diff --git a/resources/countries_flags/png-16/holy-16x16-33136.png b/resources/countries_flags/png-16/holy-16x16-33136.png new file mode 100644 index 00000000..47a3d223 Binary files /dev/null and b/resources/countries_flags/png-16/holy-16x16-33136.png differ diff --git a/resources/countries_flags/png-16/honduras-16x16-33020.png b/resources/countries_flags/png-16/honduras-16x16-33020.png new file mode 100644 index 00000000..7212eaef Binary files /dev/null and b/resources/countries_flags/png-16/honduras-16x16-33020.png differ diff --git a/resources/countries_flags/png-16/hong-16x16-32987.png b/resources/countries_flags/png-16/hong-16x16-32987.png new file mode 100644 index 00000000..501ae675 Binary files /dev/null and b/resources/countries_flags/png-16/hong-16x16-32987.png differ diff --git a/resources/countries_flags/png-16/hungary-16x16-33019.png b/resources/countries_flags/png-16/hungary-16x16-33019.png new file mode 100644 index 00000000..c43197da Binary files /dev/null and b/resources/countries_flags/png-16/hungary-16x16-33019.png differ diff --git a/resources/countries_flags/png-16/iceland-16x16-33152.png b/resources/countries_flags/png-16/iceland-16x16-33152.png new file mode 100644 index 00000000..a8a7c3cd Binary files /dev/null and b/resources/countries_flags/png-16/iceland-16x16-33152.png differ diff --git a/resources/countries_flags/png-16/india-16x16-32988.png b/resources/countries_flags/png-16/india-16x16-32988.png new file mode 100644 index 00000000..f5daf636 Binary files /dev/null and b/resources/countries_flags/png-16/india-16x16-32988.png differ diff --git a/resources/countries_flags/png-16/indonesia-16x16-32994.png b/resources/countries_flags/png-16/indonesia-16x16-32994.png new file mode 100644 index 00000000..1c59a1d3 Binary files /dev/null and b/resources/countries_flags/png-16/indonesia-16x16-32994.png differ diff --git a/resources/countries_flags/png-16/iran-16x16-33022.png b/resources/countries_flags/png-16/iran-16x16-33022.png new file mode 100644 index 00000000..eb60830b Binary files /dev/null and b/resources/countries_flags/png-16/iran-16x16-33022.png differ diff --git a/resources/countries_flags/png-16/iraq-16x16-33017.png b/resources/countries_flags/png-16/iraq-16x16-33017.png new file mode 100644 index 00000000..a3d5934b Binary files /dev/null and b/resources/countries_flags/png-16/iraq-16x16-33017.png differ diff --git a/resources/countries_flags/png-16/ireland-16x16-32996.png b/resources/countries_flags/png-16/ireland-16x16-32996.png new file mode 100644 index 00000000..25a4d688 Binary files /dev/null and b/resources/countries_flags/png-16/ireland-16x16-32996.png differ diff --git a/resources/countries_flags/png-16/isle-16x16-32998.png b/resources/countries_flags/png-16/isle-16x16-32998.png new file mode 100644 index 00000000..2685263f Binary files /dev/null and b/resources/countries_flags/png-16/isle-16x16-32998.png differ diff --git a/resources/countries_flags/png-16/israel-16x16-32997.png b/resources/countries_flags/png-16/israel-16x16-32997.png new file mode 100644 index 00000000..5b29daf1 Binary files /dev/null and b/resources/countries_flags/png-16/israel-16x16-32997.png differ diff --git a/resources/countries_flags/png-16/italy-16x16-32999.png b/resources/countries_flags/png-16/italy-16x16-32999.png new file mode 100644 index 00000000..4ad7da3a Binary files /dev/null and b/resources/countries_flags/png-16/italy-16x16-32999.png differ diff --git a/resources/countries_flags/png-16/itcairn-16x16-33034.png b/resources/countries_flags/png-16/itcairn-16x16-33034.png new file mode 100644 index 00000000..c2eadb7c Binary files /dev/null and b/resources/countries_flags/png-16/itcairn-16x16-33034.png differ diff --git a/resources/countries_flags/png-16/jamaica-16x16-33000.png b/resources/countries_flags/png-16/jamaica-16x16-33000.png new file mode 100644 index 00000000..9f6a1e63 Binary files /dev/null and b/resources/countries_flags/png-16/jamaica-16x16-33000.png differ diff --git a/resources/countries_flags/png-16/japan-16x16-33001.png b/resources/countries_flags/png-16/japan-16x16-33001.png new file mode 100644 index 00000000..630cc6da Binary files /dev/null and b/resources/countries_flags/png-16/japan-16x16-33001.png differ diff --git a/resources/countries_flags/png-16/jersey-16x16-33004.png b/resources/countries_flags/png-16/jersey-16x16-33004.png new file mode 100644 index 00000000..21806854 Binary files /dev/null and b/resources/countries_flags/png-16/jersey-16x16-33004.png differ diff --git a/resources/countries_flags/png-16/jordan-16x16-33005.png b/resources/countries_flags/png-16/jordan-16x16-33005.png new file mode 100644 index 00000000..2b7193af Binary files /dev/null and b/resources/countries_flags/png-16/jordan-16x16-33005.png differ diff --git a/resources/countries_flags/png-16/kazakhstan-16x16-33021.png b/resources/countries_flags/png-16/kazakhstan-16x16-33021.png new file mode 100644 index 00000000..a19d3313 Binary files /dev/null and b/resources/countries_flags/png-16/kazakhstan-16x16-33021.png differ diff --git a/resources/countries_flags/png-16/kenya-16x16-33010.png b/resources/countries_flags/png-16/kenya-16x16-33010.png new file mode 100644 index 00000000..7d08ac4a Binary files /dev/null and b/resources/countries_flags/png-16/kenya-16x16-33010.png differ diff --git a/resources/countries_flags/png-16/kiribati-16x16-33012.png b/resources/countries_flags/png-16/kiribati-16x16-33012.png new file mode 100644 index 00000000..f36f36a6 Binary files /dev/null and b/resources/countries_flags/png-16/kiribati-16x16-33012.png differ diff --git a/resources/countries_flags/png-16/kuwait-16x16-33013.png b/resources/countries_flags/png-16/kuwait-16x16-33013.png new file mode 100644 index 00000000..8d365679 Binary files /dev/null and b/resources/countries_flags/png-16/kuwait-16x16-33013.png differ diff --git a/resources/countries_flags/png-16/kyrgyzstan-16x16-33014.png b/resources/countries_flags/png-16/kyrgyzstan-16x16-33014.png new file mode 100644 index 00000000..8f4c7a8c Binary files /dev/null and b/resources/countries_flags/png-16/kyrgyzstan-16x16-33014.png differ diff --git a/resources/countries_flags/png-16/laos-16x16-33018.png b/resources/countries_flags/png-16/laos-16x16-33018.png new file mode 100644 index 00000000..0da072aa Binary files /dev/null and b/resources/countries_flags/png-16/laos-16x16-33018.png differ diff --git a/resources/countries_flags/png-16/latvia-16x16-33031.png b/resources/countries_flags/png-16/latvia-16x16-33031.png new file mode 100644 index 00000000..c96aaadd Binary files /dev/null and b/resources/countries_flags/png-16/latvia-16x16-33031.png differ diff --git a/resources/countries_flags/png-16/lebanon-16x16-33015.png b/resources/countries_flags/png-16/lebanon-16x16-33015.png new file mode 100644 index 00000000..ea2b0f6e Binary files /dev/null and b/resources/countries_flags/png-16/lebanon-16x16-33015.png differ diff --git a/resources/countries_flags/png-16/lesotho-16x16-33029.png b/resources/countries_flags/png-16/lesotho-16x16-33029.png new file mode 100644 index 00000000..478e011a Binary files /dev/null and b/resources/countries_flags/png-16/lesotho-16x16-33029.png differ diff --git a/resources/countries_flags/png-16/liberia-16x16-33032.png b/resources/countries_flags/png-16/liberia-16x16-33032.png new file mode 100644 index 00000000..5101396a Binary files /dev/null and b/resources/countries_flags/png-16/liberia-16x16-33032.png differ diff --git a/resources/countries_flags/png-16/libya-16x16-33026.png b/resources/countries_flags/png-16/libya-16x16-33026.png new file mode 100644 index 00000000..5fff5486 Binary files /dev/null and b/resources/countries_flags/png-16/libya-16x16-33026.png differ diff --git a/resources/countries_flags/png-16/liechtenstein-16x16-33016.png b/resources/countries_flags/png-16/liechtenstein-16x16-33016.png new file mode 100644 index 00000000..ecdc0509 Binary files /dev/null and b/resources/countries_flags/png-16/liechtenstein-16x16-33016.png differ diff --git a/resources/countries_flags/png-16/lithuania-16x16-33043.png b/resources/countries_flags/png-16/lithuania-16x16-33043.png new file mode 100644 index 00000000..ecf305a8 Binary files /dev/null and b/resources/countries_flags/png-16/lithuania-16x16-33043.png differ diff --git a/resources/countries_flags/png-16/luxembourg-16x16-33041.png b/resources/countries_flags/png-16/luxembourg-16x16-33041.png new file mode 100644 index 00000000..0c7ef185 Binary files /dev/null and b/resources/countries_flags/png-16/luxembourg-16x16-33041.png differ diff --git a/resources/countries_flags/png-16/madagascar-16x16-33042.png b/resources/countries_flags/png-16/madagascar-16x16-33042.png new file mode 100644 index 00000000..fa83a097 Binary files /dev/null and b/resources/countries_flags/png-16/madagascar-16x16-33042.png differ diff --git a/resources/countries_flags/png-16/malawi-16x16-33116.png b/resources/countries_flags/png-16/malawi-16x16-33116.png new file mode 100644 index 00000000..218d464a Binary files /dev/null and b/resources/countries_flags/png-16/malawi-16x16-33116.png differ diff --git a/resources/countries_flags/png-16/malaysia-16x16-33134.png b/resources/countries_flags/png-16/malaysia-16x16-33134.png new file mode 100644 index 00000000..68dae6c1 Binary files /dev/null and b/resources/countries_flags/png-16/malaysia-16x16-33134.png differ diff --git a/resources/countries_flags/png-16/maldives-16x16-33122.png b/resources/countries_flags/png-16/maldives-16x16-33122.png new file mode 100644 index 00000000..97bffe94 Binary files /dev/null and b/resources/countries_flags/png-16/maldives-16x16-33122.png differ diff --git a/resources/countries_flags/png-16/mali-16x16-33025.png b/resources/countries_flags/png-16/mali-16x16-33025.png new file mode 100644 index 00000000..2a4bcce1 Binary files /dev/null and b/resources/countries_flags/png-16/mali-16x16-33025.png differ diff --git a/resources/countries_flags/png-16/malta-16x16-33120.png b/resources/countries_flags/png-16/malta-16x16-33120.png new file mode 100644 index 00000000..a2b2ec5e Binary files /dev/null and b/resources/countries_flags/png-16/malta-16x16-33120.png differ diff --git a/resources/countries_flags/png-16/marshall-16x16-33054.png b/resources/countries_flags/png-16/marshall-16x16-33054.png new file mode 100644 index 00000000..4662899f Binary files /dev/null and b/resources/countries_flags/png-16/marshall-16x16-33054.png differ diff --git a/resources/countries_flags/png-16/martinique-16x16-33119.png b/resources/countries_flags/png-16/martinique-16x16-33119.png new file mode 100644 index 00000000..06a8de47 Binary files /dev/null and b/resources/countries_flags/png-16/martinique-16x16-33119.png differ diff --git a/resources/countries_flags/png-16/mauritania-16x16-33125.png b/resources/countries_flags/png-16/mauritania-16x16-33125.png new file mode 100644 index 00000000..4de16bcb Binary files /dev/null and b/resources/countries_flags/png-16/mauritania-16x16-33125.png differ diff --git a/resources/countries_flags/png-16/mauritius-16x16-33121.png b/resources/countries_flags/png-16/mauritius-16x16-33121.png new file mode 100644 index 00000000..a379d6ad Binary files /dev/null and b/resources/countries_flags/png-16/mauritius-16x16-33121.png differ diff --git a/resources/countries_flags/png-16/mayotte-16x16-33123.png b/resources/countries_flags/png-16/mayotte-16x16-33123.png new file mode 100644 index 00000000..5b62fd87 Binary files /dev/null and b/resources/countries_flags/png-16/mayotte-16x16-33123.png differ diff --git a/resources/countries_flags/png-16/mexico-16x16-33133.png b/resources/countries_flags/png-16/mexico-16x16-33133.png new file mode 100644 index 00000000..ad16b086 Binary files /dev/null and b/resources/countries_flags/png-16/mexico-16x16-33133.png differ diff --git a/resources/countries_flags/png-16/mn-16x16-33117.png b/resources/countries_flags/png-16/mn-16x16-33117.png new file mode 100644 index 00000000..4a4253dc Binary files /dev/null and b/resources/countries_flags/png-16/mn-16x16-33117.png differ diff --git a/resources/countries_flags/png-16/mo-16x16-33127.png b/resources/countries_flags/png-16/mo-16x16-33127.png new file mode 100644 index 00000000..0cb9cd55 Binary files /dev/null and b/resources/countries_flags/png-16/mo-16x16-33127.png differ diff --git a/resources/countries_flags/png-16/moldova-16x16-33055.png b/resources/countries_flags/png-16/moldova-16x16-33055.png new file mode 100644 index 00000000..2a96494b Binary files /dev/null and b/resources/countries_flags/png-16/moldova-16x16-33055.png differ diff --git a/resources/countries_flags/png-16/monaco-16x16-33053.png b/resources/countries_flags/png-16/monaco-16x16-33053.png new file mode 100644 index 00000000..838aa74b Binary files /dev/null and b/resources/countries_flags/png-16/monaco-16x16-33053.png differ diff --git a/resources/countries_flags/png-16/montenegro-16x16-33056.png b/resources/countries_flags/png-16/montenegro-16x16-33056.png new file mode 100644 index 00000000..41018682 Binary files /dev/null and b/resources/countries_flags/png-16/montenegro-16x16-33056.png differ diff --git a/resources/countries_flags/png-16/montserrat-16x16-33126.png b/resources/countries_flags/png-16/montserrat-16x16-33126.png new file mode 100644 index 00000000..41fad778 Binary files /dev/null and b/resources/countries_flags/png-16/montserrat-16x16-33126.png differ diff --git a/resources/countries_flags/png-16/morocco-16x16-33027.png b/resources/countries_flags/png-16/morocco-16x16-33027.png new file mode 100644 index 00000000..5384c54c Binary files /dev/null and b/resources/countries_flags/png-16/morocco-16x16-33027.png differ diff --git a/resources/countries_flags/png-16/mozambique-16x16-33033.png b/resources/countries_flags/png-16/mozambique-16x16-33033.png new file mode 100644 index 00000000..784cccda Binary files /dev/null and b/resources/countries_flags/png-16/mozambique-16x16-33033.png differ diff --git a/resources/countries_flags/png-16/myanmar-16x16-33118.png b/resources/countries_flags/png-16/myanmar-16x16-33118.png new file mode 100644 index 00000000..b038cafb Binary files /dev/null and b/resources/countries_flags/png-16/myanmar-16x16-33118.png differ diff --git a/resources/countries_flags/png-16/namibia-16x16-33132.png b/resources/countries_flags/png-16/namibia-16x16-33132.png new file mode 100644 index 00000000..68adcdd3 Binary files /dev/null and b/resources/countries_flags/png-16/namibia-16x16-33132.png differ diff --git a/resources/countries_flags/png-16/nauru-16x16-33030.png b/resources/countries_flags/png-16/nauru-16x16-33030.png new file mode 100644 index 00000000..2d9ebee7 Binary files /dev/null and b/resources/countries_flags/png-16/nauru-16x16-33030.png differ diff --git a/resources/countries_flags/png-16/nepal-16x16-33028.png b/resources/countries_flags/png-16/nepal-16x16-33028.png new file mode 100644 index 00000000..5b9a2923 Binary files /dev/null and b/resources/countries_flags/png-16/nepal-16x16-33028.png differ diff --git a/resources/countries_flags/png-16/netherlands-16x16-33035.png b/resources/countries_flags/png-16/netherlands-16x16-33035.png new file mode 100644 index 00000000..1d56654c Binary files /dev/null and b/resources/countries_flags/png-16/netherlands-16x16-33035.png differ diff --git a/resources/countries_flags/png-16/new-16x16-33036.png b/resources/countries_flags/png-16/new-16x16-33036.png new file mode 100644 index 00000000..2be1690c Binary files /dev/null and b/resources/countries_flags/png-16/new-16x16-33036.png differ diff --git a/resources/countries_flags/png-16/new-16x16-33065.png b/resources/countries_flags/png-16/new-16x16-33065.png new file mode 100644 index 00000000..a82137b0 Binary files /dev/null and b/resources/countries_flags/png-16/new-16x16-33065.png differ diff --git a/resources/countries_flags/png-16/nicaragua-16x16-33037.png b/resources/countries_flags/png-16/nicaragua-16x16-33037.png new file mode 100644 index 00000000..52b02bca Binary files /dev/null and b/resources/countries_flags/png-16/nicaragua-16x16-33037.png differ diff --git a/resources/countries_flags/png-16/niger-16x16-33038.png b/resources/countries_flags/png-16/niger-16x16-33038.png new file mode 100644 index 00000000..ff071f82 Binary files /dev/null and b/resources/countries_flags/png-16/niger-16x16-33038.png differ diff --git a/resources/countries_flags/png-16/nigeria-16x16-33039.png b/resources/countries_flags/png-16/nigeria-16x16-33039.png new file mode 100644 index 00000000..42f4ffd2 Binary files /dev/null and b/resources/countries_flags/png-16/nigeria-16x16-33039.png differ diff --git a/resources/countries_flags/png-16/niue-16x16-33040.png b/resources/countries_flags/png-16/niue-16x16-33040.png new file mode 100644 index 00000000..2af5c06f Binary files /dev/null and b/resources/countries_flags/png-16/niue-16x16-33040.png differ diff --git a/resources/countries_flags/png-16/norfolk-16x16-33044.png b/resources/countries_flags/png-16/norfolk-16x16-33044.png new file mode 100644 index 00000000..dba57544 Binary files /dev/null and b/resources/countries_flags/png-16/norfolk-16x16-33044.png differ diff --git a/resources/countries_flags/png-16/north-16x16-33045.png b/resources/countries_flags/png-16/north-16x16-33045.png new file mode 100644 index 00000000..09cb0691 Binary files /dev/null and b/resources/countries_flags/png-16/north-16x16-33045.png differ diff --git a/resources/countries_flags/png-16/northern-16x16-33128.png b/resources/countries_flags/png-16/northern-16x16-33128.png new file mode 100644 index 00000000..aee9c63d Binary files /dev/null and b/resources/countries_flags/png-16/northern-16x16-33128.png differ diff --git a/resources/countries_flags/png-16/northern-16x16-33160.png b/resources/countries_flags/png-16/northern-16x16-33160.png new file mode 100644 index 00000000..e371be99 Binary files /dev/null and b/resources/countries_flags/png-16/northern-16x16-33160.png differ diff --git a/resources/countries_flags/png-16/norway-16x16-33155.png b/resources/countries_flags/png-16/norway-16x16-33155.png new file mode 100644 index 00000000..4aea2788 Binary files /dev/null and b/resources/countries_flags/png-16/norway-16x16-33155.png differ diff --git a/resources/countries_flags/png-16/oman-16x16-33046.png b/resources/countries_flags/png-16/oman-16x16-33046.png new file mode 100644 index 00000000..bb2289a3 Binary files /dev/null and b/resources/countries_flags/png-16/oman-16x16-33046.png differ diff --git a/resources/countries_flags/png-16/pakistan-16x16-33047.png b/resources/countries_flags/png-16/pakistan-16x16-33047.png new file mode 100644 index 00000000..ab728c29 Binary files /dev/null and b/resources/countries_flags/png-16/pakistan-16x16-33047.png differ diff --git a/resources/countries_flags/png-16/palau-16x16-33048.png b/resources/countries_flags/png-16/palau-16x16-33048.png new file mode 100644 index 00000000..19f07345 Binary files /dev/null and b/resources/countries_flags/png-16/palau-16x16-33048.png differ diff --git a/resources/countries_flags/png-16/panama-16x16-33049.png b/resources/countries_flags/png-16/panama-16x16-33049.png new file mode 100644 index 00000000..64e5e03c Binary files /dev/null and b/resources/countries_flags/png-16/panama-16x16-33049.png differ diff --git a/resources/countries_flags/png-16/papua-16x16-33050.png b/resources/countries_flags/png-16/papua-16x16-33050.png new file mode 100644 index 00000000..0295c49e Binary files /dev/null and b/resources/countries_flags/png-16/papua-16x16-33050.png differ diff --git a/resources/countries_flags/png-16/paraguay-16x16-33066.png b/resources/countries_flags/png-16/paraguay-16x16-33066.png new file mode 100644 index 00000000..f1a5ae02 Binary files /dev/null and b/resources/countries_flags/png-16/paraguay-16x16-33066.png differ diff --git a/resources/countries_flags/png-16/peru-16x16-33051.png b/resources/countries_flags/png-16/peru-16x16-33051.png new file mode 100644 index 00000000..f31a03e3 Binary files /dev/null and b/resources/countries_flags/png-16/peru-16x16-33051.png differ diff --git a/resources/countries_flags/png-16/philippines-16x16-33052.png b/resources/countries_flags/png-16/philippines-16x16-33052.png new file mode 100644 index 00000000..1d7a1680 Binary files /dev/null and b/resources/countries_flags/png-16/philippines-16x16-33052.png differ diff --git a/resources/countries_flags/png-16/poland-16x16-33057.png b/resources/countries_flags/png-16/poland-16x16-33057.png new file mode 100644 index 00000000..2423dae5 Binary files /dev/null and b/resources/countries_flags/png-16/poland-16x16-33057.png differ diff --git a/resources/countries_flags/png-16/portugal-16x16-33058.png b/resources/countries_flags/png-16/portugal-16x16-33058.png new file mode 100644 index 00000000..438e43db Binary files /dev/null and b/resources/countries_flags/png-16/portugal-16x16-33058.png differ diff --git a/resources/countries_flags/png-16/puerto-16x16-33059.png b/resources/countries_flags/png-16/puerto-16x16-33059.png new file mode 100644 index 00000000..e53e1622 Binary files /dev/null and b/resources/countries_flags/png-16/puerto-16x16-33059.png differ diff --git a/resources/countries_flags/png-16/qatar-16x16-33060.png b/resources/countries_flags/png-16/qatar-16x16-33060.png new file mode 100644 index 00000000..be8299a2 Binary files /dev/null and b/resources/countries_flags/png-16/qatar-16x16-33060.png differ diff --git a/resources/countries_flags/png-16/question.png b/resources/countries_flags/png-16/question.png new file mode 100644 index 00000000..447f886c Binary files /dev/null and b/resources/countries_flags/png-16/question.png differ diff --git a/resources/countries_flags/png-16/republic-16x16-33061.png b/resources/countries_flags/png-16/republic-16x16-33061.png new file mode 100644 index 00000000..a2b01b24 Binary files /dev/null and b/resources/countries_flags/png-16/republic-16x16-33061.png differ diff --git a/resources/countries_flags/png-16/romania-16x16-33063.png b/resources/countries_flags/png-16/romania-16x16-33063.png new file mode 100644 index 00000000..72738625 Binary files /dev/null and b/resources/countries_flags/png-16/romania-16x16-33063.png differ diff --git a/resources/countries_flags/png-16/runion-16x16-33062.png b/resources/countries_flags/png-16/runion-16x16-33062.png new file mode 100644 index 00000000..272975ec Binary files /dev/null and b/resources/countries_flags/png-16/runion-16x16-33062.png differ diff --git a/resources/countries_flags/png-16/russia-16x16-33064.png b/resources/countries_flags/png-16/russia-16x16-33064.png new file mode 100644 index 00000000..db293674 Binary files /dev/null and b/resources/countries_flags/png-16/russia-16x16-33064.png differ diff --git a/resources/countries_flags/png-16/rwanda-16x16-33067.png b/resources/countries_flags/png-16/rwanda-16x16-33067.png new file mode 100644 index 00000000..2bce274f Binary files /dev/null and b/resources/countries_flags/png-16/rwanda-16x16-33067.png differ diff --git a/resources/countries_flags/png-16/saint-16x16-33068.png b/resources/countries_flags/png-16/saint-16x16-33068.png new file mode 100644 index 00000000..c9264b34 Binary files /dev/null and b/resources/countries_flags/png-16/saint-16x16-33068.png differ diff --git a/resources/countries_flags/png-16/saint-16x16-33069.png b/resources/countries_flags/png-16/saint-16x16-33069.png new file mode 100644 index 00000000..261f8d74 Binary files /dev/null and b/resources/countries_flags/png-16/saint-16x16-33069.png differ diff --git a/resources/countries_flags/png-16/saint-16x16-33070.png b/resources/countries_flags/png-16/saint-16x16-33070.png new file mode 100644 index 00000000..79d3e28c Binary files /dev/null and b/resources/countries_flags/png-16/saint-16x16-33070.png differ diff --git a/resources/countries_flags/png-16/saint-16x16-33071.png b/resources/countries_flags/png-16/saint-16x16-33071.png new file mode 100644 index 00000000..3a3270cf Binary files /dev/null and b/resources/countries_flags/png-16/saint-16x16-33071.png differ diff --git a/resources/countries_flags/png-16/saint-16x16-33072.png b/resources/countries_flags/png-16/saint-16x16-33072.png new file mode 100644 index 00000000..cfd08515 Binary files /dev/null and b/resources/countries_flags/png-16/saint-16x16-33072.png differ diff --git a/resources/countries_flags/png-16/saint-16x16-33073.png b/resources/countries_flags/png-16/saint-16x16-33073.png new file mode 100644 index 00000000..6af1be96 Binary files /dev/null and b/resources/countries_flags/png-16/saint-16x16-33073.png differ diff --git a/resources/countries_flags/png-16/saint-16x16-33131.png b/resources/countries_flags/png-16/saint-16x16-33131.png new file mode 100644 index 00000000..c788eb55 Binary files /dev/null and b/resources/countries_flags/png-16/saint-16x16-33131.png differ diff --git a/resources/countries_flags/png-16/samoa-16x16-33124.png b/resources/countries_flags/png-16/samoa-16x16-33124.png new file mode 100644 index 00000000..c2ea13ac Binary files /dev/null and b/resources/countries_flags/png-16/samoa-16x16-33124.png differ diff --git a/resources/countries_flags/png-16/san-16x16-33074.png b/resources/countries_flags/png-16/san-16x16-33074.png new file mode 100644 index 00000000..e5cac663 Binary files /dev/null and b/resources/countries_flags/png-16/san-16x16-33074.png differ diff --git a/resources/countries_flags/png-16/sao-16x16-33075.png b/resources/countries_flags/png-16/sao-16x16-33075.png new file mode 100644 index 00000000..333f81a6 Binary files /dev/null and b/resources/countries_flags/png-16/sao-16x16-33075.png differ diff --git a/resources/countries_flags/png-16/saudi-16x16-33076.png b/resources/countries_flags/png-16/saudi-16x16-33076.png new file mode 100644 index 00000000..02f30005 Binary files /dev/null and b/resources/countries_flags/png-16/saudi-16x16-33076.png differ diff --git a/resources/countries_flags/png-16/scotland-16x16-33154.png b/resources/countries_flags/png-16/scotland-16x16-33154.png new file mode 100644 index 00000000..ba0fc689 Binary files /dev/null and b/resources/countries_flags/png-16/scotland-16x16-33154.png differ diff --git a/resources/countries_flags/png-16/senegal-16x16-33077.png b/resources/countries_flags/png-16/senegal-16x16-33077.png new file mode 100644 index 00000000..7b9d8b21 Binary files /dev/null and b/resources/countries_flags/png-16/senegal-16x16-33077.png differ diff --git a/resources/countries_flags/png-16/serbia-16x16-33099.png b/resources/countries_flags/png-16/serbia-16x16-33099.png new file mode 100644 index 00000000..c6e6a4b8 Binary files /dev/null and b/resources/countries_flags/png-16/serbia-16x16-33099.png differ diff --git a/resources/countries_flags/png-16/seychelles-16x16-33078.png b/resources/countries_flags/png-16/seychelles-16x16-33078.png new file mode 100644 index 00000000..a3d2f120 Binary files /dev/null and b/resources/countries_flags/png-16/seychelles-16x16-33078.png differ diff --git a/resources/countries_flags/png-16/sierra-16x16-33079.png b/resources/countries_flags/png-16/sierra-16x16-33079.png new file mode 100644 index 00000000..3d0fc691 Binary files /dev/null and b/resources/countries_flags/png-16/sierra-16x16-33079.png differ diff --git a/resources/countries_flags/png-16/singapore-16x16-33080.png b/resources/countries_flags/png-16/singapore-16x16-33080.png new file mode 100644 index 00000000..6eb95a6a Binary files /dev/null and b/resources/countries_flags/png-16/singapore-16x16-33080.png differ diff --git a/resources/countries_flags/png-16/sint-16x16-33081.png b/resources/countries_flags/png-16/sint-16x16-33081.png new file mode 100644 index 00000000..62185fe2 Binary files /dev/null and b/resources/countries_flags/png-16/sint-16x16-33081.png differ diff --git a/resources/countries_flags/png-16/slovakia-16x16-33082.png b/resources/countries_flags/png-16/slovakia-16x16-33082.png new file mode 100644 index 00000000..a53f4b6a Binary files /dev/null and b/resources/countries_flags/png-16/slovakia-16x16-33082.png differ diff --git a/resources/countries_flags/png-16/slovenia-16x16-33084.png b/resources/countries_flags/png-16/slovenia-16x16-33084.png new file mode 100644 index 00000000..32393401 Binary files /dev/null and b/resources/countries_flags/png-16/slovenia-16x16-33084.png differ diff --git a/resources/countries_flags/png-16/solomon-16x16-33083.png b/resources/countries_flags/png-16/solomon-16x16-33083.png new file mode 100644 index 00000000..e755eeb7 Binary files /dev/null and b/resources/countries_flags/png-16/solomon-16x16-33083.png differ diff --git a/resources/countries_flags/png-16/somalia-16x16-33085.png b/resources/countries_flags/png-16/somalia-16x16-33085.png new file mode 100644 index 00000000..bf4e4806 Binary files /dev/null and b/resources/countries_flags/png-16/somalia-16x16-33085.png differ diff --git a/resources/countries_flags/png-16/south-16x16-33086.png b/resources/countries_flags/png-16/south-16x16-33086.png new file mode 100644 index 00000000..e7cca291 Binary files /dev/null and b/resources/countries_flags/png-16/south-16x16-33086.png differ diff --git a/resources/countries_flags/png-16/south-16x16-33087.png b/resources/countries_flags/png-16/south-16x16-33087.png new file mode 100644 index 00000000..d453848a Binary files /dev/null and b/resources/countries_flags/png-16/south-16x16-33087.png differ diff --git a/resources/countries_flags/png-16/south-16x16-33088.png b/resources/countries_flags/png-16/south-16x16-33088.png new file mode 100644 index 00000000..b498882a Binary files /dev/null and b/resources/countries_flags/png-16/south-16x16-33088.png differ diff --git a/resources/countries_flags/png-16/south-16x16-33130.png b/resources/countries_flags/png-16/south-16x16-33130.png new file mode 100644 index 00000000..2e9c9d12 Binary files /dev/null and b/resources/countries_flags/png-16/south-16x16-33130.png differ diff --git a/resources/countries_flags/png-16/spain-16x16-33105.png b/resources/countries_flags/png-16/spain-16x16-33105.png new file mode 100644 index 00000000..4b3d88f1 Binary files /dev/null and b/resources/countries_flags/png-16/spain-16x16-33105.png differ diff --git a/resources/countries_flags/png-16/sri-16x16-33091.png b/resources/countries_flags/png-16/sri-16x16-33091.png new file mode 100644 index 00000000..9554fe8d Binary files /dev/null and b/resources/countries_flags/png-16/sri-16x16-33091.png differ diff --git a/resources/countries_flags/png-16/state-16x16-33089.png b/resources/countries_flags/png-16/state-16x16-33089.png new file mode 100644 index 00000000..e28a4409 Binary files /dev/null and b/resources/countries_flags/png-16/state-16x16-33089.png differ diff --git a/resources/countries_flags/png-16/sudan-16x16-33090.png b/resources/countries_flags/png-16/sudan-16x16-33090.png new file mode 100644 index 00000000..64598a26 Binary files /dev/null and b/resources/countries_flags/png-16/sudan-16x16-33090.png differ diff --git a/resources/countries_flags/png-16/suriname-16x16-33092.png b/resources/countries_flags/png-16/suriname-16x16-33092.png new file mode 100644 index 00000000..0b5716c2 Binary files /dev/null and b/resources/countries_flags/png-16/suriname-16x16-33092.png differ diff --git a/resources/countries_flags/png-16/svalbard-16x16-33093.png b/resources/countries_flags/png-16/svalbard-16x16-33093.png new file mode 100644 index 00000000..02b70a3b Binary files /dev/null and b/resources/countries_flags/png-16/svalbard-16x16-33093.png differ diff --git a/resources/countries_flags/png-16/swaziland-16x16-33094.png b/resources/countries_flags/png-16/swaziland-16x16-33094.png new file mode 100644 index 00000000..05884022 Binary files /dev/null and b/resources/countries_flags/png-16/swaziland-16x16-33094.png differ diff --git a/resources/countries_flags/png-16/sweden-16x16-33096.png b/resources/countries_flags/png-16/sweden-16x16-33096.png new file mode 100644 index 00000000..d6abe916 Binary files /dev/null and b/resources/countries_flags/png-16/sweden-16x16-33096.png differ diff --git a/resources/countries_flags/png-16/switzerland-16x16-33095.png b/resources/countries_flags/png-16/switzerland-16x16-33095.png new file mode 100644 index 00000000..7799ae66 Binary files /dev/null and b/resources/countries_flags/png-16/switzerland-16x16-33095.png differ diff --git a/resources/countries_flags/png-16/syrian-16x16-33097.png b/resources/countries_flags/png-16/syrian-16x16-33097.png new file mode 100644 index 00000000..c46475fd Binary files /dev/null and b/resources/countries_flags/png-16/syrian-16x16-33097.png differ diff --git a/resources/countries_flags/png-16/taiwan-16x16-33098.png b/resources/countries_flags/png-16/taiwan-16x16-33098.png new file mode 100644 index 00000000..5e49dc94 Binary files /dev/null and b/resources/countries_flags/png-16/taiwan-16x16-33098.png differ diff --git a/resources/countries_flags/png-16/tajikistan-16x16-33100.png b/resources/countries_flags/png-16/tajikistan-16x16-33100.png new file mode 100644 index 00000000..0422e444 Binary files /dev/null and b/resources/countries_flags/png-16/tajikistan-16x16-33100.png differ diff --git a/resources/countries_flags/png-16/tanzania-16x16-33101.png b/resources/countries_flags/png-16/tanzania-16x16-33101.png new file mode 100644 index 00000000..e2913276 Binary files /dev/null and b/resources/countries_flags/png-16/tanzania-16x16-33101.png differ diff --git a/resources/countries_flags/png-16/thailand-16x16-33102.png b/resources/countries_flags/png-16/thailand-16x16-33102.png new file mode 100644 index 00000000..86885e15 Binary files /dev/null and b/resources/countries_flags/png-16/thailand-16x16-33102.png differ diff --git a/resources/countries_flags/png-16/timor-16x16-33103.png b/resources/countries_flags/png-16/timor-16x16-33103.png new file mode 100644 index 00000000..99e3232e Binary files /dev/null and b/resources/countries_flags/png-16/timor-16x16-33103.png differ diff --git a/resources/countries_flags/png-16/togo-16x16-33106.png b/resources/countries_flags/png-16/togo-16x16-33106.png new file mode 100644 index 00000000..50b4bf4d Binary files /dev/null and b/resources/countries_flags/png-16/togo-16x16-33106.png differ diff --git a/resources/countries_flags/png-16/tokelau-16x16-33104.png b/resources/countries_flags/png-16/tokelau-16x16-33104.png new file mode 100644 index 00000000..d915c945 Binary files /dev/null and b/resources/countries_flags/png-16/tokelau-16x16-33104.png differ diff --git a/resources/countries_flags/png-16/tonga-16x16-33107.png b/resources/countries_flags/png-16/tonga-16x16-33107.png new file mode 100644 index 00000000..ddc23004 Binary files /dev/null and b/resources/countries_flags/png-16/tonga-16x16-33107.png differ diff --git a/resources/countries_flags/png-16/trinidad-16x16-33108.png b/resources/countries_flags/png-16/trinidad-16x16-33108.png new file mode 100644 index 00000000..787abafa Binary files /dev/null and b/resources/countries_flags/png-16/trinidad-16x16-33108.png differ diff --git a/resources/countries_flags/png-16/tunisia-16x16-33110.png b/resources/countries_flags/png-16/tunisia-16x16-33110.png new file mode 100644 index 00000000..c6e9c123 Binary files /dev/null and b/resources/countries_flags/png-16/tunisia-16x16-33110.png differ diff --git a/resources/countries_flags/png-16/turkey-16x16-33109.png b/resources/countries_flags/png-16/turkey-16x16-33109.png new file mode 100644 index 00000000..6f7a2417 Binary files /dev/null and b/resources/countries_flags/png-16/turkey-16x16-33109.png differ diff --git a/resources/countries_flags/png-16/turkmenistan-16x16-33111.png b/resources/countries_flags/png-16/turkmenistan-16x16-33111.png new file mode 100644 index 00000000..e33d3fbe Binary files /dev/null and b/resources/countries_flags/png-16/turkmenistan-16x16-33111.png differ diff --git a/resources/countries_flags/png-16/turks-16x16-33112.png b/resources/countries_flags/png-16/turks-16x16-33112.png new file mode 100644 index 00000000..307cd854 Binary files /dev/null and b/resources/countries_flags/png-16/turks-16x16-33112.png differ diff --git a/resources/countries_flags/png-16/tuvalu-16x16-33113.png b/resources/countries_flags/png-16/tuvalu-16x16-33113.png new file mode 100644 index 00000000..b297bee3 Binary files /dev/null and b/resources/countries_flags/png-16/tuvalu-16x16-33113.png differ diff --git a/resources/countries_flags/png-16/uganda-16x16-33129.png b/resources/countries_flags/png-16/uganda-16x16-33129.png new file mode 100644 index 00000000..b9d5579a Binary files /dev/null and b/resources/countries_flags/png-16/uganda-16x16-33129.png differ diff --git a/resources/countries_flags/png-16/ukraine-16x16-33145.png b/resources/countries_flags/png-16/ukraine-16x16-33145.png new file mode 100644 index 00000000..1f57f29b Binary files /dev/null and b/resources/countries_flags/png-16/ukraine-16x16-33145.png differ diff --git a/resources/countries_flags/png-16/united-16x16-33114.png b/resources/countries_flags/png-16/united-16x16-33114.png new file mode 100644 index 00000000..5875e133 Binary files /dev/null and b/resources/countries_flags/png-16/united-16x16-33114.png differ diff --git a/resources/countries_flags/png-16/united-16x16-33115.png b/resources/countries_flags/png-16/united-16x16-33115.png new file mode 100644 index 00000000..ce9b4e28 Binary files /dev/null and b/resources/countries_flags/png-16/united-16x16-33115.png differ diff --git a/resources/countries_flags/png-16/united-16x16-33135.png b/resources/countries_flags/png-16/united-16x16-33135.png new file mode 100644 index 00000000..6fed47e0 Binary files /dev/null and b/resources/countries_flags/png-16/united-16x16-33135.png differ diff --git a/resources/countries_flags/png-16/united-16x16-33137.png b/resources/countries_flags/png-16/united-16x16-33137.png new file mode 100644 index 00000000..438f5bb8 Binary files /dev/null and b/resources/countries_flags/png-16/united-16x16-33137.png differ diff --git a/resources/countries_flags/png-16/uruguay-16x16-33140.png b/resources/countries_flags/png-16/uruguay-16x16-33140.png new file mode 100644 index 00000000..8d5fb8ee Binary files /dev/null and b/resources/countries_flags/png-16/uruguay-16x16-33140.png differ diff --git a/resources/countries_flags/png-16/uzbekistan-16x16-33141.png b/resources/countries_flags/png-16/uzbekistan-16x16-33141.png new file mode 100644 index 00000000..d6b282a6 Binary files /dev/null and b/resources/countries_flags/png-16/uzbekistan-16x16-33141.png differ diff --git a/resources/countries_flags/png-16/vanuatu-16x16-33142.png b/resources/countries_flags/png-16/vanuatu-16x16-33142.png new file mode 100644 index 00000000..90b17883 Binary files /dev/null and b/resources/countries_flags/png-16/vanuatu-16x16-33142.png differ diff --git a/resources/countries_flags/png-16/venezuela-16x16-33138.png b/resources/countries_flags/png-16/venezuela-16x16-33138.png new file mode 100644 index 00000000..63d2cf74 Binary files /dev/null and b/resources/countries_flags/png-16/venezuela-16x16-33138.png differ diff --git a/resources/countries_flags/png-16/vietnam-16x16-33148.png b/resources/countries_flags/png-16/vietnam-16x16-33148.png new file mode 100644 index 00000000..a0a842a5 Binary files /dev/null and b/resources/countries_flags/png-16/vietnam-16x16-33148.png differ diff --git a/resources/countries_flags/png-16/virgin-16x16-33147.png b/resources/countries_flags/png-16/virgin-16x16-33147.png new file mode 100644 index 00000000..52f4579e Binary files /dev/null and b/resources/countries_flags/png-16/virgin-16x16-33147.png differ diff --git a/resources/countries_flags/png-16/virgin-16x16-33149.png b/resources/countries_flags/png-16/virgin-16x16-33149.png new file mode 100644 index 00000000..63c570a2 Binary files /dev/null and b/resources/countries_flags/png-16/virgin-16x16-33149.png differ diff --git a/resources/countries_flags/png-16/wales-16x16-33158.png b/resources/countries_flags/png-16/wales-16x16-33158.png new file mode 100644 index 00000000..9df12b7f Binary files /dev/null and b/resources/countries_flags/png-16/wales-16x16-33158.png differ diff --git a/resources/countries_flags/png-16/wallis-16x16-33144.png b/resources/countries_flags/png-16/wallis-16x16-33144.png new file mode 100644 index 00000000..faa756de Binary files /dev/null and b/resources/countries_flags/png-16/wallis-16x16-33144.png differ diff --git a/resources/countries_flags/png-16/western-16x16-33139.png b/resources/countries_flags/png-16/western-16x16-33139.png new file mode 100644 index 00000000..abb8f097 Binary files /dev/null and b/resources/countries_flags/png-16/western-16x16-33139.png differ diff --git a/resources/countries_flags/png-16/yemen-16x16-33143.png b/resources/countries_flags/png-16/yemen-16x16-33143.png new file mode 100644 index 00000000..2d95a290 Binary files /dev/null and b/resources/countries_flags/png-16/yemen-16x16-33143.png differ diff --git a/resources/countries_flags/png-16/zambia-16x16-33146.png b/resources/countries_flags/png-16/zambia-16x16-33146.png new file mode 100644 index 00000000..cdb1f2ef Binary files /dev/null and b/resources/countries_flags/png-16/zambia-16x16-33146.png differ diff --git a/resources/countries_flags/png-16/zimbabwe-16x16-33150.png b/resources/countries_flags/png-16/zimbabwe-16x16-33150.png new file mode 100644 index 00000000..0c33cbac Binary files /dev/null and b/resources/countries_flags/png-16/zimbabwe-16x16-33150.png differ diff --git a/resources/filters_view.png b/resources/filters_view.png deleted file mode 100644 index 909dc894..00000000 Binary files a/resources/filters_view.png and /dev/null differ diff --git a/resources/header_repository.png b/resources/header_repository.png deleted file mode 100644 index fbde20eb..00000000 Binary files a/resources/header_repository.png and /dev/null differ diff --git a/resources/glyph.svg b/resources/logos/glyph.svg similarity index 100% rename from resources/glyph.svg rename to resources/logos/glyph.svg diff --git a/resources/icon.ico b/resources/logos/icon.ico similarity index 100% rename from resources/icon.ico rename to resources/logos/icon.ico diff --git a/resources/icon.png b/resources/logos/icon.png similarity index 100% rename from resources/icon.png rename to resources/logos/icon.png diff --git a/resources/icon_black.png b/resources/logos/icon_black.png similarity index 100% rename from resources/icon_black.png rename to resources/logos/icon_black.png diff --git a/resources/icon_white.png b/resources/logos/icon_white.png similarity index 100% rename from resources/icon_white.png rename to resources/logos/icon_white.png diff --git a/resources/icon_window.png b/resources/logos/icon_window.png similarity index 100% rename from resources/icon_window.png rename to resources/logos/icon_window.png diff --git a/resources/logo_black.png b/resources/logos/logo_black.png similarity index 100% rename from resources/logo_black.png rename to resources/logos/logo_black.png diff --git a/resources/logo_white.png b/resources/logos/logo_white.png similarity index 100% rename from resources/logo_white.png rename to resources/logos/logo_white.png diff --git a/resources/packets_view.png b/resources/packets_view.png deleted file mode 100644 index afbb87b9..00000000 Binary files a/resources/packets_view.png and /dev/null differ diff --git a/resources/palettes/DeepSea.png b/resources/palettes/DeepSea.png new file mode 100644 index 00000000..25ff24f3 Binary files /dev/null and b/resources/palettes/DeepSea.png differ diff --git a/resources/palettes/MonAmour.png b/resources/palettes/MonAmour.png new file mode 100644 index 00000000..d8b0abfa Binary files /dev/null and b/resources/palettes/MonAmour.png differ diff --git a/resources/palettes/YetiDay.png b/resources/palettes/YetiDay.png new file mode 100644 index 00000000..1f20b905 Binary files /dev/null and b/resources/palettes/YetiDay.png differ diff --git a/resources/palettes/YetiNight.png b/resources/palettes/YetiNight.png new file mode 100644 index 00000000..df28f712 Binary files /dev/null and b/resources/palettes/YetiNight.png differ diff --git a/resources/report_view.png b/resources/report_view.png deleted file mode 100644 index b9f00718..00000000 Binary files a/resources/report_view.png and /dev/null differ diff --git a/resources/repository_resources/README_features/initial_page.png b/resources/repository_resources/README_features/initial_page.png new file mode 100644 index 00000000..d2384141 Binary files /dev/null and b/resources/repository_resources/README_features/initial_page.png differ diff --git a/resources/repository_resources/README_features/notifications_page.png b/resources/repository_resources/README_features/notifications_page.png new file mode 100644 index 00000000..24e467fb Binary files /dev/null and b/resources/repository_resources/README_features/notifications_page.png differ diff --git a/resources/repository_resources/README_features/overview_page.png b/resources/repository_resources/README_features/overview_page.png new file mode 100644 index 00000000..cf5be95f Binary files /dev/null and b/resources/repository_resources/README_features/overview_page.png differ diff --git a/resources/repository_resources/README_features/settings_page.png b/resources/repository_resources/README_features/settings_page.png new file mode 100644 index 00000000..c99b14a5 Binary files /dev/null and b/resources/repository_resources/README_features/settings_page.png differ diff --git a/resources/sniffnet_run_example.gif b/resources/repository_resources/README_video/sniffnet_run_example.gif similarity index 100% rename from resources/sniffnet_run_example.gif rename to resources/repository_resources/README_video/sniffnet_run_example.gif diff --git a/resources/sniffnet_run_example.mp4 b/resources/repository_resources/README_video/sniffnet_run_example.mp4 similarity index 100% rename from resources/sniffnet_run_example.mp4 rename to resources/repository_resources/README_video/sniffnet_run_example.mp4 diff --git a/resources/repository_resources/header_repository.png b/resources/repository_resources/header_repository.png new file mode 100644 index 00000000..6955835b Binary files /dev/null and b/resources/repository_resources/header_repository.png differ diff --git a/resources/logo_repository.png b/resources/repository_resources/logo_repository.png similarity index 100% rename from resources/logo_repository.png rename to resources/repository_resources/logo_repository.png diff --git a/resources/sounds/gulp.mp3 b/resources/sounds/gulp.mp3 new file mode 100644 index 00000000..c0f0813a Binary files /dev/null and b/resources/sounds/gulp.mp3 differ diff --git a/resources/sounds/pop.mp3 b/resources/sounds/pop.mp3 new file mode 100644 index 00000000..24ec0813 Binary files /dev/null and b/resources/sounds/pop.mp3 differ diff --git a/resources/sounds/swhoosh.mp3 b/resources/sounds/swhoosh.mp3 new file mode 100644 index 00000000..96347941 Binary files /dev/null and b/resources/sounds/swhoosh.mp3 differ diff --git a/src/enums/app_protocol.rs b/src/enums/app_protocol.rs index 73e255cc..8731041e 100644 --- a/src/enums/app_protocol.rs +++ b/src/enums/app_protocol.rs @@ -120,6 +120,14 @@ impl fmt::Display for AppProtocol { /// Defines a constant to be used in the picklist in gui initial page impl AppProtocol { + // pub fn get_picklist_label(&self, language: Language) -> String { + // let display = format!("{self:?}").to_owned(); + // match self { + // AppProtocol::Other => all_protocols_translation(language).to_string(), + // _ => display + // } + // } + pub(crate) const ALL: [AppProtocol; 25] = [ AppProtocol::Other, AppProtocol::BGP, diff --git a/src/enums/byte_multiple.rs b/src/enums/byte_multiple.rs new file mode 100644 index 00000000..d34e17f8 --- /dev/null +++ b/src/enums/byte_multiple.rs @@ -0,0 +1,53 @@ +use crate::enums::byte_multiple::ByteMultiple::{B, GB, KB, MB}; +use serde::{Deserialize, Serialize}; +use std::fmt; + +/// Enum representing the possible observed values of IP protocol version. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum ByteMultiple { + /// A Byte + B, + /// A thousand Bytes + KB, + /// A million Bytes + MB, + /// A billion Bytes + GB, +} + +impl fmt::Display for ByteMultiple { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self:?}") + } +} + +impl ByteMultiple { + // pub(crate) const ALL: [ByteMultiple; 4] = [B, KB, MB, GB]; + + pub fn get_multiplier(self) -> u64 { + match self { + B => 1, + KB => 1_000, + MB => 1_000_000, + GB => 1_000_000_000, + } + } + + pub fn get_char(&self) -> &str { + match self { + B => "", + KB => "K", + MB => "M", + GB => "G", + } + } +} + +pub fn from_char_to_multiple(ch: char) -> ByteMultiple { + match ch.to_ascii_uppercase() { + 'K' => ByteMultiple::KB, + 'M' => ByteMultiple::MB, + 'G' => ByteMultiple::GB, + _ => ByteMultiple::B, + } +} diff --git a/src/enums/chart_type.rs b/src/enums/chart_type.rs index 281d4aed..513a0b23 100644 --- a/src/enums/chart_type.rs +++ b/src/enums/chart_type.rs @@ -1,6 +1,20 @@ +use crate::utility::translations::{bytes_chart_translation, packets_chart_translation}; +use crate::Language; + /// Enum representing the possible kind of chart displayed. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ChartType { Packets, Bytes, } + +impl ChartType { + pub(crate) const ALL: [ChartType; 2] = [ChartType::Packets, ChartType::Bytes]; + + pub fn get_radio_label(&self, language: Language) -> &str { + match self { + ChartType::Packets => packets_chart_translation(language), + ChartType::Bytes => bytes_chart_translation(language), + } + } +} diff --git a/src/enums/element_type.rs b/src/enums/element_type.rs new file mode 100644 index 00000000..15edcdd0 --- /dev/null +++ b/src/enums/element_type.rs @@ -0,0 +1,13 @@ +/// Used to specify the kind of `iced` element, to be able to choose the appropriate style for it +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum ElementType { + Standard, + Headers, + BorderedRound, + TabActive, + TabInactive, + Starred, + NotStarred, + Alert, + Tooltip, +} diff --git a/src/enums/ip_version.rs b/src/enums/ip_version.rs index 02c5c8c4..35d5340e 100644 --- a/src/enums/ip_version.rs +++ b/src/enums/ip_version.rs @@ -1,3 +1,5 @@ +use crate::utility::translations::both_translation; +use crate::Language; use std::fmt; /// Enum representing the possible observed values of IP protocol version. @@ -16,3 +18,15 @@ impl fmt::Display for IpVersion { write!(f, "{self:?}") } } + +impl IpVersion { + pub(crate) const ALL: [IpVersion; 3] = [IpVersion::IPv4, IpVersion::IPv6, IpVersion::Other]; + + pub fn get_radio_label(&self, language: Language) -> &str { + match self { + IpVersion::IPv4 => "IPv4", + IpVersion::IPv6 => "IPv6", + IpVersion::Other => both_translation(language), + } + } +} diff --git a/src/enums/language.rs b/src/enums/language.rs new file mode 100644 index 00000000..d7b5c7e1 --- /dev/null +++ b/src/enums/language.rs @@ -0,0 +1,27 @@ +use serde::{Deserialize, Serialize}; + +/// This enum defines the available languages. +#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)] +pub enum Language { + /// English (default language). + EN, + /// Italian. + IT, +} + +impl Default for Language { + fn default() -> Self { + Self::EN + } +} + +impl Language { + pub(crate) const ALL: [Language; 2] = [Language::EN, Language::IT]; + + pub fn get_radio_label(&self) -> &str { + match self { + Language::EN => "English", + Language::IT => "Italiano", + } + } +} diff --git a/src/enums/logged_notification.rs b/src/enums/logged_notification.rs new file mode 100644 index 00000000..ac895fe9 --- /dev/null +++ b/src/enums/logged_notification.rs @@ -0,0 +1,35 @@ +use crate::structs::address_port_pair::AddressPortPair; +use crate::structs::info_address_port_pair::InfoAddressPortPair; +use crate::structs::notifications::{BytesNotification, PacketsNotification}; + +/// Enum representing the possible observed values of IP protocol version. +pub enum LoggedNotification { + /// Packets threshold exceeded + PacketsThresholdExceeded(PacketsThresholdExceeded), + /// Byte threshold exceeded + BytesThresholdExceeded(BytesThresholdExceeded), + /// Favorite connection exchanged data + FavoriteTransmitted(FavoriteTransmitted), +} + +#[derive(Clone)] +pub struct PacketsThresholdExceeded { + pub(crate) notification: PacketsNotification, + pub(crate) incoming: u32, + pub(crate) outgoing: u32, + pub(crate) timestamp: String, +} + +#[derive(Clone)] +pub struct BytesThresholdExceeded { + pub(crate) notification: BytesNotification, + pub(crate) incoming: u32, + pub(crate) outgoing: u32, + pub(crate) timestamp: String, +} + +#[derive(Clone)] +pub struct FavoriteTransmitted { + pub(crate) connection: (AddressPortPair, InfoAddressPortPair), + pub(crate) timestamp: String, +} diff --git a/src/enums/message.rs b/src/enums/message.rs index 09bfb96f..adbb0323 100644 --- a/src/enums/message.rs +++ b/src/enums/message.rs @@ -1,4 +1,7 @@ -use crate::{AppProtocol, ChartType, IpVersion, ReportType, TransProtocol}; +use crate::enums::overlay::MyOverlay; +use crate::enums::running_page::RunningPage; +use crate::structs::notifications::{BytesNotification, FavoriteNotification, PacketsNotification}; +use crate::{AppProtocol, ChartType, IpVersion, Language, ReportType, StyleType, TransProtocol}; #[derive(Debug, Clone)] /// Messages types that permit to react to application interactions/subscriptions @@ -19,6 +22,10 @@ pub enum Message { ChartSelection(ChartType), /// Select report type to be displayed ReportSelection(ReportType), + /// Saves the given connection into the favorites + SaveConnection(usize), + /// Un-saves the given connection into the favorites + UnSaveConnection(usize), /// Open Sniffnet's complete textual report OpenReport, /// Open Sniffnet's GitHub page @@ -28,5 +35,25 @@ pub enum Message { /// Stop sniffing process and return to initial page Reset, /// Change application style (day or night) - Style, + Style(StyleType), + /// Manage waiting time + Waiting, + /// Displays an overlay + ShowModal(MyOverlay), + /// Hides the current overlay modal; if true is passed, config file is updated + HideModal(bool), + /// Permits to change the current running page + ChangeRunningPage(RunningPage), + /// Select language + LanguageSelection(Language), + /// Set packets notification + UpdatePacketsNotification(PacketsNotification, bool), + /// Set packets notification + UpdateBytesNotification(BytesNotification, bool), + /// Set packets notification + UpdateFavoriteNotification(FavoriteNotification, bool), + /// Clear all received notifications + ClearAllNotifications, + /// Set notifications volume + ChangeVolume(u8), } diff --git a/src/enums/mod.rs b/src/enums/mod.rs index 077a3aec..297f16de 100644 --- a/src/enums/mod.rs +++ b/src/enums/mod.rs @@ -1,8 +1,16 @@ pub mod app_protocol; +pub mod byte_multiple; pub mod chart_type; +pub mod element_type; pub mod ip_version; +pub mod language; +pub mod logged_notification; pub mod message; +pub mod overlay; pub mod report_type; +pub mod running_page; +pub mod sound; pub mod status; +pub mod style_type; pub mod traffic_type; pub mod trans_protocol; diff --git a/src/enums/overlay.rs b/src/enums/overlay.rs new file mode 100644 index 00000000..f884b626 --- /dev/null +++ b/src/enums/overlay.rs @@ -0,0 +1,30 @@ +use crate::utility::translations::{ + language_translation, notifications_translation, style_translation, +}; +use crate::Language; + +/// This enum defines the current running page. +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum MyOverlay { + /// Settings Notifications page. + SettingsNotifications, + /// Settings Appearance page. + SettingsAppearance, + /// Settings Language page. + SettingsLanguage, + /// Quit modal. + Quit, + /// Clear all modal. + ClearAll, +} + +impl MyOverlay { + pub fn get_tab_label(&self, language: Language) -> &str { + match self { + MyOverlay::SettingsNotifications => notifications_translation(language), + MyOverlay::SettingsAppearance => style_translation(language), + MyOverlay::SettingsLanguage => language_translation(language), + MyOverlay::Quit | MyOverlay::ClearAll => "", + } + } +} diff --git a/src/enums/report_type.rs b/src/enums/report_type.rs index f6321d73..59e061fa 100644 --- a/src/enums/report_type.rs +++ b/src/enums/report_type.rs @@ -1,8 +1,34 @@ #![allow(clippy::enum_variant_names)] + +use crate::utility::translations::{ + bytes_report_translation, favorite_report_translation, packets_report_translation, + recent_report_translation, +}; +use crate::Language; + /// Enum representing the possible kinds of displayed relevant connections. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ReportType { MostRecent, MostPackets, MostBytes, + Favorites, +} + +impl ReportType { + pub(crate) const ALL: [ReportType; 4] = [ + ReportType::MostRecent, + ReportType::MostPackets, + ReportType::MostBytes, + ReportType::Favorites, + ]; + + pub fn get_radio_label(&self, language: Language) -> &str { + match self { + ReportType::MostRecent => recent_report_translation(language), + ReportType::MostPackets => packets_report_translation(language), + ReportType::MostBytes => bytes_report_translation(language), + ReportType::Favorites => favorite_report_translation(language), + } + } } diff --git a/src/enums/running_page.rs b/src/enums/running_page.rs new file mode 100644 index 00000000..f26219db --- /dev/null +++ b/src/enums/running_page.rs @@ -0,0 +1,23 @@ +use crate::utility::translations::{notifications_translation, overview_translation}; +use crate::Language; + +/// This enum defines the current running page. +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum RunningPage { + /// Overview page. + Overview, + // /// Inspect page. + // Inspect, + /// Notifications page. + Notifications, +} + +impl RunningPage { + pub fn get_tab_label(&self, language: Language) -> &str { + match self { + RunningPage::Overview => overview_translation(language), + // RunningPage::Inspect => inspect_translation(language), + RunningPage::Notifications => notifications_translation(language), + } + } +} diff --git a/src/enums/sound.rs b/src/enums/sound.rs new file mode 100644 index 00000000..928cde58 --- /dev/null +++ b/src/enums/sound.rs @@ -0,0 +1,74 @@ +use crate::enums::sound::Sound::{Gulp, Pop, Swhoosh}; +use crate::utility::translations::none_translation; +use crate::Language; +use rodio::{Decoder, OutputStream, Sink}; +use serde::{Deserialize, Serialize}; +use std::fmt; +use std::thread; + +/// Enum representing the possible notification sounds. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Sound { + Gulp, + Pop, + Swhoosh, + None, +} + +pub const GULP: &[u8] = include_bytes!("../../resources/sounds/gulp.mp3"); +pub const POP: &[u8] = include_bytes!("../../resources/sounds/pop.mp3"); +pub const SWHOOSH: &[u8] = include_bytes!("../../resources/sounds/swhoosh.mp3"); + +impl fmt::Display for Sound { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self:?}") + } +} + +/// Defines a constant to be used in the picklist in gui notifications page +impl Sound { + pub(crate) const ALL: [Sound; 4] = [Gulp, Pop, Swhoosh, Sound::None]; + + fn mp3_sound(self) -> &'static [u8] { + match self { + Gulp => GULP, + Pop => POP, + Swhoosh => SWHOOSH, + Sound::None => &[], + } + } + + pub fn get_radio_label(&self, language: Language) -> &str { + match self { + Gulp => "Gulp", + Pop => "Pop", + Swhoosh => "Swhoosh", + Sound::None => none_translation(language), + } + } +} + +pub fn play_sound(sound: Sound, volume: u8) { + if sound.eq(&Sound::None) || volume == 0 { + return; + } + let mp3_sound = sound.mp3_sound(); + thread::Builder::new() + .name("thread_play_sound".to_string()) + .spawn(move || { + // Get a output stream handle to the default physical sound device + let (_stream, stream_handle) = OutputStream::try_default().unwrap(); + let sink = Sink::try_new(&stream_handle).unwrap(); + //load data + let data = std::io::Cursor::new(mp3_sound); + // Decode that sound file into a source + let source = Decoder::new(data).unwrap(); + // Play the sound directly on the device + sink.set_volume(f32::from(volume) / 200.0); // set the desired volume + sink.append(source); + // The sound plays in a separate thread. This call will block the current thread until the sink + // has finished playing all its queued sounds. + sink.sleep_until_end(); + }) + .unwrap(); +} diff --git a/src/enums/style_type.rs b/src/enums/style_type.rs new file mode 100644 index 00000000..f6f0dfbe --- /dev/null +++ b/src/enums/style_type.rs @@ -0,0 +1,16 @@ +use serde::{Deserialize, Serialize}; + +/// Used to specify the kind of style of the application +#[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] +pub enum StyleType { + Night, + Day, + DeepSea, + MonAmour, +} + +impl Default for StyleType { + fn default() -> Self { + Self::Night + } +} diff --git a/src/enums/traffic_type.rs b/src/enums/traffic_type.rs index 8ae2d347..fa2a11d4 100644 --- a/src/enums/traffic_type.rs +++ b/src/enums/traffic_type.rs @@ -7,6 +7,8 @@ pub enum TrafficType { Outgoing, /// Multicast traffic (from remote address to multicast address) Multicast, + /// Multicast traffic (from remote address to broadcast address) + Broadcast, /// Not identified Other, } diff --git a/src/enums/trans_protocol.rs b/src/enums/trans_protocol.rs index f6bd7da5..ab024c25 100644 --- a/src/enums/trans_protocol.rs +++ b/src/enums/trans_protocol.rs @@ -1,4 +1,6 @@ #![allow(clippy::upper_case_acronyms)] +use crate::utility::translations::both_translation; +use crate::Language; use std::fmt; /// Enum representing the possible observed values of transport layer protocol. @@ -17,3 +19,16 @@ impl fmt::Display for TransProtocol { write!(f, "{self:?}") } } + +impl TransProtocol { + pub(crate) const ALL: [TransProtocol; 3] = + [TransProtocol::TCP, TransProtocol::UDP, TransProtocol::Other]; + + pub fn get_radio_label(&self, language: Language) -> &str { + match self { + TransProtocol::TCP => "TCP", + TransProtocol::UDP => "UDP", + TransProtocol::Other => both_translation(language), + } + } +} diff --git a/src/gui/app.rs b/src/gui/app.rs index 05155f09..e9c5d945 100644 --- a/src/gui/app.rs +++ b/src/gui/app.rs @@ -2,21 +2,40 @@ //! //! It also is a wrapper of gui's main two pages: initial and run page. +use iced::widget::Column; +use iced::{executor, Application, Command, Element, Subscription, Theme}; +use pcap::Device; +use std::cell::RefCell; +use std::collections::VecDeque; +use std::rc::Rc; use std::thread; use std::time::Duration; -use iced::{executor, Application, Command, Container, Element, Length, Subscription}; -use pcap::Device; - use crate::enums::message::Message; +use crate::enums::overlay::MyOverlay; +use crate::enums::running_page::RunningPage; +use crate::enums::sound::{play_sound, Sound}; use crate::enums::status::Status; -use crate::gui::style::StyleType; -use crate::gui::{gui_initial_page::initial_page, gui_run_page::run_page}; +use crate::gui::components::footer::get_footer; +use crate::gui::components::header::get_header; +use crate::gui::components::modal::{get_clear_all_overlay, get_exit_overlay, Modal}; +use crate::gui::pages::initial_page::initial_page; +// use crate::gui::pages::inspect_page::inspect_page; +use crate::gui::pages::notifications_page::notifications_page; +use crate::gui::pages::overview_page::overview_page; +use crate::gui::pages::settings::{ + settings_appearance_page, settings_language_page, settings_notifications_page, +}; +use crate::structs::config::Config; use crate::structs::sniffer::Sniffer; use crate::structs::traffic_chart::TrafficChart; use crate::thread_parse_packets::parse_packets_loop; use crate::utility::manage_charts_data::update_charts_data; -use crate::{InfoTraffic, RunTimeData}; +use crate::utility::manage_notifications::notify_and_log; +use crate::utility::manage_packets::get_capture_result; +use crate::utility::manage_report_data::update_report_data; +use crate::utility::style_constants::get_font; +use crate::{InfoTraffic, ReportType, RunTimeData}; /// Update period when app is running pub const PERIOD_RUNNING: u64 = 1000; @@ -27,10 +46,11 @@ pub const PERIOD_INIT: u64 = 5000; //milliseconds impl Application for Sniffer { type Executor = executor::Default; type Message = Message; + type Theme = Theme; type Flags = Sniffer; fn new(flags: Sniffer) -> (Sniffer, Command) { - (flags, Command::none()) + (flags, iced::window::maximize(true)) } fn title(&self) -> String { @@ -41,42 +61,75 @@ impl Application for Sniffer { match message { Message::TickInit => {} Message::TickRun => { - let mut runtime_data_lock = self.runtime_data.lock().unwrap(); - let info_traffic_lock = self.info_traffic.lock().unwrap(); - runtime_data_lock.all_packets = info_traffic_lock.all_packets; - runtime_data_lock.tot_sent_packets = info_traffic_lock.tot_sent_packets as i128; - runtime_data_lock.tot_received_packets = - info_traffic_lock.tot_received_packets as i128; - runtime_data_lock.all_bytes = info_traffic_lock.all_bytes; - runtime_data_lock.tot_received_bytes = info_traffic_lock.tot_received_bytes as i128; - runtime_data_lock.tot_sent_bytes = info_traffic_lock.tot_sent_bytes as i128; - runtime_data_lock.app_protocols = info_traffic_lock.app_protocols.clone(); - drop(info_traffic_lock); - drop(runtime_data_lock); - update_charts_data(self.runtime_data.clone()); + let mut info_traffic_lock = self.info_traffic.lock().unwrap(); + self.runtime_data.borrow_mut().all_packets = info_traffic_lock.all_packets; + if info_traffic_lock.tot_received_packets + info_traffic_lock.tot_sent_packets == 0 + { + drop(info_traffic_lock); + self.update(Message::Waiting); + } else { + self.runtime_data.borrow_mut().tot_sent_packets = + info_traffic_lock.tot_sent_packets; + self.runtime_data.borrow_mut().tot_received_packets = + info_traffic_lock.tot_received_packets; + self.runtime_data.borrow_mut().all_packets = info_traffic_lock.all_packets; + self.runtime_data.borrow_mut().all_bytes = info_traffic_lock.all_bytes; + self.runtime_data.borrow_mut().tot_received_bytes = + info_traffic_lock.tot_received_bytes; + self.runtime_data.borrow_mut().tot_sent_bytes = + info_traffic_lock.tot_sent_bytes; + self.runtime_data.borrow_mut().app_protocols = + info_traffic_lock.app_protocols.clone(); + self.runtime_data + .borrow_mut() + .favorite_featured_last_interval = + info_traffic_lock.favorite_featured_last_interval.clone(); + info_traffic_lock.favorite_featured_last_interval = None; + drop(info_traffic_lock); + notify_and_log(self.runtime_data.borrow_mut(), self.notifications); + update_charts_data(self.runtime_data.borrow_mut()); + update_report_data( + self.runtime_data.borrow_mut(), + &self.info_traffic, + self.report_type, + ); + // waiting notifications + if self.running_page.eq(&RunningPage::Notifications) + && self.runtime_data.borrow().logged_notifications.is_empty() + { + self.update(Message::Waiting); + } + } } Message::AdapterSelection(name) => { for dev in Device::list().expect("Error retrieving device list\r\n") { if dev.name.eq(&name) { - *self.device.lock().unwrap() = dev; + self.device = dev; break; } } } Message::IpVersionSelection(version) => { - self.filters.lock().unwrap().ip = version; + self.filters.ip = version; } Message::TransportProtocolSelection(protocol) => { - self.filters.lock().unwrap().transport = protocol; + self.filters.transport = protocol; } Message::AppProtocolSelection(protocol) => { - self.filters.lock().unwrap().application = protocol; + self.filters.application = protocol; } Message::ChartSelection(what_to_display) => { - self.chart_type = what_to_display; + self.traffic_chart.change_kind(what_to_display); } Message::ReportSelection(what_to_display) => { - self.report_type = what_to_display; + if what_to_display.ne(&self.report_type) { + self.report_type = what_to_display; + update_report_data( + self.runtime_data.borrow_mut(), + &self.info_traffic, + self.report_type, + ); + } } Message::OpenReport => { #[cfg(target_os = "windows")] @@ -114,73 +167,187 @@ impl Application for Sniffer { .unwrap(); } Message::Start => { - let current_capture_id = self.current_capture_id.clone(); let device = self.device.clone(); - let filters = self.filters.clone(); - let pcap_error = self.pcap_error.clone(); + let (pcap_error, cap) = get_capture_result(&device); + self.pcap_error = pcap_error.clone(); + *self.status_pair.0.lock().unwrap() = Status::Running; let info_traffic_mutex = self.info_traffic.clone(); *info_traffic_mutex.lock().unwrap() = InfoTraffic::new(); - let runtime_data_mutex = self.runtime_data.clone(); - *runtime_data_mutex.lock().unwrap() = RunTimeData::new(); - *self.status_pair.0.lock().unwrap() = Status::Running; - self.traffic_chart = TrafficChart::new(runtime_data_mutex); - self.status_pair.1.notify_all(); - thread::Builder::new() - .name(format!( - "thread_parse_packets_{}", - current_capture_id.lock().unwrap() - )) - .spawn(move || { - parse_packets_loop( - current_capture_id, - device, - filters, - info_traffic_mutex, - pcap_error, - ); - }) - .unwrap(); + self.runtime_data = Rc::new(RefCell::new(RunTimeData::new())); + self.traffic_chart = + TrafficChart::new(self.runtime_data.clone(), self.style, self.language); + + if pcap_error.is_none() { + // no pcap error + let current_capture_id = self.current_capture_id.clone(); + let filters = self.filters.clone(); + self.status_pair.1.notify_all(); + thread::Builder::new() + .name("thread_parse_packets".to_string()) + .spawn(move || { + parse_packets_loop( + ¤t_capture_id, + device.clone(), + cap.unwrap(), + &filters, + &info_traffic_mutex, + ); + }) + .unwrap(); + } } Message::Reset => { - *self.current_capture_id.lock().unwrap() += 1; //change capture id to kill previous capture and to rewrite output file *self.status_pair.0.lock().unwrap() = Status::Init; - *self.pcap_error.lock().unwrap() = Option::None; + self.running_page = RunningPage::Overview; + *self.current_capture_id.lock().unwrap() += 1; //change capture id to kill previous capture and to rewrite output file + self.pcap_error = None; + self.report_type = ReportType::MostRecent; + self.update(Message::HideModal(false)); } - Message::Style => { - self.style = if self.style == StyleType::Day { - StyleType::Night - } else { - StyleType::Day - }; + Message::Style(style) => { + self.style = style; + self.traffic_chart.change_colors(self.style); } - } - Command::none() - } - - fn subscription(&self) -> Subscription { - match *self.status_pair.0.lock().unwrap() { - Status::Running => { - iced::time::every(Duration::from_millis(PERIOD_RUNNING)).map(|_| Message::TickRun) + Message::Waiting => { + if self.waiting.len() > 2 { + self.waiting = String::new(); + } + self.waiting = ".".repeat(self.waiting.len() + 1); + } + Message::SaveConnection(index) => { + let mut info_traffic = self.info_traffic.lock().unwrap(); + info_traffic.favorite_connections.insert(index); + let key_val = info_traffic.map.get_index_mut(index).unwrap(); + key_val.1.is_favorite = true; + drop(info_traffic); + update_report_data( + self.runtime_data.borrow_mut(), + &self.info_traffic, + self.report_type, + ); + } + Message::UnSaveConnection(index) => { + let mut info_traffic = self.info_traffic.lock().unwrap(); + info_traffic.favorite_connections.remove(&index); + let key_val = info_traffic.map.get_index_mut(index).unwrap(); + key_val.1.is_favorite = false; + drop(info_traffic); + update_report_data( + self.runtime_data.borrow_mut(), + &self.info_traffic, + self.report_type, + ); + } + Message::ShowModal(overlay) => { + self.overlay = Some(overlay); + } + Message::HideModal(save_config) => { + self.overlay = None; + if save_config { + let store = Config { + style: self.style, + notifications: self.notifications, + language: self.language, + }; + confy::store("sniffnet", None, store).unwrap(); + } + } + Message::ChangeRunningPage(running_page) => { + self.running_page = running_page; + } + Message::LanguageSelection(language) => { + self.language = language; + self.traffic_chart.change_language(language); + } + Message::UpdatePacketsNotification(value, emit_sound) => { + if emit_sound { + play_sound(value.sound, self.notifications.volume); + } + self.notifications.packets_notification = value; + } + Message::UpdateBytesNotification(value, emit_sound) => { + if emit_sound { + play_sound(value.sound, self.notifications.volume); + } + self.notifications.bytes_notification = value; + } + Message::UpdateFavoriteNotification(value, emit_sound) => { + if emit_sound { + play_sound(value.sound, self.notifications.volume); + } + self.notifications.favorite_notification = value; + } + Message::ChangeVolume(volume) => { + play_sound(Sound::Pop, volume); + self.notifications.volume = volume; + } + Message::ClearAllNotifications => { + self.runtime_data.borrow_mut().logged_notifications = VecDeque::new(); + self.update(Message::HideModal(false)); } - _ => iced::time::every(Duration::from_millis(PERIOD_INIT)).map(|_| Message::TickInit), } + Command::none() } - fn view(&mut self) -> Element { + fn view(&self) -> Element { let status = *self.status_pair.0.lock().unwrap(); - let mode = self.style; + let style = self.style; + + let header = match status { + Status::Init => get_header(style, false, 0, self.language), + Status::Running => get_header( + style, + true, + self.info_traffic.lock().unwrap().all_packets, + self.language, + ), + }; let body = match status { Status::Init => initial_page(self), - Status::Running => run_page(self), + Status::Running => match self.running_page { + RunningPage::Overview => overview_page(self), + // RunningPage::Inspect => inspect_page(self), + RunningPage::Notifications => notifications_page(self), + }, }; - Container::new(body) - .width(Length::Fill) - .height(Length::Fill) - .center_x() - .center_y() - .style(mode) - .into() + let content = Column::new() + .push(header) + .push(body) + .push(get_footer(style)); + + if self.overlay.is_none() { + content.into() + } else { + let (overlay, save_config) = match self.overlay.unwrap() { + MyOverlay::Quit => ( + get_exit_overlay(style, get_font(style), self.language), + false, + ), + MyOverlay::ClearAll => ( + get_clear_all_overlay(style, get_font(style), self.language), + false, + ), + MyOverlay::SettingsNotifications => (settings_notifications_page(self), true), + MyOverlay::SettingsAppearance => (settings_appearance_page(self), true), + MyOverlay::SettingsLanguage => (settings_language_page(self), true), + }; + + Modal::new(content, overlay) + .on_blur(Message::HideModal(save_config)) + .into() + } + } + + fn subscription(&self) -> Subscription { + match *self.status_pair.0.lock().unwrap() { + Status::Running => { + iced::time::every(Duration::from_millis(PERIOD_RUNNING)).map(|_| Message::TickRun) + } + Status::Init => { + iced::time::every(Duration::from_millis(PERIOD_INIT)).map(|_| Message::TickInit) + } + } } } diff --git a/src/gui/components/footer.rs b/src/gui/components/footer.rs new file mode 100644 index 00000000..1029edd4 --- /dev/null +++ b/src/gui/components/footer.rs @@ -0,0 +1,59 @@ +//! GUI bottom footer + +use crate::enums::element_type::ElementType; +use crate::enums::message::Message; +use crate::enums::style_type::StyleType; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::get_formatted_strings::APP_VERSION; +use crate::utility::style_constants::{ + get_font, get_font_headers, FONT_SIZE_FOOTER, HEIGHT_FOOTER, ICONS, +}; +use iced::alignment::{Horizontal, Vertical}; +use iced::widget::{button, Container, Row, Text, Tooltip}; +use iced::Length::FillPortion; +use iced::{Alignment, Length}; +use iced_native::widget::tooltip::Position; + +pub fn get_footer(style: StyleType) -> Container<'static, Message> { + let font = get_font(style); + let font_footer = get_font_headers(style); + + let footer_row = Row::new() + .align_items(Alignment::Center) + .push( + Text::new(format!("Sniffnet {APP_VERSION} - by Giuliano Bellini ")) + .size(FONT_SIZE_FOOTER) + .font(font_footer), + ) + .push(get_button_github(style)) + .push(Text::new(" ").font(font)); + + Container::new(footer_row) + .height(FillPortion(HEIGHT_FOOTER)) + .width(Length::Fill) + .align_y(Vertical::Center) + .align_x(Horizontal::Center) + .style(>::into( + StyleTuple(style, ElementType::Headers), + )) +} + +pub fn get_button_github(style: StyleType) -> Tooltip<'static, Message> { + let content = button( + Text::new('H'.to_string()) + .font(ICONS) + .size(24) + .horizontal_alignment(Horizontal::Center) + .vertical_alignment(Vertical::Center), + ) + .height(Length::Units(35)) + .width(Length::Units(35)) + .style(StyleTuple(style, ElementType::Standard).into()) + .on_press(Message::OpenGithub); + + Tooltip::new(content, "GitHub", Position::Right) + .font(get_font(style)) + .style(>::into( + StyleTuple(style, ElementType::Tooltip), + )) +} diff --git a/src/gui/components/header.rs b/src/gui/components/header.rs new file mode 100644 index 00000000..60e62a46 --- /dev/null +++ b/src/gui/components/header.rs @@ -0,0 +1,119 @@ +//! GUI upper header + +use crate::enums::element_type::ElementType; +use crate::enums::message::Message; +use crate::enums::overlay::MyOverlay; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::style_constants::{get_font, HEIGHT_HEADER, ICONS}; +use crate::utility::translations::{quit_analysis_translation, settings_translation}; +use crate::{Language, StyleType}; +use iced::alignment::{Horizontal, Vertical}; +use iced::widget::{button, horizontal_space, Container, Row, Text, Tooltip}; +use iced::Length::FillPortion; +use iced::{Alignment, Length}; +use iced_native::widget::tooltip::Position; + +pub fn get_header( + style: StyleType, + back_button: bool, + all_packets: u128, + language: Language, +) -> Container<'static, Message> { + let logo = Text::new('A'.to_string()) + .font(ICONS) + .horizontal_alignment(Horizontal::Center) + .size(95); + + Container::new( + Row::new() + .height(Length::Fill) + .width(Length::Fill) + .align_items(Alignment::Center) + .push(if back_button { + Container::new(get_button_reset(style, all_packets, language)) + .width(FillPortion(1)) + .align_x(Horizontal::Center) + } else { + Container::new(Row::new()) + .width(FillPortion(1)) + .align_x(Horizontal::Center) + }) + .push( + Container::new( + Row::new() + .height(Length::Fill) + .align_items(Alignment::Center) + .push(logo), + ) + .width(FillPortion(6)) + .height(Length::Fill) + .align_y(Vertical::Center) + .align_x(Horizontal::Center), + ) + .push( + Container::new(get_button_settings(style, language)) + .width(FillPortion(1)) + .align_x(Horizontal::Center), + ) + .push(horizontal_space(Length::Units(15))), + ) + .height(FillPortion(HEIGHT_HEADER)) + .align_y(Vertical::Center) + .width(Length::Fill) + .style(>::into( + StyleTuple(style, ElementType::Headers), + )) +} + +pub fn get_button_reset( + style: StyleType, + all_packets: u128, + language: Language, +) -> Tooltip<'static, Message> { + let content = button( + Text::new('C'.to_string()) + .font(ICONS) + .size(20) + .horizontal_alignment(Horizontal::Center) + .vertical_alignment(Vertical::Center), + ) + .padding(10) + .height(Length::Units(40)) + .width(Length::Units(60)) + .style(StyleTuple(style, ElementType::Standard).into()) + .on_press(if all_packets == 0 { + Message::Reset + } else { + Message::ShowModal(MyOverlay::Quit) + }); + + Tooltip::new( + content, + quit_analysis_translation(language), + Position::Right, + ) + .font(get_font(style)) + .style(>::into( + StyleTuple(style, ElementType::Tooltip), + )) +} + +pub fn get_button_settings(style: StyleType, language: Language) -> Tooltip<'static, Message> { + let content = button( + Text::new("a") + .font(ICONS) + .horizontal_alignment(Horizontal::Center) + .vertical_alignment(Vertical::Center), + ) + .padding(10) + .height(Length::Units(40)) + .width(Length::Units(60)) + .style(StyleTuple(style, ElementType::Standard).into()) + .on_press(Message::ShowModal(MyOverlay::SettingsNotifications)); + + Tooltip::new(content, settings_translation(language), Position::Left) + .font(get_font(style)) + .style(>::into( + StyleTuple(style, ElementType::Tooltip), + )) +} diff --git a/src/gui/components/mod.rs b/src/gui/components/mod.rs new file mode 100644 index 00000000..efaa4099 --- /dev/null +++ b/src/gui/components/mod.rs @@ -0,0 +1,5 @@ +pub mod footer; +pub mod header; +pub mod modal; +pub mod radio; +pub mod tab; diff --git a/src/gui/components/modal.rs b/src/gui/components/modal.rs new file mode 100644 index 00000000..456a258f --- /dev/null +++ b/src/gui/components/modal.rs @@ -0,0 +1,422 @@ +use crate::enums::element_type::ElementType; +use crate::enums::message::Message; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::style_constants::{get_font, get_font_headers, FONT_SIZE_TITLE}; +use crate::utility::translations::{ + ask_clear_all_translation, ask_quit_translation, clear_all_translation, hide_translation, + quit_analysis_translation, yes_translation, +}; +use crate::{Language, StyleType}; +use iced::alignment::{Alignment, Horizontal, Vertical}; +use iced::widget::{ + button, horizontal_space, vertical_space, Column, Container, Row, Text, Tooltip, +}; +use iced::{event, mouse, Color, Element, Event, Font, Length, Point, Rectangle, Size}; +use iced_native::widget::tooltip::Position; +use iced_native::widget::{self, Tree}; +use iced_native::{layout, overlay, renderer, Clipboard, Layout, Shell, Widget}; + +pub fn get_exit_overlay( + style: StyleType, + font: Font, + language: Language, +) -> Container<'static, Message> { + let row_buttons = Row::new().push( + button( + yes_translation(language) + .font(font) + .vertical_alignment(Vertical::Center) + .horizontal_alignment(Horizontal::Center), + ) + .padding(5) + .height(Length::Units(40)) + .width(Length::Units(80)) + .style(StyleTuple(style, ElementType::Alert).into()) + .on_press(Message::Reset), + ); + + let content = Column::new() + .align_items(Alignment::Center) + .width(Length::Fill) + .push(get_modal_header( + style, + language, + quit_analysis_translation(language), + )) + .push(vertical_space(Length::Units(20))) + .push(ask_quit_translation(language).font(font)) + .push(vertical_space(Length::Units(20))) + .push(row_buttons); + + Container::new(content) + .height(Length::Units(150)) + .width(Length::Units(450)) + .style(>::into( + StyleTuple(style, ElementType::Standard), + )) +} + +pub fn get_clear_all_overlay( + style: StyleType, + font: Font, + language: Language, +) -> Container<'static, Message> { + let row_buttons = Row::new().push( + button( + yes_translation(language) + .font(font) + .vertical_alignment(Vertical::Center) + .horizontal_alignment(Horizontal::Center), + ) + .padding(5) + .height(Length::Units(40)) + .width(Length::Units(80)) + .style(StyleTuple(style, ElementType::Alert).into()) + .on_press(Message::ClearAllNotifications), + ); + + let content = Column::new() + .align_items(Alignment::Center) + .width(Length::Fill) + .push(get_modal_header( + style, + language, + clear_all_translation(language), + )) + .push(vertical_space(Length::Units(20))) + .push(ask_clear_all_translation(language).font(font)) + .push(vertical_space(Length::Units(20))) + .push(row_buttons); + + Container::new(content) + .height(Length::Units(150)) + .width(Length::Units(450)) + .style(>::into( + StyleTuple(style, ElementType::Standard), + )) +} + +fn get_modal_header( + style: StyleType, + language: Language, + title: String, +) -> Container<'static, Message> { + Container::new( + Row::new() + .push(horizontal_space(Length::FillPortion(1))) + .push( + Text::new(title) + .font(get_font_headers(style)) + .size(FONT_SIZE_TITLE) + .width(Length::FillPortion(6)) + .horizontal_alignment(Horizontal::Center), + ) + .push( + Container::new( + Tooltip::new( + button( + Text::new("x") + .font(get_font(style)) + .horizontal_alignment(Horizontal::Center) + .size(15), + ) + .padding(2) + .height(Length::Units(20)) + .width(Length::Units(20)) + .style(StyleTuple(style, ElementType::Standard).into()) + .on_press(Message::HideModal(false)), + hide_translation(language), + Position::Right, + ) + .font(get_font(style)) + .style(>::into( + StyleTuple(style, ElementType::Tooltip), + )), + ) + .width(Length::FillPortion(1)) + .align_x(Horizontal::Center), + ), + ) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) + .height(Length::Units(40)) + .width(Length::Fill) + .style(>::into( + StyleTuple(style, ElementType::Headers), + )) +} + +/// A widget that centers a modal element over some base element +pub struct Modal<'a, Message, Renderer> { + base: Element<'a, Message, Renderer>, + modal: Element<'a, Message, Renderer>, + on_blur: Option, +} + +impl<'a, Message, Renderer> Modal<'a, Message, Renderer> { + /// Returns a new [`Modal`] + pub fn new( + base: impl Into>, + modal: impl Into>, + ) -> Self { + Self { + base: base.into(), + modal: modal.into(), + on_blur: None, + } + } + + /// Sets the message that will be produces when the background + /// of the [`Modal`] is pressed + pub fn on_blur(self, on_blur: Message) -> Self { + Self { + on_blur: Some(on_blur), + ..self + } + } +} + +impl<'a, Message, Renderer> Widget for Modal<'a, Message, Renderer> +where + Renderer: iced_native::Renderer, + Message: Clone, +{ + fn width(&self) -> Length { + self.base.as_widget().width() + } + + fn height(&self) -> Length { + self.base.as_widget().height() + } + + fn layout(&self, renderer: &Renderer, limits: &layout::Limits) -> layout::Node { + self.base.as_widget().layout(renderer, limits) + } + + fn draw( + &self, + state: &Tree, + renderer: &mut Renderer, + theme: &::Theme, + style: &renderer::Style, + layout: Layout<'_>, + cursor_position: Point, + viewport: &Rectangle, + ) { + self.base.as_widget().draw( + &state.children[0], + renderer, + theme, + style, + layout, + cursor_position, + viewport, + ); + } + + fn children(&self) -> Vec { + vec![Tree::new(&self.base), Tree::new(&self.modal)] + } + + fn diff(&self, tree: &mut Tree) { + tree.diff_children(&[&self.base, &self.modal]); + } + + fn operate( + &self, + state: &mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn widget::Operation, + ) { + self.base + .as_widget() + .operate(&mut state.children[0], layout, renderer, operation); + } + + fn on_event( + &mut self, + state: &mut Tree, + event: Event, + layout: Layout<'_>, + cursor_position: Point, + renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, Message>, + ) -> event::Status { + self.base.as_widget_mut().on_event( + &mut state.children[0], + event, + layout, + cursor_position, + renderer, + clipboard, + shell, + ) + } + + fn mouse_interaction( + &self, + state: &Tree, + layout: Layout<'_>, + cursor_position: Point, + viewport: &Rectangle, + renderer: &Renderer, + ) -> mouse::Interaction { + self.base.as_widget().mouse_interaction( + &state.children[0], + layout, + cursor_position, + viewport, + renderer, + ) + } + + fn overlay<'b>( + &'b mut self, + state: &'b mut Tree, + layout: Layout<'_>, + _renderer: &Renderer, + ) -> Option> { + Some(overlay::Element::new( + layout.position(), + Box::new(Overlay { + content: &mut self.modal, + tree: &mut state.children[1], + size: layout.bounds().size(), + on_blur: self.on_blur.clone(), + }), + )) + } +} + +struct Overlay<'a, 'b, Message, Renderer> { + content: &'b mut Element<'a, Message, Renderer>, + tree: &'b mut Tree, + size: Size, + on_blur: Option, +} + +impl<'a, 'b, Message, Renderer> overlay::Overlay + for Overlay<'a, 'b, Message, Renderer> +where + Renderer: iced_native::Renderer, + Message: Clone, +{ + fn layout(&self, renderer: &Renderer, _bounds: Size, position: Point) -> layout::Node { + let limits = layout::Limits::new(Size::ZERO, self.size) + .width(Length::Fill) + .height(Length::Fill); + + let mut child = self.content.as_widget().layout(renderer, &limits); + child.align(Alignment::Center, Alignment::Center, limits.max()); + + let mut node = layout::Node::with_children(self.size, vec![child]); + node.move_to(position); + + node + } + + fn draw( + &self, + renderer: &mut Renderer, + theme: &Renderer::Theme, + style: &renderer::Style, + layout: Layout<'_>, + cursor_position: Point, + ) { + renderer.fill_quad( + renderer::Quad { + bounds: layout.bounds(), + border_radius: renderer::BorderRadius::from(0.0), + border_width: 0.0, + border_color: Color::TRANSPARENT, + }, + Color { + a: 0.8, // background opacity + ..Color::BLACK + }, + ); + + self.content.as_widget().draw( + self.tree, + renderer, + theme, + style, + layout.children().next().unwrap(), + cursor_position, + &layout.bounds(), + ); + } + + fn operate( + &mut self, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn widget::Operation, + ) { + self.content.as_widget().operate( + self.tree, + layout.children().next().unwrap(), + renderer, + operation, + ); + } + + fn on_event( + &mut self, + event: Event, + layout: Layout<'_>, + cursor_position: Point, + renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, Message>, + ) -> event::Status { + let content_bounds = layout.children().next().unwrap().bounds(); + + if let Some(message) = self.on_blur.as_ref() { + if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) = &event { + if !content_bounds.contains(cursor_position) { + shell.publish(message.clone()); + return event::Status::Captured; + } + } + } + + self.content.as_widget_mut().on_event( + self.tree, + event, + layout.children().next().unwrap(), + cursor_position, + renderer, + clipboard, + shell, + ) + } + + fn mouse_interaction( + &self, + layout: Layout<'_>, + cursor_position: Point, + viewport: &Rectangle, + renderer: &Renderer, + ) -> mouse::Interaction { + self.content.as_widget().mouse_interaction( + self.tree, + layout.children().next().unwrap(), + cursor_position, + viewport, + renderer, + ) + } +} + +impl<'a, Message, Renderer> From> for Element<'a, Message, Renderer> +where + Renderer: 'a + iced_native::Renderer, + Message: 'a + Clone, +{ + fn from(modal: Modal<'a, Message, Renderer>) -> Self { + Element::new(modal) + } +} diff --git a/src/gui/components/radio.rs b/src/gui/components/radio.rs new file mode 100644 index 00000000..16ef1909 --- /dev/null +++ b/src/gui/components/radio.rs @@ -0,0 +1,279 @@ +use crate::enums::element_type::ElementType; +use crate::enums::message::Message; +use crate::enums::sound::Sound; +use crate::structs::notifications::{BytesNotification, FavoriteNotification, PacketsNotification}; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::countries::get_flag; +use crate::utility::style_constants::FONT_SIZE_SUBTITLE; +use crate::utility::translations::{ + ip_version_translation, relevant_connections_translation, sound_translation, + traffic_rate_translation, transport_protocol_translation, +}; +use crate::{ChartType, IpVersion, Language, ReportType, StyleType, TransProtocol}; +use iced::widget::{Column, Radio, Row, Text}; +use iced::{Alignment, Font, Length}; +use iced_native::widget::horizontal_space; + +pub fn ip_version_radios( + active: IpVersion, + font: Font, + style: StyleType, + language: Language, +) -> Column<'static, Message> { + let mut ret_val = Column::new().spacing(10).padding(0).push( + ip_version_translation(language) + .font(font) + .size(FONT_SIZE_SUBTITLE), + ); + for option in IpVersion::ALL { + ret_val = ret_val.push( + Radio::new( + option, + option.get_radio_label(language), + Some(active), + Message::IpVersionSelection, + ) + .font(font) + .size(15) + .style(>::into(StyleTuple( + style, + ElementType::Standard, + ))), + ); + } + ret_val +} + +pub fn transport_protocol_radios( + active: TransProtocol, + font: Font, + style: StyleType, + language: Language, +) -> Column<'static, Message> { + let mut ret_val = Column::new().spacing(10).push( + Text::new(transport_protocol_translation(language)) + .font(font) + .size(FONT_SIZE_SUBTITLE), + ); + for option in TransProtocol::ALL { + ret_val = ret_val.push( + Radio::new( + option, + option.get_radio_label(language), + Some(active), + Message::TransportProtocolSelection, + ) + .font(font) + .size(15) + .style(>::into(StyleTuple( + style, + ElementType::Standard, + ))), + ); + } + ret_val +} + +pub fn language_radios(active: Language, font: Font, style: StyleType) -> Column<'static, Message> { + let mut ret_val = Column::new().spacing(10); + for option in Language::ALL { + ret_val = ret_val.push( + Row::new() + .align_items(Alignment::Center) + .push( + Radio::new( + option, + option.get_radio_label(), + Some(active), + Message::LanguageSelection, + ) + .font(font) + .size(15) + .style(>::into(StyleTuple( + style, + ElementType::Standard, + ))), + ) + .push(horizontal_space(Length::Units(5))) + .push(get_flag(&format!("{option:?}"))), + ); + } + ret_val +} + +pub fn sound_packets_threshold_radios( + packets_notification: PacketsNotification, + font: Font, + style: StyleType, + language: Language, +) -> Row<'static, Message> { + let mut ret_val = Row::new() + .spacing(20) + .push(Text::new(sound_translation(language)).font(font)); + for option in Sound::ALL { + ret_val = ret_val.push( + Radio::new( + option, + option.get_radio_label(language), + Some(packets_notification.sound), + |value| { + Message::UpdatePacketsNotification( + PacketsNotification { + sound: value, + ..packets_notification + }, + value.ne(&Sound::None), + ) + }, + ) + .font(font) + .size(15) + .style(>::into(StyleTuple( + style, + ElementType::Standard, + ))), + ); + } + ret_val +} + +pub fn sound_bytes_threshold_radios( + bytes_notification: BytesNotification, + font: Font, + style: StyleType, + language: Language, +) -> Row<'static, Message> { + let mut ret_val = Row::new() + .spacing(20) + .push(Text::new(sound_translation(language)).font(font)); + for option in Sound::ALL { + ret_val = ret_val.push( + Radio::new( + option, + option.get_radio_label(language), + Some(bytes_notification.sound), + |value| { + Message::UpdateBytesNotification( + BytesNotification { + sound: value, + ..bytes_notification + }, + value.ne(&Sound::None), + ) + }, + ) + .font(font) + .size(15) + .style(>::into(StyleTuple( + style, + ElementType::Standard, + ))), + ); + } + ret_val +} + +pub fn sound_favorite_radios( + favorite_notification: FavoriteNotification, + font: Font, + style: StyleType, + language: Language, +) -> Row<'static, Message> { + let mut ret_val = Row::new() + .spacing(20) + .push(Text::new(sound_translation(language)).font(font)); + for option in Sound::ALL { + ret_val = ret_val.push( + Radio::new( + option, + option.get_radio_label(language), + Some(favorite_notification.sound), + |value| { + Message::UpdateFavoriteNotification( + FavoriteNotification { + sound: value, + ..favorite_notification + }, + value.ne(&Sound::None), + ) + }, + ) + .font(font) + .size(15) + .style(>::into(StyleTuple( + style, + ElementType::Standard, + ))), + ); + } + ret_val +} + +pub fn chart_radios( + active: ChartType, + font: Font, + style: StyleType, + language: Language, +) -> Row<'static, Message> { + let mut ret_val = Row::new() + .padding(15) + .spacing(20) + .align_items(Alignment::Center) + .push( + traffic_rate_translation(language) + .font(font) + .size(FONT_SIZE_SUBTITLE), + ); + for option in ChartType::ALL { + ret_val = ret_val.push( + Radio::new( + option, + option.get_radio_label(language), + Some(active), + Message::ChartSelection, + ) + .font(font) + .size(15) + .style(>::into(StyleTuple( + style, + ElementType::Standard, + ))), + ); + } + ret_val +} + +pub fn report_radios( + active: ReportType, + font: Font, + style: StyleType, + language: Language, +) -> Row<'static, Message> { + let mut ret_val = Row::new() + .padding(15) + .spacing(20) + .align_items(Alignment::Center) + .push( + relevant_connections_translation(language) + .font(font) + .size(FONT_SIZE_SUBTITLE), + ); + for option in ReportType::ALL { + ret_val = ret_val.push( + Radio::new( + option, + option.get_radio_label(language), + Some(active), + Message::ReportSelection, + ) + .font(font) + .size(15) + .style(>::into(StyleTuple( + style, + ElementType::Standard, + ))), + ); + } + ret_val = ret_val.push(horizontal_space(Length::Units(120))); + ret_val +} diff --git a/src/gui/components/tab.rs b/src/gui/components/tab.rs new file mode 100644 index 00000000..81accf2f --- /dev/null +++ b/src/gui/components/tab.rs @@ -0,0 +1,103 @@ +//! Tab buttons to be used in the various pages just under the header + +use crate::enums::element_type::ElementType; +use crate::enums::message::Message; +use crate::enums::overlay::MyOverlay; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::style_constants::{get_font, FONT_SIZE_SUBTITLE, ICONS}; +use crate::{Language, RunningPage, StyleType}; +use iced::widget::{button, horizontal_space, Button, Row, Text}; +use iced::{alignment, Alignment, Length}; + +pub fn get_settings_tabs( + labels: [MyOverlay; 3], + icons: &[&str], + actions: &[Message], + active: MyOverlay, + style: StyleType, + language: Language, +) -> Row<'static, Message> { + let mut tabs = Row::new() + .width(Length::Fill) + .align_items(Alignment::Center); + + for (i, label) in labels.iter().enumerate() { + let active = label.eq(&active); + tabs = tabs.push(new_tab( + (*label).get_tab_label(language).to_string(), + (*icons.get(i).unwrap()).to_string(), + actions.get(i).unwrap().clone(), + active, + style, + )); + } + tabs +} + +pub fn get_pages_tabs( + labels: [RunningPage; 2], + icons: &[&str], + actions: &[Message], + active: RunningPage, + style: StyleType, + language: Language, +) -> Row<'static, Message> { + let mut tabs = Row::new() + .width(Length::Fill) + .align_items(Alignment::Center); + + for (i, label) in labels.iter().enumerate() { + let active = label.eq(&active); + tabs = tabs.push(new_tab( + (*label).get_tab_label(language).to_string(), + (*icons.get(i).unwrap()).to_string(), + actions.get(i).unwrap().clone(), + active, + style, + )); + } + tabs +} + +fn new_tab( + label: String, + icon: String, + action: Message, + active: bool, + style: StyleType, +) -> Button<'static, Message> { + let content = Row::new() + .align_items(Alignment::Center) + .push(horizontal_space(Length::FillPortion(1))) + .push( + Text::new(icon) + .font(ICONS) + .size(15) + .horizontal_alignment(alignment::Horizontal::Center) + .vertical_alignment(alignment::Vertical::Center), + ) + .push( + Text::new(label) + .font(get_font(style)) + .size(FONT_SIZE_SUBTITLE) + .horizontal_alignment(alignment::Horizontal::Center) + .vertical_alignment(alignment::Vertical::Center), + ) + .push(horizontal_space(Length::FillPortion(1))); + + button(content) + .height(Length::Units(35)) + .width(Length::FillPortion(1)) + .style( + StyleTuple( + style, + if active { + ElementType::TabActive + } else { + ElementType::TabInactive + }, + ) + .into(), + ) + .on_press(action) +} diff --git a/src/gui/gui_initial_page.rs b/src/gui/gui_initial_page.rs deleted file mode 100644 index 4f2e6d49..00000000 --- a/src/gui/gui_initial_page.rs +++ /dev/null @@ -1,350 +0,0 @@ -//! Module defining the initial page of the application. -//! -//! It contains elements to select network adapter and traffic filters. - -use iced::alignment::{Horizontal, Vertical}; -use iced::Length::FillPortion; -use iced::{ - alignment, Alignment, Button, Column, Container, Length, PickList, Radio, Row, Scrollable, Text, -}; -use pcap::Device; - -use crate::enums::message::Message; -use crate::gui::style::{ - icon_sun_moon, logo_glyph, APP_VERSION, COURIER_PRIME, COURIER_PRIME_BOLD, - COURIER_PRIME_BOLD_ITALIC, COURIER_PRIME_ITALIC, FONT_SIZE_FOOTER, FONT_SIZE_SUBTITLE, - FONT_SIZE_TITLE, HEIGHT_BODY, HEIGHT_FOOTER, HEIGHT_HEADER, ICONS, -}; -use crate::structs::sniffer::Sniffer; -use crate::{AppProtocol, IpVersion, StyleType, TransProtocol}; - -/// Computes the body of gui initial page -pub fn initial_page(sniffer: &mut Sniffer) -> Column { - let font = if sniffer.style == StyleType::Day { - COURIER_PRIME_BOLD - } else { - COURIER_PRIME - }; - let font_footer = if sniffer.style == StyleType::Day { - COURIER_PRIME_ITALIC - } else { - COURIER_PRIME_BOLD_ITALIC - }; - let headers_style = if sniffer.style == StyleType::Day { - StyleType::HeadersDay - } else { - StyleType::HeadersNight - }; - let logo = logo_glyph().size(90); - - let button_style = Button::new( - &mut sniffer.mode, - icon_sun_moon(sniffer.style).horizontal_alignment(alignment::Horizontal::Center), - ) - .padding(10) - .height(Length::Units(40)) - .width(Length::Units(60)) - .style(sniffer.style) - .on_press(Message::Style); - - let header = Container::new( - Row::new() - .height(Length::Fill) - .width(Length::Fill) - .align_items(Alignment::Center) - .push( - Container::new(Row::new()) - .width(Length::FillPortion(1)) - .width(Length::FillPortion(1)) - .align_x(Horizontal::Center), - ) - .push( - Container::new( - Row::new() - .height(Length::Fill) - .align_items(Alignment::Center) - .push(logo), - ) - .width(Length::FillPortion(6)) - .height(Length::Fill) - .align_y(Vertical::Center) - .align_x(Horizontal::Center), - ) - .push( - Container::new(button_style) - .width(Length::FillPortion(1)) - .align_x(Horizontal::Center), - ), - ) - .height(Length::FillPortion(HEIGHT_HEADER)) - .align_y(Vertical::Center) - .width(Length::Fill) - .style(headers_style); - - let button_start = Button::new( - &mut sniffer.start, - Text::new("Run!") - .font(font) - .size(FONT_SIZE_TITLE) - .vertical_alignment(alignment::Vertical::Center) - .horizontal_alignment(alignment::Horizontal::Center), - ) - .padding(10) - .height(Length::Units(80)) - .width(Length::Units(160)) - .style(sniffer.style) - .on_press(Message::Start); - - let mut dev_str_list = vec![]; - for dev in Device::list().expect("Error retrieving device list\r\n") { - let mut dev_str = "\n".to_string(); - let name = dev.name; - match dev.desc { - None => { - dev_str.push_str(&name); - } - Some(description) => { - #[cfg(not(target_os = "windows"))] - dev_str.push_str(&format!("{name}\n")); - dev_str.push_str(&description); - } - } - let num_addresses = dev.addresses.len(); - match num_addresses { - 0 => {} - 1 => { - dev_str.push_str("\nAddress:"); - } - _ => { - dev_str.push_str("\nAddresses:"); - } - } - - for addr in dev.addresses { - let address_string = addr.addr.to_string(); - dev_str.push_str(&format!("\n {address_string}")); - } - dev_str.push_str("\n "); - dev_str_list.push((name, dev_str)); - } - - let col_adapter = Column::new() - .padding(10) - .spacing(5) - .height(Length::Fill) - .width(Length::FillPortion(4)) - .push( - Text::new("Select network adapter to inspect") - .font(font) - .size(FONT_SIZE_TITLE), - ) - .push( - dev_str_list.iter().fold( - Scrollable::new(&mut sniffer.scroll_adapters) - .style(sniffer.style) - .padding(13) - .spacing(5), - |scroll_adapters, adapter| { - scroll_adapters.push( - Container::new( - Radio::new( - &adapter.0, - &adapter.1, - Some(&sniffer.device.clone().lock().unwrap().name), - |name| Message::AdapterSelection(name.to_string()), - ) - .font(font) - .size(15) - .width(Length::Fill) - .style(sniffer.style), - ) - .padding(10) - .style(StyleType::BorderedRound), - ) - }, - ), - ); - - let col_space = Column::new() - .padding(20) - .spacing(10) - .width(Length::FillPortion(1)); - - let filtri = sniffer.filters.lock().unwrap(); - let ip_active = filtri.ip; - let col_ip_radio = Column::new() - .spacing(10) - .push(Text::new("IP version").font(font).size(FONT_SIZE_SUBTITLE)) - .push( - Radio::new( - IpVersion::IPv4, - "IPv4", - Some(ip_active), - Message::IpVersionSelection, - ) - .width(Length::Fill) - .font(font) - .size(15) - .style(sniffer.style), - ) - .push( - Radio::new( - IpVersion::IPv6, - "IPv6", - Some(ip_active), - Message::IpVersionSelection, - ) - .width(Length::Fill) - .font(font) - .size(15) - .style(sniffer.style), - ) - .push( - Radio::new( - IpVersion::Other, - "both", - Some(ip_active), - Message::IpVersionSelection, - ) - .width(Length::Fill) - .font(font) - .size(15) - .style(sniffer.style), - ); - let col_ip = Column::new() - .spacing(10) - .width(Length::FillPortion(1)) - .push(col_ip_radio); - - let transport_active = filtri.transport; - let col_transport_radio = Column::new() - .spacing(10) - .push( - Text::new("Transport protocol") - .font(font) - .size(FONT_SIZE_SUBTITLE), - ) - .push( - Radio::new( - TransProtocol::TCP, - "TCP", - Some(transport_active), - Message::TransportProtocolSelection, - ) - .width(Length::Fill) - .font(font) - .size(15) - .style(sniffer.style), - ) - .push( - Radio::new( - TransProtocol::UDP, - "UDP", - Some(transport_active), - Message::TransportProtocolSelection, - ) - .width(Length::Fill) - .font(font) - .size(15) - .style(sniffer.style), - ) - .push( - Radio::new( - TransProtocol::Other, - "both", - Some(transport_active), - Message::TransportProtocolSelection, - ) - .width(Length::Fill) - .font(font) - .size(15) - .style(sniffer.style), - ); - let col_transport = Column::new() - .align_items(Alignment::Center) - .spacing(10) - .width(Length::FillPortion(2)) - .push(col_transport_radio) - .push(Row::new().height(Length::FillPortion(2))) - .push(button_start) - .push(Row::new().height(Length::FillPortion(1))); - - let app_active = filtri.application; - let picklist_app = PickList::new( - &mut sniffer.app, - &AppProtocol::ALL[..], - Some(app_active), - Message::AppProtocolSelection, - ) - .font(font) - .placeholder("Select application protocol") - .style(sniffer.style); - let col_app = Column::new() - .width(Length::FillPortion(2)) - .spacing(10) - .push( - iced::Text::new("Application protocol") - .font(font) - .size(FONT_SIZE_SUBTITLE), - ) - .push(picklist_app); - - let filters = Column::new() - .width(Length::FillPortion(6)) - .padding(10) - .spacing(15) - .push( - Row::new().push( - Text::new("Select filters to be applied on network traffic") - .font(font) - .size(FONT_SIZE_TITLE), - ), - ) - .push( - Row::new() - .height(Length::FillPortion(3)) - .push(col_ip) - .push(col_transport) - .push(col_app), - ); - - let body = Row::new() - .height(Length::FillPortion(HEIGHT_BODY)) - .push(col_adapter) - .push(col_space) - .push(filters); - - let button_github = Button::new( - &mut sniffer.git, - Text::new('H'.to_string()) - .font(ICONS) - .size(24) - .horizontal_alignment(alignment::Horizontal::Center) - .vertical_alignment(alignment::Vertical::Center), - ) - .height(Length::Units(35)) - .width(Length::Units(35)) - .style(sniffer.style) - .on_press(Message::OpenGithub); - let footer_row = Row::new() - .align_items(Alignment::Center) - .push( - Text::new(format!("Sniffnet {APP_VERSION} - by Giuliano Bellini ")) - .size(FONT_SIZE_FOOTER) - .font(font_footer), - ) - .push(button_github) - .push(Text::new(" ").font(font)); - let footer = Container::new(footer_row) - .width(Length::Fill) - .height(FillPortion(HEIGHT_FOOTER)) - .align_y(Vertical::Center) - .align_x(Horizontal::Center) - .style(headers_style); - - Column::new() - .spacing(10) - .push(header) - .push(body) - .push(footer) -} diff --git a/src/gui/gui_run_page.rs b/src/gui/gui_run_page.rs deleted file mode 100644 index b27ce21f..00000000 --- a/src/gui/gui_run_page.rs +++ /dev/null @@ -1,458 +0,0 @@ -//! Module defining the run page of the application. -//! -//! It contains elements to display traffic statistics: charts, detailed connections data -//! and overall statistics about the filtered traffic. - -use std::cmp::min; - -use iced::alignment::{Horizontal, Vertical}; -use iced::Length::FillPortion; -use iced::{alignment, Alignment, Button, Column, Container, Length, Radio, Row, Scrollable, Text}; -use thousands::Separable; - -use crate::enums::message::Message; -use crate::gui::style::{ - icon_sun_moon, logo_glyph, APP_VERSION, COURIER_PRIME, COURIER_PRIME_BOLD, - COURIER_PRIME_BOLD_ITALIC, COURIER_PRIME_ITALIC, FONT_SIZE_FOOTER, FONT_SIZE_SUBTITLE, - HEIGHT_BODY, HEIGHT_FOOTER, HEIGHT_HEADER, ICONS, -}; -use crate::structs::address_port_pair::AddressPortPair; -use crate::structs::info_address_port_pair::InfoAddressPortPair; -use crate::structs::sniffer::Sniffer; -use crate::utility::get_formatted_strings::{ - get_active_filters_string, get_active_filters_string_nobr, get_app_count_string, - get_connection_color, get_formatted_bytes_string, get_percentage_string, -}; -use crate::{AppProtocol, ChartType, ReportType, StyleType}; - -/// Computes the body of gui run page -pub fn run_page(sniffer: &mut Sniffer) -> Column { - let font = if sniffer.style == StyleType::Day { - COURIER_PRIME_BOLD - } else { - COURIER_PRIME - }; - let font_footer = if sniffer.style == StyleType::Day { - COURIER_PRIME_ITALIC - } else { - COURIER_PRIME_BOLD_ITALIC - }; - let headers_style = if sniffer.style == StyleType::Day { - StyleType::HeadersDay - } else { - StyleType::HeadersNight - }; - let logo = logo_glyph().size(90); - - let button_style = Button::new( - &mut sniffer.mode, - icon_sun_moon(sniffer.style).horizontal_alignment(alignment::Horizontal::Center), - ) - .padding(10) - .height(Length::Units(40)) - .width(Length::Units(60)) - .style(sniffer.style) - .on_press(Message::Style); - - let button_reset = Button::new( - &mut sniffer.reset, - Text::new('C'.to_string()) - .font(ICONS) - .size(20) - .horizontal_alignment(alignment::Horizontal::Center) - .vertical_alignment(alignment::Vertical::Center), - ) - .padding(10) - .height(Length::Units(40)) - .width(Length::Units(60)) - .style(sniffer.style) - .on_press(Message::Reset); - - let header = Container::new( - Row::new() - .height(Length::Fill) - .width(Length::Fill) - .align_items(Alignment::Center) - .push( - Container::new(button_reset) - .width(Length::FillPortion(1)) - .width(Length::FillPortion(1)) - .align_x(Horizontal::Center), - ) - .push( - Container::new(Row::new().align_items(Alignment::Center).push(logo)) - .width(Length::FillPortion(6)) - .height(Length::Fill) - .align_x(Horizontal::Center) - .align_y(Vertical::Center), - ) - .push( - Container::new(button_style) - .width(Length::FillPortion(1)) - .align_x(Horizontal::Center), - ), - ) - .height(Length::FillPortion(HEIGHT_HEADER)) - .width(Length::Fill) - .style(headers_style); - - let button_report = Button::new( - &mut sniffer.report, - Text::new("Open full report") - .font(font) - .horizontal_alignment(alignment::Horizontal::Center) - .vertical_alignment(alignment::Vertical::Center), - ) - .padding(10) - .height(Length::Units(85)) - .width(Length::Units(75)) - .style(sniffer.style) - .on_press(Message::OpenReport); - - let runtime_data_lock = sniffer.runtime_data.lock().unwrap(); - let observed = runtime_data_lock.all_packets; - let filtered = runtime_data_lock.tot_sent_packets + runtime_data_lock.tot_received_packets; - let observed_bytes = runtime_data_lock.all_bytes; - let filtered_bytes = runtime_data_lock.tot_sent_bytes + runtime_data_lock.tot_received_bytes; - let app_protocols = runtime_data_lock.app_protocols.clone(); - drop(runtime_data_lock); - let filtered_bytes_string = get_formatted_bytes_string(filtered_bytes as u128); - - let mut body = Column::new() - .height(Length::FillPortion(HEIGHT_BODY)) - .width(Length::Fill) - .padding(10) - .spacing(10) - .align_items(Alignment::Center); - - if sniffer.pcap_error.lock().unwrap().is_none() { - // NO pcap error detected - - match (observed, filtered) { - (0, 0) => { - //no packets observed at all - if sniffer.waiting.len() > 2 { - sniffer.waiting = "".to_string(); - } - sniffer.waiting = ".".repeat(sniffer.waiting.len() + 1); - let adapter_name = &*sniffer.device.clone().lock().unwrap().name.clone(); - let (icon_text, nothing_to_see_text) = if !sniffer - .device - .lock() - .unwrap() - .addresses - .is_empty() - { - (Text::new(sniffer.waiting.len().to_string()).font(ICONS).size(60), - Text::new(format!("No traffic has been observed yet. Waiting for network packets...\n\n\ - Network adapter: {adapter_name}\n\n\ - Are you sure you are connected to the internet and you have selected the right adapter?")).font(font)) - } else { - (Text::new('T'.to_string()).font(ICONS).size(60), - Text::new(format!("No traffic can be observed because the adapter you selected has no active addresses...\n\n\ - Network adapter: {adapter_name}\n\n\ - If you are sure you are connected to the internet, try choosing a different adapter.")).font(font)) - }; - body = body - .push(Row::new().height(Length::FillPortion(1))) - .push(icon_text) - .push(nothing_to_see_text) - .push(Text::new(sniffer.waiting.clone()).font(font).size(50)) - .push(Row::new().height(Length::FillPortion(2))); - } - - (observed, 0) => { - //no packets have been filtered but some have been observed - if sniffer.waiting.len() > 2 { - sniffer.waiting = "".to_string(); - } - sniffer.waiting = ".".repeat(sniffer.waiting.len() + 1); - - let tot_packets_text = Text::new(format!("Total intercepted packets: {}\n\n\ - Filtered packets: 0\n\n\ - Some packets have been intercepted, but still none has been selected according to the filters you specified...\n\n{}", - observed.separate_with_spaces(), get_active_filters_string_nobr(sniffer.filters.clone()))).font(font); - - body = body - .push(Row::new().height(Length::FillPortion(1))) - .push(Text::new('V'.to_string()).font(ICONS).size(60)) - .push(tot_packets_text) - .push(Text::new(sniffer.waiting.clone()).font(font).size(50)) - .push(Row::new().height(Length::FillPortion(2))); - } - - (observed, filtered) => { - //observed > filtered > 0 || observed = filtered > 0 - - let active_radio_chart = sniffer.chart_type; - let row_radio_chart = Row::new() - .padding(15) - .spacing(10) - .push( - Text::new("Plotted data: ") - .size(FONT_SIZE_SUBTITLE) - .font(font), - ) - .push( - Radio::new( - ChartType::Packets, - "packets per second", - Some(active_radio_chart), - Message::ChartSelection, - ) - .width(Length::Units(220)) - .font(font) - .size(15) - .style(sniffer.style), - ) - .push( - Radio::new( - ChartType::Bytes, - "bytes per second", - Some(active_radio_chart), - Message::ChartSelection, - ) - .width(Length::Units(220)) - .font(font) - .size(15) - .style(sniffer.style), - ); - - let col_chart = Container::new( - Column::new().push(row_radio_chart).push( - sniffer - .traffic_chart - .view(sniffer.style, sniffer.chart_type), - ), - ) - .width(Length::FillPortion(2)) - .align_x(Horizontal::Center) - .align_y(Vertical::Center) - .style(StyleType::BorderedRound); - - let mut col_packets = Column::new() - .width(Length::FillPortion(1)) - .padding(10) - //.push(iced::Text::new(std::env::current_dir().unwrap().to_str().unwrap()).font(font)) - .push(Text::new(get_active_filters_string(sniffer.filters.clone())).font(font)) - .push(Text::new(" ")) - .push( - Text::new(format!( - "Filtered packets:\n {} ({} of the total)", - filtered.separate_with_spaces(), - get_percentage_string(observed, filtered) - )) - .font(font), - ) - .push(Text::new(" ")) - .push( - Text::new(format!( - "Filtered bytes:\n {} ({} of the total)", - filtered_bytes_string, - get_percentage_string(observed_bytes, filtered_bytes) - )) - .font(font), - ); - if sniffer - .filters - .lock() - .unwrap() - .application - .eq(&AppProtocol::Other) - { - col_packets = col_packets - .push(Text::new(" ")) - .push(Text::new("Filtered packets per application protocol:").font(font)) - .push( - Scrollable::new(&mut sniffer.scroll_packets) - .style(sniffer.style) - .push( - Text::new(get_app_count_string( - app_protocols, - filtered as u128, - )) - .font(font), - ), - ); - } - - let active_radio_report = sniffer.report_type; - let row_radio_report = Row::new() - .padding(10) - .push( - Text::new("Relevant connections: ") - .size(FONT_SIZE_SUBTITLE) - .font(font), - ) - .push( - Radio::new( - ReportType::MostRecent, - "most recent", - Some(active_radio_report), - Message::ReportSelection, - ) - .width(Length::Units(200)) - .font(font) - .size(15) - .style(sniffer.style), - ) - .push( - Radio::new( - ReportType::MostPackets, - "most packets", - Some(active_radio_report), - Message::ReportSelection, - ) - .width(Length::Units(200)) - .font(font) - .size(15) - .style(sniffer.style), - ) - .push( - Radio::new( - ReportType::MostBytes, - "most bytes", - Some(active_radio_report), - Message::ReportSelection, - ) - .width(Length::Units(200)) - .font(font) - .size(15) - .style(sniffer.style), - ); - - let sniffer_lock = sniffer.info_traffic.lock().unwrap(); - let mut sorted_vec: Vec<(&AddressPortPair, &InfoAddressPortPair)> = - sniffer_lock.map.iter().collect(); - match active_radio_report { - ReportType::MostRecent => { - sorted_vec - .sort_by(|&(_, a), &(_, b)| b.final_timestamp.cmp(&a.final_timestamp)); - } - ReportType::MostPackets => { - sorted_vec.sort_by(|&(_, a), &(_, b)| { - b.transmitted_packets.cmp(&a.transmitted_packets) - }); - } - ReportType::MostBytes => { - sorted_vec.sort_by(|&(_, a), &(_, b)| { - b.transmitted_bytes.cmp(&a.transmitted_bytes) - }); - } - } - let n_entry = min(sorted_vec.len(), 15); - let mut col_report = Column::new() - .height(Length::Fill) - .push(row_radio_report) - .push(Text::new(" ")) - .push(iced::Text::new(" Src IP address Src port Dst IP address Dst port Layer 4 Layer 7 Packets Bytes ").font(font)) - .push(iced::Text::new("---------------------------------------------------------------------------------------------------------------").font(font)) - ; - let mut scroll_report = - Scrollable::new(&mut sniffer.scroll_report).style(sniffer.style); - for i in 0..n_entry { - let key_val = sorted_vec.get(i).unwrap(); - let entry_color = get_connection_color(key_val.1.traffic_type); - scroll_report = scroll_report.push( - iced::Text::new(format!( - "{}{}", - key_val.0.print_gui(), - key_val.1.print_gui() - )) - .color(entry_color) - .font(COURIER_PRIME_BOLD), - ); - } - col_report = col_report.push(scroll_report); - drop(sniffer_lock); - let col_open_report = Container::new(button_report) - .width(Length::Fill) - .height(Length::Fill) - .align_x(Horizontal::Center) - .align_y(Vertical::Center); - let row_report = Row::new() - .spacing(10) - .height(Length::FillPortion(2)) - .width(Length::Fill) - .align_items(Alignment::Start) - .push( - Container::new(col_report) - .padding(10) - .height(Length::Fill) - .style(StyleType::BorderedRound), - ) - .push(col_open_report); - - body = body - .push( - Row::new() - .spacing(10) - .height(Length::FillPortion(3)) - .push(col_chart) - .push( - Container::new(col_packets) - .padding(10) - .height(Length::Fill) - .style(StyleType::BorderedRound), - ), - ) - .push(row_report); - } - } - } else { - // pcap threw an ERROR! - let err_string = sniffer.pcap_error.lock().unwrap().clone().unwrap(); - - if sniffer.waiting.len() > 2 { - sniffer.waiting = "".to_string(); - } - sniffer.waiting = ".".repeat(sniffer.waiting.len() + 1); - - let error_text = Text::new(format!( - "An error occurred! \n\n\ - {err_string}", - )) - .font(font); - - body = body - .push(Row::new().height(Length::FillPortion(1))) - .push(Text::new('U'.to_string()).font(ICONS).size(60)) - .push(error_text) - .push(Text::new(sniffer.waiting.clone()).font(font).size(50)) - .push(Row::new().height(Length::FillPortion(2))); - } - - let button_github = Button::new( - &mut sniffer.git, - Text::new('H'.to_string()) - .font(ICONS) - .size(24) - .horizontal_alignment(alignment::Horizontal::Center) - .vertical_alignment(alignment::Vertical::Center), - ) - .height(Length::Units(35)) - .width(Length::Units(35)) - .style(sniffer.style) - .on_press(Message::OpenGithub); - let footer_row = Row::new() - .align_items(Alignment::Center) - .push( - Text::new(format!("Sniffnet {APP_VERSION} - by Giuliano Bellini ")) - .size(FONT_SIZE_FOOTER) - .font(font_footer), - ) - .push(button_github) - .push(Text::new(" ").font(font)); - let footer = Container::new(footer_row) - .width(Length::Fill) - .height(FillPortion(HEIGHT_FOOTER)) - .align_y(Vertical::Center) - .align_x(Horizontal::Center) - .style(headers_style); - - Column::new() - .spacing(10) - .push(header) - .push(body) - .push(footer) -} diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 9efe8a36..289d0e0d 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -1,4 +1,4 @@ pub mod app; -pub mod gui_initial_page; -pub mod gui_run_page; -pub mod style; +pub mod components; +pub mod pages; +pub mod styles; diff --git a/src/gui/pages/initial_page.rs b/src/gui/pages/initial_page.rs new file mode 100644 index 00000000..ed0b7b6a --- /dev/null +++ b/src/gui/pages/initial_page.rs @@ -0,0 +1,205 @@ +//! Module defining the initial page of the application. +//! +//! It contains elements to select network adapter and traffic filters. + +use iced::widget::{ + button, horizontal_space, vertical_space, Column, Container, PickList, Radio, Row, Scrollable, + Text, Tooltip, +}; +use iced::Length::FillPortion; +use iced::{alignment, Alignment, Font, Length}; +use iced_native::widget::tooltip::Position; +use pcap::Device; + +use crate::enums::element_type::ElementType; +use crate::enums::message::Message; +use crate::gui::components::radio::{ip_version_radios, transport_protocol_radios}; +use crate::structs::sniffer::Sniffer; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::style_constants::{ + get_font, FONT_SIZE_SUBTITLE, FONT_SIZE_TITLE, HEIGHT_BODY, ICONS, +}; +use crate::utility::translations::{ + address_translation, addresses_translation, application_protocol_translation, + choose_adapters_translation, select_filters_translation, start_translation, +}; +use crate::{AppProtocol, Language, StyleType}; + +/// Computes the body of gui initial page +pub fn initial_page(sniffer: &Sniffer) -> Container { + let font = get_font(sniffer.style); + + let col_adapter = get_col_adapter(sniffer, font); + + let ip_active = sniffer.filters.ip; + let col_ip_radio = ip_version_radios(ip_active, font, sniffer.style, sniffer.language); + let col_ip = Column::new() + .spacing(10) + .width(FillPortion(1)) + .push(col_ip_radio); + + let transport_active = sniffer.filters.transport; + let col_transport_radio = + transport_protocol_radios(transport_active, font, sniffer.style, sniffer.language); + let col_transport = Column::new() + .align_items(Alignment::Center) + .spacing(10) + .width(FillPortion(2)) + .push(col_transport_radio) + .push(vertical_space(FillPortion(2))) + .push(get_button_start(sniffer.style, sniffer.language)) + .push(vertical_space(FillPortion(1))); + + let app_active = sniffer.filters.application; + let picklist_app = PickList::new( + &AppProtocol::ALL[..], + Some(app_active), + Message::AppProtocolSelection, + ) + .font(font) + .style(>::into( + StyleTuple(sniffer.style, ElementType::Standard), + )); + let col_app = Column::new() + .width(FillPortion(1)) + .spacing(10) + .push( + Text::new(application_protocol_translation(sniffer.language)) + .font(font) + .size(FONT_SIZE_SUBTITLE), + ) + .push(picklist_app); + + let filters = Column::new() + .width(FillPortion(6)) + .padding(10) + .spacing(15) + .push( + Row::new().push( + select_filters_translation(sniffer.language) + .font(font) + .size(FONT_SIZE_TITLE), + ), + ) + .push( + Row::new() + .spacing(10) + .height(FillPortion(3)) + .push(col_ip) + .push(col_transport) + .push(col_app), + ); + + let body = Column::new().push(vertical_space(Length::Units(5))).push( + Row::new() + .push(col_adapter) + .push(horizontal_space(Length::Units(30))) + .push(filters), + ); + + Container::new(body) + .height(FillPortion(HEIGHT_BODY)) + .style(>::into( + StyleTuple(sniffer.style, ElementType::Standard), + )) +} + +pub fn get_button_start(style: StyleType, language: Language) -> Tooltip<'static, Message> { + let content = button( + Text::new("S") + .font(ICONS) + .size(FONT_SIZE_TITLE) + .horizontal_alignment(alignment::Horizontal::Center) + .vertical_alignment(alignment::Vertical::Center), + ) + .padding(10) + .height(Length::Units(80)) + .width(Length::Units(160)) + .style(StyleTuple(style, ElementType::Standard).into()) + .on_press(Message::Start); + + Tooltip::new(content, start_translation(language), Position::Top) + .gap(5) + .font(get_font(style)) + .style(>::into( + StyleTuple(style, ElementType::Tooltip), + )) +} + +fn get_col_adapter(sniffer: &Sniffer, font: Font) -> Column { + let mut dev_str_list = vec![]; + for dev in Device::list().expect("Error retrieving device list\r\n") { + let mut dev_str = "\n".to_string(); + let name = dev.name; + match dev.desc { + None => { + dev_str.push_str(&name); + } + Some(description) => { + #[cfg(not(target_os = "windows"))] + dev_str.push_str(&format!("{name}\n")); + dev_str.push_str(&description); + } + } + let num_addresses = dev.addresses.len(); + match num_addresses { + 0 => {} + 1 => { + dev_str.push_str(address_translation(sniffer.language)); + } + _ => { + dev_str.push_str(addresses_translation(sniffer.language)); + } + } + + for addr in dev.addresses { + let address_string = addr.addr.to_string(); + dev_str.push_str(&format!("\n {address_string}")); + } + dev_str.push_str("\n "); + dev_str_list.push((name, dev_str)); + } + + Column::new() + .padding(10) + .spacing(5) + .height(Length::Fill) + .width(FillPortion(4)) + .push( + choose_adapters_translation(sniffer.language) + .font(font) + .size(FONT_SIZE_TITLE), + ) + .push( + Scrollable::new(dev_str_list.iter().fold( + Column::new().padding(13).spacing(5), + |scroll_adapters, adapter| { + let name = &adapter.0; + scroll_adapters.push( + Container::new( + Radio::new(name, &adapter.1, Some(&sniffer.device.name), |name| { + Message::AdapterSelection(name.to_string()) + }) + .font(font) + .size(15) + .width(Length::Fill) + .style(>::into( + StyleTuple(sniffer.style, ElementType::Standard), + )), + ) + .padding(10) + .style(>::into( + StyleTuple(sniffer.style, ElementType::BorderedRound), + )), + ) + }, + )) + .style(>::into( + StyleTuple(sniffer.style, ElementType::Standard), + )), + ) +} diff --git a/src/gui/pages/inspect_page.rs b/src/gui/pages/inspect_page.rs new file mode 100644 index 00000000..bf88c49a --- /dev/null +++ b/src/gui/pages/inspect_page.rs @@ -0,0 +1,47 @@ +// use crate::enums::element_type::ElementType; +// use crate::enums::message::Message; +// use crate::gui::components::tab::get_pages_tabs; +// use crate::structs::style_tuple::StyleTuple; +// use crate::utility::style_constants::HEIGHT_BODY; +// use crate::{RunningPage, Sniffer}; +// use iced::widget::{Column, Container}; +// use iced::Length::FillPortion; +// use iced::{Alignment, Length}; +// +// /// Computes the body of gui inspect page +// pub fn inspect_page(sniffer: &Sniffer) -> Container { +// //let font = get_font(sniffer.style); +// +// let body = Column::new() +// .width(Length::Fill) +// .padding(5) +// .spacing(5) +// .align_items(Alignment::Center); +// +// let mut tab_and_body = Column::new().height(FillPortion(HEIGHT_BODY)); +// +// let tabs = get_pages_tabs( +// [ +// RunningPage::Overview, +// RunningPage::Inspect, +// RunningPage::Notifications, +// ], +// &["d ", "5 ", "7 "], +// &[ +// Message::ChangeRunningPage(RunningPage::Overview), +// Message::TickInit, +// Message::ChangeRunningPage(RunningPage::Notifications), +// ], +// RunningPage::Inspect, +// sniffer.style, +// sniffer.language, +// ); +// +// tab_and_body = tab_and_body.push(tabs); +// +// Container::new(Column::new().push(tab_and_body.push(body))) +// .height(FillPortion(HEIGHT_BODY)) +// .style(>::into( +// StyleTuple(sniffer.style, ElementType::Standard), +// )) +// } diff --git a/src/gui/pages/mod.rs b/src/gui/pages/mod.rs new file mode 100644 index 00000000..3892afb2 --- /dev/null +++ b/src/gui/pages/mod.rs @@ -0,0 +1,5 @@ +pub mod initial_page; +pub mod inspect_page; +pub mod notifications_page; +pub mod overview_page; +pub mod settings; diff --git a/src/gui/pages/notifications_page.rs b/src/gui/pages/notifications_page.rs new file mode 100644 index 00000000..01eaffa2 --- /dev/null +++ b/src/gui/pages/notifications_page.rs @@ -0,0 +1,424 @@ +use crate::enums::element_type::ElementType; +use crate::enums::logged_notification::{ + BytesThresholdExceeded, FavoriteTransmitted, LoggedNotification, PacketsThresholdExceeded, +}; +use crate::enums::message::Message; +use crate::enums::overlay::MyOverlay; +use crate::enums::traffic_type::TrafficType; +use crate::gui::components::header::get_button_settings; +use crate::gui::components::tab::get_pages_tabs; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::countries::get_flag; +use crate::utility::get_formatted_strings::get_formatted_bytes_string; +use crate::utility::style_constants::{get_font, FONT_SIZE_FOOTER, HEIGHT_BODY, ICONS}; +use crate::utility::translations::{ + application_protocol_translation, bytes_exceeded_translation, bytes_exceeded_value_translation, + clear_all_translation, favorite_transmitted_translation, incoming_translation, + no_notifications_received_translation, no_notifications_set_translation, + only_last_30_translation, outgoing_translation, packets_exceeded_translation, + packets_exceeded_value_translation, per_second_translation, threshold_translation, +}; +use crate::{Language, RunningPage, Sniffer, StyleType}; +use iced::alignment::{Horizontal, Vertical}; +use iced::widget::{Column, Container, Row, Scrollable, Text, Tooltip}; +use iced::Length::FillPortion; +use iced::{Alignment, Length}; +use iced_native::widget::tooltip::Position; +use iced_native::widget::{button, vertical_space}; + +/// Computes the body of gui notifications page +pub fn notifications_page(sniffer: &Sniffer) -> Container { + let notifications = sniffer.notifications; + + let mut body = Column::new() + .width(Length::Units(830)) + .padding(5) + .spacing(10) + .align_items(Alignment::Center); + + let mut tab_and_body = Column::new() + .align_items(Alignment::Center) + .height(FillPortion(HEIGHT_BODY)); + + let tabs = get_pages_tabs( + [ + RunningPage::Overview, + //RunningPage::Inspect, + RunningPage::Notifications, + ], + &["d ", "7 "], + &[ + Message::ChangeRunningPage(RunningPage::Overview), + // Message::ChangeRunningPage(RunningPage::Inspect), + Message::TickInit, + ], + RunningPage::Notifications, + sniffer.style, + sniffer.language, + ); + + tab_and_body = tab_and_body + .push(tabs) + .push(vertical_space(Length::Units(15))); + + if notifications.packets_notification.threshold.is_none() + && notifications.bytes_notification.threshold.is_none() + && !notifications.favorite_notification.notify_on_favorite + && sniffer + .runtime_data + .borrow() + .logged_notifications + .is_empty() + { + body = body + .width(Length::Fill) + .padding(5) + .spacing(5) + .align_items(Alignment::Center) + .push(vertical_space(FillPortion(1))) + .push(vertical_space(Length::Units(15))) + .push( + no_notifications_set_translation(sniffer.language) + .horizontal_alignment(Horizontal::Center) + .font(get_font(sniffer.style)), + ) + .push(get_button_settings(sniffer.style, sniffer.language)) + .push(vertical_space(FillPortion(2))); + tab_and_body = tab_and_body.push(body); + } else if sniffer + .runtime_data + .borrow() + .logged_notifications + .is_empty() + { + body = body + .width(Length::Fill) + .padding(5) + .spacing(5) + .align_items(Alignment::Center) + .push(vertical_space(FillPortion(1))) + .push(vertical_space(Length::Units(15))) + .push( + no_notifications_received_translation(sniffer.language) + .horizontal_alignment(Horizontal::Center) + .font(get_font(sniffer.style)), + ) + .push( + Text::new(sniffer.waiting.clone()) + .font(get_font(sniffer.style)) + .size(50), + ) + .push(vertical_space(FillPortion(2))); + tab_and_body = tab_and_body.push(body); + } else { + for logged_notification in &sniffer.runtime_data.borrow().logged_notifications { + body = body.push(match logged_notification { + LoggedNotification::PacketsThresholdExceeded(packet_threshold_exceeded) => { + packets_notification_log( + packet_threshold_exceeded.clone(), + sniffer.language, + sniffer.style, + ) + } + LoggedNotification::BytesThresholdExceeded(byte_threshold_exceeded) => { + bytes_notification_log( + byte_threshold_exceeded.clone(), + sniffer.language, + sniffer.style, + ) + } + LoggedNotification::FavoriteTransmitted(favorite_transmitted) => { + favorite_notification_log( + favorite_transmitted.clone(), + sniffer.language, + sniffer.style, + ) + } + }); + } + let body_row = Row::new() + .width(Length::Fill) + .push( + Container::new( + if sniffer.runtime_data.borrow().logged_notifications.len() < 30 { + Text::new("") + } else { + Text::new(only_last_30_translation(sniffer.language)) + .font(get_font(sniffer.style)) + }, + ) + .width(Length::FillPortion(1)) + .height(Length::Fill) + .align_x(Horizontal::Center) + .align_y(Vertical::Center), + ) + .push( + Scrollable::new(body).style(>::into( + StyleTuple(sniffer.style, ElementType::Standard), + )), + ) + .push( + Container::new(get_button_clear_all(sniffer.style, sniffer.language)) + .width(Length::FillPortion(1)) + .height(Length::Fill) + .align_x(Horizontal::Center) + .align_y(Vertical::Center), + ); + tab_and_body = tab_and_body.push(body_row); + } + + Container::new(Column::new().push(tab_and_body)) + .height(FillPortion(HEIGHT_BODY)) + .style(>::into( + StyleTuple(sniffer.style, ElementType::Standard), + )) +} + +fn packets_notification_log( + logged_notification: PacketsThresholdExceeded, + language: Language, + style: StyleType, +) -> Container<'static, Message> { + let font = get_font(style); + let mut threshold_str = threshold_translation(language); + threshold_str.push_str( + &logged_notification + .notification + .previous_threshold + .to_string(), + ); + threshold_str.push_str(&format!(" {}", per_second_translation(language))); + let mut incoming_str = " - ".to_string(); + incoming_str.push_str(incoming_translation(language)); + incoming_str.push_str(": "); + incoming_str.push_str(&logged_notification.incoming.to_string()); + let mut outgoing_str = " - ".to_string(); + outgoing_str.push_str(outgoing_translation(language)); + outgoing_str.push_str(": "); + outgoing_str.push_str(&logged_notification.outgoing.to_string()); + let content = Row::new() + .spacing(30) + .push( + Tooltip::new( + Text::new("e").font(ICONS).size(80), + packets_exceeded_translation(language), + Position::Left, + ) + .gap(5) + .font(get_font(style)) + .style(>::into( + StyleTuple(style, ElementType::Tooltip), + )), + ) + .push( + Column::new() + .spacing(7) + .width(Length::Units(250)) + .push( + Row::new() + .spacing(5) + .push(Text::new("9").font(ICONS)) + .push(Text::new(logged_notification.timestamp).font(font)), + ) + .push(Text::new(packets_exceeded_translation(language)).font(font)) + .push(Text::new(threshold_str).size(FONT_SIZE_FOOTER).font(font)), + ) + .push( + Column::new() + .spacing(7) + .push( + Text::new(packets_exceeded_value_translation( + language, + logged_notification.incoming + logged_notification.outgoing, + )) + .font(font), + ) + .push(Text::new(incoming_str).font(font)) + .push(Text::new(outgoing_str).font(font)), + ); + Container::new(content) + .height(Length::Units(120)) + .width(Length::Units(800)) + .padding(20) + .style(>::into( + StyleTuple(style, ElementType::BorderedRound), + )) +} + +fn bytes_notification_log( + logged_notification: BytesThresholdExceeded, + language: Language, + style: StyleType, +) -> Container<'static, Message> { + let font = get_font(style); + let mut threshold_str = threshold_translation(language); + threshold_str.push_str( + &(logged_notification.notification.previous_threshold + / logged_notification + .notification + .byte_multiple + .get_multiplier()) + .to_string(), + ); + threshold_str.push_str(&format!( + " {}", + logged_notification.notification.byte_multiple.get_char() + )); + threshold_str.push_str(&format!(" {}", per_second_translation(language))); + let mut incoming_str = " - ".to_string(); + incoming_str.push_str(incoming_translation(language)); + incoming_str.push_str(": "); + incoming_str.push_str(&get_formatted_bytes_string(u128::from( + logged_notification.incoming, + ))); + let mut outgoing_str = " - ".to_string(); + outgoing_str.push_str(outgoing_translation(language)); + outgoing_str.push_str(": "); + outgoing_str.push_str(&get_formatted_bytes_string(u128::from( + logged_notification.outgoing, + ))); + let content = Row::new() + .spacing(30) + .push( + Tooltip::new( + Text::new("f").font(ICONS).size(80), + bytes_exceeded_translation(language), + Position::Left, + ) + .gap(5) + .font(get_font(style)) + .style(>::into( + StyleTuple(style, ElementType::Tooltip), + )), + ) + .push( + Column::new() + .spacing(7) + .width(Length::Units(250)) + .push( + Row::new() + .spacing(5) + .push(Text::new("9").font(ICONS)) + .push(Text::new(logged_notification.timestamp).font(font)), + ) + .push(Text::new(bytes_exceeded_translation(language)).font(font)) + .push(Text::new(threshold_str).size(FONT_SIZE_FOOTER).font(font)), + ) + .push( + Column::new() + .spacing(7) + .push( + Text::new(bytes_exceeded_value_translation( + language, + &get_formatted_bytes_string(u128::from( + logged_notification.incoming + logged_notification.outgoing, + )), + )) + .font(font), + ) + .push(Text::new(incoming_str).font(font)) + .push(Text::new(outgoing_str).font(font)), + ); + Container::new(content) + .height(Length::Units(120)) + .width(Length::Units(800)) + .padding(20) + .style(>::into( + StyleTuple(style, ElementType::BorderedRound), + )) +} + +fn favorite_notification_log( + logged_notification: FavoriteTransmitted, + language: Language, + style: StyleType, +) -> Container<'static, Message> { + let font = get_font(style); + let traffic_type = logged_notification.connection.1.traffic_type; + let country = logged_notification.connection.1.country; + let src_str = format!("Src: {}", logged_notification.connection.0.address1); + let dst_str = format!("Dst: {}", logged_notification.connection.0.address2); + let mut app_str = application_protocol_translation(language).to_string(); + app_str.push_str(&format!( + ": {:?}", + logged_notification.connection.1.app_protocol + )); + let mut row_src_flag = Row::new() + .align_items(Alignment::Center) + .spacing(5) + .push(Text::new(src_str).font(font)); + let mut row_dst_flag = Row::new() + .align_items(Alignment::Center) + .spacing(5) + .push(Text::new(dst_str).font(font)); + if !country.is_empty() { + if traffic_type.eq(&TrafficType::Outgoing) { + row_dst_flag = row_dst_flag.push(get_flag(&country)); + } else { + row_src_flag = row_src_flag.push(get_flag(&country)); + } + } + let content = Row::new() + .spacing(30) + .push( + Tooltip::new( + Text::new("g").font(ICONS).size(80), + favorite_transmitted_translation(language), + Position::Left, + ) + .gap(5) + .font(get_font(style)) + .style(>::into( + StyleTuple(style, ElementType::Tooltip), + )), + ) + .push( + Column::new() + .width(Length::Units(250)) + .spacing(7) + .push( + Row::new() + .spacing(5) + .push(Text::new("9").font(ICONS)) + .push(Text::new(logged_notification.timestamp).font(font)), + ) + .push(Text::new(favorite_transmitted_translation(language)).font(font)), // .push(Text::new(threshold_str).font(font)), + ) + .push( + Column::new() + .spacing(7) + .width(Length::Fill) + .push(row_src_flag) + .push(row_dst_flag) + .push(Text::new(app_str).font(font)), + ); + Container::new(content) + .height(Length::Units(120)) + .width(Length::Units(800)) + .padding(20) + .style(>::into( + StyleTuple(style, ElementType::BorderedRound), + )) +} + +pub fn get_button_clear_all(style: StyleType, language: Language) -> Tooltip<'static, Message> { + let content = button( + Text::new('h'.to_string()) + .font(ICONS) + .size(20) + .horizontal_alignment(Horizontal::Center) + .vertical_alignment(Vertical::Center), + ) + .padding(10) + .height(Length::Units(50)) + .width(Length::Units(75)) + .style(StyleTuple(style, ElementType::Standard).into()) + .on_press(Message::ShowModal(MyOverlay::ClearAll)); + + Tooltip::new(content, clear_all_translation(language), Position::Top) + .gap(5) + .font(get_font(style)) + .style(>::into( + StyleTuple(style, ElementType::Tooltip), + )) +} diff --git a/src/gui/pages/overview_page.rs b/src/gui/pages/overview_page.rs new file mode 100644 index 00000000..5d62c8b5 --- /dev/null +++ b/src/gui/pages/overview_page.rs @@ -0,0 +1,376 @@ +//! Module defining the run page of the application. +//! +//! It contains elements to display traffic statistics: charts, detailed connections data +//! and overall statistics about the filtered traffic. + +use iced::alignment::{Horizontal, Vertical}; +use iced::widget::scrollable::Properties; +use iced::widget::{button, vertical_space, Column, Container, Row, Scrollable, Text, Tooltip}; +use iced::Length::FillPortion; +use iced::{alignment, Alignment, Length}; +use iced_native::widget::tooltip::Position; +use thousands::Separable; +//use dns_lookup::lookup_addr; + +use crate::enums::element_type::ElementType; +use crate::enums::message::Message; +use crate::gui::components::radio::{chart_radios, report_radios}; +use crate::gui::components::tab::get_pages_tabs; +use crate::structs::sniffer::Sniffer; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::countries::{get_flag, FLAGS_WIDTH}; +use crate::utility::get_formatted_strings::{ + get_active_filters_string, get_active_filters_string_nobr, get_app_count_string, + get_connection_color, get_formatted_bytes_string, get_percentage_string, +}; +use crate::utility::style_constants::{get_font, HEIGHT_BODY, ICONS, INCONSOLATA_BOLD}; +use crate::utility::translations::{ + error_translation, filtered_application_translation, filtered_bytes_translation, + filtered_packets_translation, no_addresses_translation, no_favorites_translation, + open_report_translation, some_observed_translation, waiting_translation, +}; +use crate::{AppProtocol, ReportType, RunningPage}; + +/// Computes the body of gui run page +pub fn overview_page(sniffer: &Sniffer) -> Container { + let font = get_font(sniffer.style); + + let mut body = Column::new() + .width(Length::Fill) + .padding(5) + .spacing(5) + .align_items(Alignment::Center); + + let mut tab_and_body = Column::new().height(FillPortion(HEIGHT_BODY)); + + if sniffer.pcap_error.is_none() { + // NO pcap error detected + + let tabs = get_pages_tabs( + [ + RunningPage::Overview, + //RunningPage::Inspect, + RunningPage::Notifications, + ], + &["d ", "7 "], + &[ + Message::TickInit, + //Message::ChangeRunningPage(RunningPage::Inspect), + Message::ChangeRunningPage(RunningPage::Notifications), + ], + RunningPage::Overview, + sniffer.style, + sniffer.language, + ); + + let observed = sniffer.runtime_data.borrow().all_packets; + let filtered = sniffer.runtime_data.borrow().tot_sent_packets + + sniffer.runtime_data.borrow().tot_received_packets; + let observed_bytes = sniffer.runtime_data.borrow().all_bytes; + let filtered_bytes = sniffer.runtime_data.borrow().tot_sent_bytes + + sniffer.runtime_data.borrow().tot_received_bytes; + let app_protocols = sniffer.runtime_data.borrow().app_protocols.clone(); + let filtered_bytes_string = get_formatted_bytes_string(filtered_bytes); + + match (observed, filtered) { + (0, 0) => { + //no packets observed at all + + let adapter_name = sniffer.device.name.clone(); + let (icon_text, nothing_to_see_text) = if sniffer.device.addresses.is_empty() { + ( + Text::new('T'.to_string()).font(ICONS).size(60), + no_addresses_translation(sniffer.language, &adapter_name) + .horizontal_alignment(Horizontal::Center) + .font(font), + ) + } else { + ( + Text::new(sniffer.waiting.len().to_string()) + .font(ICONS) + .size(60), + waiting_translation(sniffer.language, &adapter_name) + .horizontal_alignment(Horizontal::Center) + .font(font), + ) + }; + body = body + .push(vertical_space(FillPortion(1))) + .push(icon_text) + .push(vertical_space(Length::Units(15))) + .push(nothing_to_see_text) + .push(Text::new(sniffer.waiting.clone()).font(font).size(50)) + .push(vertical_space(FillPortion(2))); + } + + (observed, 0) => { + //no packets have been filtered but some have been observed + + let tot_packets_text = some_observed_translation( + sniffer.language, + &observed.separate_with_spaces(), + &get_active_filters_string_nobr(&sniffer.filters.clone(), sniffer.language), + ) + .horizontal_alignment(Horizontal::Center) + .font(font); + + body = body + .push(vertical_space(FillPortion(1))) + .push(Text::new('V'.to_string()).font(ICONS).size(60)) + .push(vertical_space(Length::Units(15))) + .push(tot_packets_text) + .push(Text::new(sniffer.waiting.clone()).font(font).size(50)) + .push(vertical_space(FillPortion(2))); + } + + (observed, filtered) => { + //observed > filtered > 0 || observed = filtered > 0 + + tab_and_body = tab_and_body.push(tabs); + + let active_radio_chart = sniffer.traffic_chart.chart_type; + let row_radio_chart = + chart_radios(active_radio_chart, font, sniffer.style, sniffer.language); + let col_chart = Container::new( + Column::new() + .push(row_radio_chart) + .push(sniffer.traffic_chart.view()), + ) + .width(FillPortion(2)) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) + .style(>::into( + StyleTuple(sniffer.style, ElementType::BorderedRound), + )); + + let mut col_packets = Column::new() + //.padding(10) + //.push(iced::Text::new(std::env::current_dir().unwrap().to_str().unwrap()).font(font)) + //.push(iced::Text::new(confy::get_configuration_file_path("sniffnet", None).unwrap().to_string_lossy()).font(font)) + //.push(Text::new(lookup_addr(&"8.8.8.8".parse().unwrap()).unwrap()).font(font)) + .push( + Text::new(get_active_filters_string( + &sniffer.filters.clone(), + sniffer.language, + )) + .font(font), + ) + .push(Text::new(" ")) + .push( + filtered_packets_translation( + sniffer.language, + &filtered.separate_with_spaces(), + &get_percentage_string(observed, filtered), + ) + .font(font), + ) + .push(Text::new(" ")) + .push( + filtered_bytes_translation( + sniffer.language, + &filtered_bytes_string, + &get_percentage_string(observed_bytes, filtered_bytes), + ) + .font(font), + ); + if sniffer.filters.application.eq(&AppProtocol::Other) { + col_packets = col_packets + .push(Text::new(" ")) + .push(filtered_application_translation(sniffer.language).font(font)) + .push( + Scrollable::new( + Text::new(get_app_count_string(&app_protocols, filtered)) + .font(font), + ) + .style(>::into( + StyleTuple(sniffer.style, ElementType::Standard), + )), + ); + } + + let active_radio_report = sniffer.report_type; + let row_radio_report = + report_radios(active_radio_report, font, sniffer.style, sniffer.language); + + let mut col_report = Column::new() + .height(Length::Fill) + .width(Length::Fill) + .push(row_radio_report); + + if sniffer.report_type.eq(&ReportType::Favorites) + && sniffer.runtime_data.borrow().report_vec.is_empty() + { + col_report = col_report.push( + no_favorites_translation(sniffer.language) + .font(font) + .height(Length::Fill) + .width(Length::Fill) + .horizontal_alignment(Horizontal::Center) + .vertical_alignment(Vertical::Center), + ); + } else { + col_report = col_report + .push(Text::new(" Src IP address Src port Dst IP address Dst port Layer4 Layer7 Packets Bytes Country").font(font)) + .push(Text::new("------------------------------------------------------------------------------------------------------------------------").font(font)) + ; + let mut scroll_report = Column::new(); + for key_val in &sniffer.runtime_data.borrow().report_vec { + let entry_color = + get_connection_color(key_val.1.traffic_type, sniffer.style); + let mut entry_row = Row::new().align_items(Alignment::Center).push( + Text::new(format!( + "{}{}", + key_val.0.print_gui(), + key_val.1.print_gui() + )) + .style(iced::theme::Text::Color(entry_color)) + .font(INCONSOLATA_BOLD), + ); + if key_val.1.country.is_empty() { + entry_row = entry_row + .push( + Text::new("?") + .width(Length::Units(FLAGS_WIDTH)) + .style(iced::theme::Text::Color(entry_color)) + .font(INCONSOLATA_BOLD), + ) + .push(Text::new(" ")); + } else { + entry_row = entry_row + .push(get_flag(&key_val.1.country)) + .push(Text::new(" ")); + } + entry_row = entry_row + .push( + button( + Text::new('X'.to_string()) + .font(ICONS) + .size(14) + .horizontal_alignment(Horizontal::Center) + .vertical_alignment(Vertical::Center), + ) + .padding(0) + .height(Length::Units(16)) + .width(Length::Units(16)) + .style( + StyleTuple( + sniffer.style, + if key_val.1.is_favorite { + ElementType::Starred + } else { + ElementType::NotStarred + }, + ) + .into(), + ) + .on_press( + if key_val.1.is_favorite { + Message::UnSaveConnection(key_val.1.index) + } else { + Message::SaveConnection(key_val.1.index) + }, + ), + ) + .push(Text::new(" ").font(font)); + scroll_report = scroll_report.push(entry_row); + } + col_report = col_report.push( + Scrollable::new(scroll_report) + .horizontal_scroll(Properties::new()) + .style(>::into( + StyleTuple(sniffer.style, ElementType::Standard), + )), + ); + }; + + let row_report = Row::new().push( + Container::new(col_report) + .padding(5) + .height(Length::Fill) + .width(Length::Units(1100)) + .style(>::into( + StyleTuple(sniffer.style, ElementType::BorderedRound), + )), + ); + + body = body + .push( + Row::new() + .spacing(5) + .height(FillPortion(3)) + .push(col_chart) + .push( + Container::new(col_packets) + .width(FillPortion(1)) + .padding(10) + .height(Length::Fill) + .align_x(Horizontal::Center) + .style(>::into( + StyleTuple(sniffer.style, ElementType::BorderedRound), + )), + ), + ) + .push( + Container::new( + Row::new() + .spacing(15) + .align_items(Alignment::Center) + .width(Length::Fill) + .push(row_report) + .push( + Tooltip::new( + button( + Text::new('8'.to_string()) + .font(ICONS) + .horizontal_alignment(alignment::Horizontal::Center) + .vertical_alignment(alignment::Vertical::Center), + ) + .padding(10) + .height(Length::Units(50)) + .width(Length::Units(75)) + .style( + StyleTuple(sniffer.style, ElementType::Standard).into(), + ) + .on_press(Message::OpenReport), + open_report_translation(sniffer.language), + Position::Top, + ) + .gap(5) + .font(get_font(sniffer.style)) + .style( + >::into( + StyleTuple(sniffer.style, ElementType::Tooltip), + ), + ), + ), + ) + .align_x(Horizontal::Center) + .height(FillPortion(2)), + ); + } + } + } else { + // pcap threw an ERROR! + let err_string = sniffer.pcap_error.clone().unwrap(); + + let error_text = error_translation(sniffer.language, &err_string) + .horizontal_alignment(Horizontal::Center) + .font(font); + + body = body + .push(vertical_space(FillPortion(1))) + .push(Text::new('U'.to_string()).font(ICONS).size(60)) + .push(vertical_space(Length::Units(15))) + .push(error_text) + .push(Text::new(sniffer.waiting.clone()).font(font).size(50)) + .push(vertical_space(FillPortion(2))); + } + + Container::new(Column::new().push(tab_and_body.push(body))) + .height(FillPortion(HEIGHT_BODY)) + .style(>::into( + StyleTuple(sniffer.style, ElementType::Standard), + )) +} diff --git a/src/gui/pages/settings.rs b/src/gui/pages/settings.rs new file mode 100644 index 00000000..394c0b44 --- /dev/null +++ b/src/gui/pages/settings.rs @@ -0,0 +1,689 @@ +use crate::enums::byte_multiple::{from_char_to_multiple, ByteMultiple}; +use crate::enums::element_type::ElementType; +use crate::enums::message::Message; +use crate::enums::overlay::MyOverlay; +use crate::gui::components::radio::{ + language_radios, sound_bytes_threshold_radios, sound_favorite_radios, + sound_packets_threshold_radios, +}; +use crate::gui::components::tab::get_settings_tabs; +use crate::structs::notifications::{BytesNotification, FavoriteNotification, PacketsNotification}; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::style_constants::{ + get_font, get_font_headers, DEEP_SEA, FONT_SIZE_FOOTER, FONT_SIZE_SUBTITLE, FONT_SIZE_TITLE, + ICONS, MON_AMOUR, YETI_DAY, YETI_NIGHT, +}; +use crate::utility::translations::{ + appearance_title_translation, bytes_threshold_translation, deep_sea_translation, + favorite_notification_translation, hide_translation, languages_title_translation, + mon_amour_translation, notifications_title_translation, packets_threshold_translation, + per_second_translation, settings_translation, specify_multiples_translation, + threshold_translation, volume_translation, yeti_day_translation, yeti_night_translation, +}; +use crate::StyleType::{Day, DeepSea, MonAmour, Night}; +use crate::{Language, Sniffer, StyleType}; +use iced::alignment::{Horizontal, Vertical}; +use iced::widget::{ + button, horizontal_space, image::Handle, vertical_space, Button, Checkbox, Column, Container, + Image, Row, Scrollable, Text, TextInput, Tooltip, +}; +use iced::Length::Units; +use iced::{Alignment, Length}; +use iced_native::widget::tooltip::Position; +use iced_native::widget::Slider; + +pub fn settings_notifications_page(sniffer: &Sniffer) -> Container { + let font = get_font(sniffer.style); + let mut content = Column::new() + .width(Length::Fill) + .push(get_settings_header(sniffer.style, sniffer.language)) + .push(get_settings_tabs( + [ + MyOverlay::SettingsNotifications, + MyOverlay::SettingsAppearance, + MyOverlay::SettingsLanguage, + ], + &["7 ", "K ", "c "], + &[ + Message::TickInit, + Message::ShowModal(MyOverlay::SettingsAppearance), + Message::ShowModal(MyOverlay::SettingsLanguage), + ], + MyOverlay::SettingsNotifications, + sniffer.style, + sniffer.language, + )) + .push(vertical_space(Units(15))) + .push( + notifications_title_translation(sniffer.language) + .font(font) + .size(FONT_SIZE_SUBTITLE) + .width(Length::Fill) + .horizontal_alignment(Horizontal::Center), + ) + .push(vertical_space(Units(5))); + + let volume_notification_col = Column::new() + .align_items(Alignment::Center) + .width(Length::Fill) + .push(volume_slider( + sniffer.language, + sniffer.style, + sniffer.notifications.volume, + )) + .push( + Scrollable::new( + Column::new() + .width(Units(720)) + .push(get_packets_notify( + sniffer.notifications.packets_notification, + sniffer.language, + sniffer.style, + )) + .push(get_bytes_notify( + sniffer.notifications.bytes_notification, + sniffer.language, + sniffer.style, + )) + .push(get_favorite_notify( + sniffer.notifications.favorite_notification, + sniffer.language, + sniffer.style, + )), + ) + .style(>::into( + StyleTuple(sniffer.style, ElementType::Standard), + )), + ); + + content = content.push(volume_notification_col); + + Container::new(content) + .height(Units(400)) + .width(Units(800)) + .style(>::into( + StyleTuple(sniffer.style, ElementType::Standard), + )) +} + +pub fn settings_appearance_page(sniffer: &Sniffer) -> Container { + let font = get_font(sniffer.style); + let content = Column::new() + .align_items(Alignment::Center) + .width(Length::Fill) + .push(get_settings_header(sniffer.style, sniffer.language)) + .push(get_settings_tabs( + [ + MyOverlay::SettingsNotifications, + MyOverlay::SettingsAppearance, + MyOverlay::SettingsLanguage, + ], + &["7 ", "K ", "c "], + &[ + Message::ShowModal(MyOverlay::SettingsNotifications), + Message::TickInit, + Message::ShowModal(MyOverlay::SettingsLanguage), + ], + MyOverlay::SettingsAppearance, + sniffer.style, + sniffer.language, + )) + .push(vertical_space(Units(15))) + .push( + appearance_title_translation(sniffer.language) + .font(font) + .size(FONT_SIZE_SUBTITLE), + ) + .push(vertical_space(Units(10))) + .push( + Row::new() + .push(get_palette_container( + sniffer.style, + YETI_NIGHT, + "Yeti Night".to_string(), + yeti_night_translation(sniffer.language).to_string(), + Night, + )) + .push(horizontal_space(Units(33))) + .push(get_palette_container( + sniffer.style, + YETI_DAY, + "Yeti Day".to_string(), + yeti_day_translation(sniffer.language).to_string(), + Day, + )), + ) + .push(vertical_space(Units(10))) + .push( + Row::new() + .push(get_palette_container( + sniffer.style, + DEEP_SEA, + "Deep Sea".to_string(), + deep_sea_translation(sniffer.language).to_string(), + DeepSea, + )) + .push(horizontal_space(Units(33))) + .push(get_palette_container( + sniffer.style, + MON_AMOUR, + "Mon Amour".to_string(), + mon_amour_translation(sniffer.language).to_string(), + MonAmour, + )), + ); + + Container::new(content) + .height(Units(400)) + .width(Units(800)) + .style(>::into( + StyleTuple(sniffer.style, ElementType::Standard), + )) +} + +pub fn settings_language_page(sniffer: &Sniffer) -> Container { + let font = get_font(sniffer.style); + + let language_active = sniffer.language; + let col_language_radio = language_radios(language_active, font, sniffer.style); + + let content = Column::new() + .align_items(Alignment::Center) + .width(Length::Fill) + .push(get_settings_header(sniffer.style, sniffer.language)) + .push(get_settings_tabs( + [ + MyOverlay::SettingsNotifications, + MyOverlay::SettingsAppearance, + MyOverlay::SettingsLanguage, + ], + &["7 ", "K ", "c "], + &[ + Message::ShowModal(MyOverlay::SettingsNotifications), + Message::ShowModal(MyOverlay::SettingsAppearance), + Message::TickInit, + ], + MyOverlay::SettingsLanguage, + sniffer.style, + sniffer.language, + )) + .push(vertical_space(Units(15))) + .push( + languages_title_translation(sniffer.language) + .font(font) + .size(FONT_SIZE_SUBTITLE), + ) + .push(vertical_space(Units(20))) + .push(col_language_radio) + .push(vertical_space(Units(30))) + .push(Container::new(Text::new("Support for more languages will come with the next releases.\n\n\ + If you want to help me translating the app in your native language, give a look at Sniffnet issues on GitHub.") + .width(Length::Units(450)) + .font(font)).padding(10).style(>::into( + StyleTuple(sniffer.style, ElementType::BorderedRound), + ))); + + Container::new(content) + .height(Units(400)) + .width(Units(800)) + .style(>::into( + StyleTuple(sniffer.style, ElementType::Standard), + )) +} + +fn get_packets_notify( + packets_notification: PacketsNotification, + language: Language, + style: StyleType, +) -> Column<'static, Message> { + let checkbox = Checkbox::new( + packets_threshold_translation(language), + packets_notification.threshold.is_some(), + move |toggled| { + if toggled { + Message::UpdatePacketsNotification( + PacketsNotification { + threshold: Some(packets_notification.previous_threshold), + ..packets_notification + }, + false, + ) + } else { + Message::UpdatePacketsNotification( + PacketsNotification { + threshold: None, + ..packets_notification + }, + false, + ) + } + }, + ) + .size(18) + .font(get_font(style)) + .style(>::into( + StyleTuple(style, ElementType::Standard), + )); + + let mut ret_val = Column::new().spacing(5).push(checkbox); + + if packets_notification.threshold.is_none() { + Column::new() + .padding(5) + .push(Container::new(ret_val).padding(10).width(Units(700)).style( + >::into(StyleTuple( + style, + ElementType::BorderedRound, + )), + )) + } else { + let input_row = Row::new() + .push(horizontal_space(Units(50))) + .push(Text::new(threshold_translation(language)).font(get_font(style))) + .push(input_group_packets(packets_notification, style, language)); + let sound_row = + Row::new() + .push(horizontal_space(Units(50))) + .push(sound_packets_threshold_radios( + packets_notification, + get_font(style), + style, + language, + )); + ret_val = ret_val + .push(vertical_space(Units(5))) + .push(input_row) + .push(sound_row); + Column::new() + .padding(5) + .push(Container::new(ret_val).padding(10).width(Units(700)).style( + >::into(StyleTuple( + style, + ElementType::BorderedRound, + )), + )) + } +} + +fn get_bytes_notify( + bytes_notification: BytesNotification, + language: Language, + style: StyleType, +) -> Column<'static, Message> { + let checkbox = Checkbox::new( + bytes_threshold_translation(language), + bytes_notification.threshold.is_some(), + move |toggled| { + if toggled { + Message::UpdateBytesNotification( + BytesNotification { + threshold: Some(bytes_notification.previous_threshold), + ..bytes_notification + }, + false, + ) + } else { + Message::UpdateBytesNotification( + BytesNotification { + threshold: None, + ..bytes_notification + }, + false, + ) + } + }, + ) + .size(18) + .font(get_font(style)) + .style(>::into( + StyleTuple(style, ElementType::Standard), + )); + + let mut ret_val = Column::new().spacing(5).push(checkbox); + + if bytes_notification.threshold.is_none() { + Column::new() + .padding(5) + .push(Container::new(ret_val).padding(10).width(Units(700)).style( + >::into(StyleTuple( + style, + ElementType::BorderedRound, + )), + )) + } else { + let input_row = Row::new() + .push(horizontal_space(Units(50))) + .push(Text::new(threshold_translation(language)).font(get_font(style))) + .push(input_group_bytes(bytes_notification, style, language)); + let sound_row = + Row::new() + .push(horizontal_space(Units(50))) + .push(sound_bytes_threshold_radios( + bytes_notification, + get_font(style), + style, + language, + )); + ret_val = ret_val + .push(vertical_space(Units(5))) + .push(input_row) + .push(sound_row); + Column::new() + .padding(5) + .push(Container::new(ret_val).padding(10).width(Units(700)).style( + >::into(StyleTuple( + style, + ElementType::BorderedRound, + )), + )) + } +} + +fn get_favorite_notify( + favorite_notification: FavoriteNotification, + language: Language, + style: StyleType, +) -> Column<'static, Message> { + let checkbox = Checkbox::new( + favorite_notification_translation(language), + favorite_notification.notify_on_favorite, + move |toggled| { + if toggled { + Message::UpdateFavoriteNotification( + FavoriteNotification { + notify_on_favorite: true, + ..favorite_notification + }, + false, + ) + } else { + Message::UpdateFavoriteNotification( + FavoriteNotification { + notify_on_favorite: false, + ..favorite_notification + }, + false, + ) + } + }, + ) + .size(18) + .font(get_font(style)) + .style(>::into( + StyleTuple(style, ElementType::Standard), + )); + + let mut ret_val = Column::new().spacing(5).push(checkbox); + + if favorite_notification.notify_on_favorite { + let sound_row = Row::new() + .push(horizontal_space(Units(50))) + .push(sound_favorite_radios( + favorite_notification, + get_font(style), + style, + language, + )); + ret_val = ret_val.push(vertical_space(Units(5))).push(sound_row); + Column::new() + .padding(5) + .push(Container::new(ret_val).padding(10).width(Units(700)).style( + >::into(StyleTuple( + style, + ElementType::BorderedRound, + )), + )) + } else { + Column::new() + .padding(5) + .push(Container::new(ret_val).padding(10).width(Units(700)).style( + >::into(StyleTuple( + style, + ElementType::BorderedRound, + )), + )) + } +} + +fn input_group_packets( + packets_notification: PacketsNotification, + style: StyleType, + language: Language, +) -> Container<'static, Message> { + let curr_threshold_str = &packets_notification.threshold.unwrap().to_string(); + let input_row = Row::new() + .spacing(10) + .push( + TextInput::new( + "0", + if curr_threshold_str == "0" { + "" + } else { + curr_threshold_str + }, + move |value| { + let new_threshold = if value.is_empty() { + 0 + } else { + value + .parse() + .unwrap_or(packets_notification.previous_threshold) + }; + Message::UpdatePacketsNotification( + PacketsNotification { + threshold: Some(new_threshold), + previous_threshold: new_threshold, + ..packets_notification + }, + false, + ) + }, + ) + .padding(1) + .font(get_font(style)) + .width(Length::Units(100)) + .style(>::into( + StyleTuple(style, ElementType::Standard), + )), + ) + .push( + Text::new(per_second_translation(language)) + .font(get_font(style)) + .vertical_alignment(Vertical::Center) + .size(FONT_SIZE_FOOTER), + ); + Container::new(input_row) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) +} + +fn input_group_bytes( + bytes_notification: BytesNotification, + style: StyleType, + language: Language, +) -> Container<'static, Message> { + let mut info_str = per_second_translation(language).to_string(); + info_str.push_str(specify_multiples_translation(language)); + let mut curr_threshold_str = (bytes_notification.threshold.unwrap() + / bytes_notification.byte_multiple.get_multiplier()) + .to_string(); + curr_threshold_str.push_str(bytes_notification.byte_multiple.get_char()); + let input_row = Row::new() + .spacing(10) + .push( + TextInput::new( + "0", + if curr_threshold_str == "0" { + "" + } else { + &curr_threshold_str + }, + move |value| { + let mut byte_multiple_inserted = ByteMultiple::B; + let new_threshold = if value.is_empty() { + 0 + } else if !value.chars().map(char::is_numeric).any(|x| !x) { + // no multiple + value + .parse::() + .unwrap_or(bytes_notification.previous_threshold) + } else { + // multiple + let last_char = value.chars().last().unwrap(); + byte_multiple_inserted = from_char_to_multiple(last_char); + let without_multiple = value[0..value.len() - 1].to_string(); + if without_multiple.parse::().is_ok() + && TryInto::::try_into( + without_multiple.parse::().unwrap() + * u128::from(byte_multiple_inserted.get_multiplier()), + ) + .is_ok() + { + without_multiple.parse::().unwrap() + * byte_multiple_inserted.get_multiplier() + } else if without_multiple.is_empty() { + byte_multiple_inserted = ByteMultiple::B; + 0 + } else { + byte_multiple_inserted = bytes_notification.byte_multiple; + bytes_notification.previous_threshold + } + }; + Message::UpdateBytesNotification( + BytesNotification { + threshold: Some(new_threshold), + previous_threshold: new_threshold, + byte_multiple: byte_multiple_inserted, + ..bytes_notification + }, + false, + ) + }, + ) + .padding(1) + .font(get_font(style)) + .width(Length::Units(100)) + .style(>::into( + StyleTuple(style, ElementType::Standard), + )), + ) + .push( + Text::new(info_str) + .font(get_font(style)) + .vertical_alignment(Vertical::Center) + .size(FONT_SIZE_FOOTER), + ); + Container::new(input_row) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) +} + +fn volume_slider(language: Language, style: StyleType, volume: u8) -> Container<'static, Message> { + Container::new( + Column::new() + .spacing(5) + .align_items(Alignment::Center) + .push(Text::new(volume_translation(language, volume)).font(get_font(style))) + .push( + Row::new() + .push( + Text::new('Y'.to_string()) + .width(Units(30)) + .vertical_alignment(Vertical::Center) + .size(20) + .font(ICONS), + ) + .push( + Slider::new(0..=100, volume, Message::ChangeVolume) + .step(5) + .width(Units(200)) + .style(>::into(StyleTuple( + style, + ElementType::Standard, + ))), + ) + .push(horizontal_space(Length::Units(10))) + .push( + Text::new('Z'.to_string()) + .vertical_alignment(Vertical::Center) + .size(20) + .font(ICONS), + ), + ), + ) + .padding(5) + .width(Length::Fill) + .height(Length::Units(60)) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) +} + +fn get_palette_container( + style: StyleType, + picture: &[u8], + name: String, + description: String, + on_press: StyleType, +) -> Button<'static, Message> { + let font = get_font(style); + let content = Column::new() + .width(Length::Fill) + .align_items(Alignment::Center) + .spacing(5) + .push(Text::new(name).font(font)) + .push(Image::new(Handle::from_memory(Vec::from(picture))).width(Units(300))) + .push(Text::new(description).font(font)); + + Button::new(content) + .height(Units(130)) + .width(Units(350)) + .padding(10) + .style(StyleTuple(style, ElementType::BorderedRound).into()) + .on_press(Message::Style(on_press)) +} + +fn get_settings_header(style: StyleType, language: Language) -> Container<'static, Message> { + Container::new( + Row::new() + .push(horizontal_space(Length::FillPortion(1))) + .push( + Text::new(settings_translation(language)) + .font(get_font_headers(style)) + .size(FONT_SIZE_TITLE) + .width(Length::FillPortion(6)) + .horizontal_alignment(Horizontal::Center), + ) + .push( + Container::new( + Tooltip::new( + button( + Text::new("x") + .font(get_font(style)) + .horizontal_alignment(Horizontal::Center) + .size(15), + ) + .padding(2) + .height(Units(20)) + .width(Units(20)) + .style(StyleTuple(style, ElementType::Standard).into()) + .on_press(Message::HideModal(false)), + hide_translation(language), + Position::Right, + ) + .font(get_font(style)) + .style(>::into( + StyleTuple(style, ElementType::Tooltip), + )), + ) + .width(Length::FillPortion(1)) + .align_x(Horizontal::Center), + ), + ) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) + .height(Units(40)) + .width(Length::Fill) + .style(>::into( + StyleTuple(style, ElementType::Headers), + )) +} diff --git a/src/gui/style.rs b/src/gui/style.rs deleted file mode 100644 index 1f6cc041..00000000 --- a/src/gui/style.rs +++ /dev/null @@ -1,390 +0,0 @@ -//! Module defining the application styles: fonts, colors, containers, picklists, buttons, -//! radios, scrollbars, icons. - -use iced::alignment::Horizontal; -use iced::container::{Style, StyleSheet}; -use iced::{alignment, button, pick_list, Background, Color, Font, Length, Text, Vector}; -use iced_style::scrollable::{Scrollbar, Scroller}; -use plotters::style::RGBColor; - -/// Application version number (to be displayed in gui footer) -pub const APP_VERSION: &str = "v1.0.1"; - -// gui Text fonts -pub const COURIER_PRIME: Font = Font::External { - name: "CourierPrime", - bytes: include_bytes!("../../fonts/CourierPrime.ttf"), -}; -pub const COURIER_PRIME_BOLD: Font = Font::External { - name: "CourierPrimeBold", - bytes: include_bytes!("../../fonts/CourierPrimeBold.ttf"), -}; -pub const COURIER_PRIME_ITALIC: Font = Font::External { - name: "CourierPrimeItalic", - bytes: include_bytes!("../../fonts/CourierPrimeItalic.ttf"), -}; -pub const COURIER_PRIME_BOLD_ITALIC: Font = Font::External { - name: "CourierPrimeBoldItalic", - bytes: include_bytes!("../../fonts/CourierPrimeBoldItalic.ttf"), -}; - -// gui charts fonts -pub const NOTOSANS: Font = Font::External { - name: "Notosans", - bytes: include_bytes!("../../fonts/notosans-regular.ttf"), -}; -pub const NOTOSANS_BOLD: Font = Font::External { - name: "NotosansBold", - bytes: include_bytes!("../../fonts/notosans-bold.ttf"), -}; - -//font to display icons -pub const ICONS: Font = Font::External { - name: "icons", - bytes: include_bytes!("../../fonts/icons.ttf"), -}; - -pub const FONT_SIZE_FOOTER: u16 = 14; -pub const FONT_SIZE_BODY: u16 = 16; -pub const FONT_SIZE_SUBTITLE: u16 = 18; -pub const FONT_SIZE_TITLE: u16 = 22; - -pub const BORDER_WIDTH: f32 = 2.0; - -pub const HEIGHT_HEADER: u16 = 2; -pub const HEIGHT_BODY: u16 = 12; -pub const HEIGHT_FOOTER: u16 = 1; - -pub const DAY_BACKGROUND: Color = Color::WHITE; -pub const NIGHT_BACKGROUND: Color = Color { - r: 0.2, - g: 0.2, - b: 0.2, - a: 1.0, -}; -pub const DAY_BUTTONS: Color = Color { - r: 0.8, - g: 0.8, - b: 0.8, - a: 1.0, -}; -pub const NIGHT_BUTTONS: Color = Color { - r: 0.1, - g: 0.1, - b: 0.1, - a: 1.0, -}; -pub const SPECIAL_NIGHT: Color = Color { - r: 0.7, - g: 0.35, - b: 0.0, - a: 1.0, -}; -pub const SPECIAL_DAY: Color = Color { - r: 0.0, - g: 0.35, - b: 0.7, - a: 1.0, -}; - -pub const SPECIAL_NIGHT_RGB: RGBColor = RGBColor(189, 89, 0); -pub const SPECIAL_DAY_RGB: RGBColor = RGBColor(0, 89, 189); - -pub const COLOR_CHART_MIX_DAY: f64 = 0.8; -pub const COLOR_CHART_MIX_NIGHT: f64 = 0.4; -pub const CHARTS_LINE_BORDER: u32 = 1; - -#[derive(Copy, Eq, PartialEq)] -/// Used to specify the kind of style to be applied to an element -pub enum StyleType { - Night, - Day, - BorderedRound, - HeadersDay, - HeadersNight, -} - -impl Clone for StyleType { - fn clone(&self) -> Self { - *self - } -} - -/// Containers style -impl StyleSheet for StyleType { - fn style(&self) -> Style { - Style { - text_color: match self { - StyleType::Day => Some(Color::BLACK), - StyleType::Night => Some(Color::WHITE), - StyleType::HeadersDay => Some(Color::WHITE), - StyleType::HeadersNight => Some(Color::BLACK), - _ => None, - }, - background: match self { - StyleType::Day => Some(Background::Color(DAY_BACKGROUND)), - StyleType::Night => Some(Background::Color(NIGHT_BACKGROUND)), - StyleType::BorderedRound => None, - StyleType::HeadersDay => Some(Background::Color(SPECIAL_DAY)), - StyleType::HeadersNight => Some(Background::Color(SPECIAL_NIGHT)), - }, - border_radius: match self { - StyleType::BorderedRound => 12.0, - _ => 0.0, - }, - border_width: match self { - StyleType::Night => 0.0, - StyleType::Day => 0.0, - _ => BORDER_WIDTH, - }, - border_color: Color::BLACK, - } - } -} - -/// Picklists style -impl pick_list::StyleSheet for StyleType { - fn menu(&self) -> iced_style::menu::Style { - iced_style::menu::Style { - text_color: match self { - StyleType::Day => Color::BLACK, - StyleType::Night => DAY_BUTTONS, - _ => Color::BLACK, - }, - background: Background::Color(match self { - StyleType::Day => DAY_BUTTONS, - StyleType::Night => NIGHT_BUTTONS, - _ => Color::BLACK, - }), - border_width: BORDER_WIDTH, - border_color: match self { - StyleType::Day => SPECIAL_DAY, - StyleType::Night => SPECIAL_NIGHT, - _ => Color::BLACK, - }, - selected_text_color: match self { - StyleType::Day => Color::BLACK, - StyleType::Night => Color::WHITE, - _ => Color::BLACK, - }, - selected_background: Background::Color(match self { - StyleType::Day => DAY_BACKGROUND, - StyleType::Night => NIGHT_BACKGROUND, - _ => Color::BLACK, - }), - } - } - - fn active(&self) -> pick_list::Style { - pick_list::Style { - text_color: match self { - StyleType::Day => Color::BLACK, - StyleType::Night => Color::WHITE, - _ => Color::BLACK, - }, - placeholder_color: Color::BLACK, - background: Background::Color(match self { - StyleType::Day => DAY_BUTTONS, - StyleType::Night => NIGHT_BUTTONS, - _ => Color::BLACK, - }), - border_radius: 0.0, - border_width: BORDER_WIDTH, - border_color: match self { - StyleType::Day => SPECIAL_DAY, - StyleType::Night => SPECIAL_NIGHT, - _ => Color::BLACK, - }, - icon_size: 0.5, - } - } - - fn hovered(&self) -> pick_list::Style { - pick_list::Style { - text_color: match self { - StyleType::Day => Color::BLACK, - StyleType::Night => Color::WHITE, - _ => Color::BLACK, - }, - placeholder_color: Color::BLACK, - background: Background::Color(match self { - StyleType::Day => DAY_BACKGROUND, - StyleType::Night => NIGHT_BACKGROUND, - _ => Color::BLACK, - }), - border_radius: 0.0, - border_width: BORDER_WIDTH, - border_color: match self { - StyleType::Day => SPECIAL_DAY, - StyleType::Night => SPECIAL_NIGHT, - _ => Color::BLACK, - }, - icon_size: 0.5, - } - } -} - -/// Buttons style -impl button::StyleSheet for StyleType { - fn active(&self) -> button::Style { - button::Style { - background: Some(Background::Color(match self { - StyleType::Day => DAY_BUTTONS, - StyleType::Night => NIGHT_BUTTONS, - _ => Color::BLACK, - })), - border_radius: 12.0, - border_width: BORDER_WIDTH, - shadow_offset: Vector::new(0.0, 0.0), - text_color: match self { - StyleType::Day => Color::BLACK, - StyleType::Night => Color::WHITE, - _ => Color::BLACK, - }, - border_color: match self { - StyleType::Day => SPECIAL_DAY, - StyleType::Night => SPECIAL_NIGHT, - _ => Color::BLACK, - }, - } - } - - fn hovered(&self) -> iced_style::button::Style { - iced_style::button::Style { - shadow_offset: Vector::new(1.0, 1.0), - background: Some(Background::Color(match self { - StyleType::Day => DAY_BACKGROUND, - StyleType::Night => NIGHT_BACKGROUND, - _ => Color::BLACK, - })), - border_radius: 12.0, - border_width: BORDER_WIDTH, - border_color: match self { - StyleType::Day => SPECIAL_DAY, - StyleType::Night => SPECIAL_NIGHT, - _ => Color::BLACK, - }, - text_color: match self { - StyleType::Day => Color::BLACK, - StyleType::Night => Color::WHITE, - _ => Color::BLACK, - }, - } - } -} - -/// Radios style -impl iced_style::radio::StyleSheet for StyleType { - fn active(&self) -> iced_style::radio::Style { - iced_style::radio::Style { - background: Background::Color(match self { - StyleType::Day => DAY_BUTTONS, - StyleType::Night => NIGHT_BUTTONS, - _ => Color::BLACK, - }), - dot_color: match self { - StyleType::Day => SPECIAL_DAY, - StyleType::Night => SPECIAL_NIGHT, - _ => Color::BLACK, - }, - border_width: 0.0, - border_color: Default::default(), - text_color: None, - } - } - - fn hovered(&self) -> iced_style::radio::Style { - iced_style::radio::Style { - background: Background::Color(match self { - StyleType::Day => DAY_BUTTONS, - StyleType::Night => NIGHT_BUTTONS, - _ => Color::BLACK, - }), - dot_color: match self { - StyleType::Day => SPECIAL_DAY, - StyleType::Night => SPECIAL_NIGHT, - _ => Color::BLACK, - }, - border_width: BORDER_WIDTH, - border_color: match self { - StyleType::Day => SPECIAL_DAY, - StyleType::Night => SPECIAL_NIGHT, - _ => Color::BLACK, - }, - text_color: None, - } - } -} - -/// Scrollbars style -impl iced_style::scrollable::StyleSheet for StyleType { - fn active(&self) -> Scrollbar { - Scrollbar { - background: Some(Background::Color(match self { - StyleType::Day => DAY_BUTTONS, - StyleType::Night => NIGHT_BUTTONS, - _ => Color::BLACK, - })), - border_radius: 12.0, - border_width: 0.0, - border_color: Color::BLACK, - scroller: Scroller { - color: match self { - StyleType::Day => DAY_BACKGROUND, - StyleType::Night => NIGHT_BACKGROUND, - _ => Color::BLACK, - }, - border_radius: 12.0, - border_width: BORDER_WIDTH / 1.5, - border_color: Color::BLACK, - }, - } - } - - fn hovered(&self) -> Scrollbar { - Scrollbar { - background: Some(Background::Color(match self { - StyleType::Day => DAY_BUTTONS, - StyleType::Night => NIGHT_BUTTONS, - _ => Color::BLACK, - })), - border_radius: 12.0, - border_width: BORDER_WIDTH / 1.5, - border_color: Color::BLACK, - scroller: Scroller { - color: match self { - StyleType::Day => SPECIAL_DAY, - StyleType::Night => SPECIAL_NIGHT, - _ => Color::BLACK, - }, - border_radius: 12.0, - border_width: BORDER_WIDTH / 1.5, - border_color: Color::BLACK, - }, - } - } -} - -/// It returns a glyph featuring Sniffnet's logo -pub fn logo_glyph() -> Text { - Text::new('A'.to_string()) - .font(ICONS) - .horizontal_alignment(Horizontal::Center) -} - -pub fn icon_sun_moon(style: StyleType) -> Text { - //F: sun, G: moon, K: sun adjust - match style { - StyleType::Night => Text::new('K'.to_string()) - .font(ICONS) - .width(Length::Units(25)) - .horizontal_alignment(alignment::Horizontal::Center) - .size(20), - StyleType::Day => Text::new('K'.to_string()) - .font(ICONS) - .width(Length::Units(25)) - .horizontal_alignment(alignment::Horizontal::Center) - .size(20), - _ => Text::new(""), - } -} diff --git a/src/gui/styles/button.rs b/src/gui/styles/button.rs new file mode 100644 index 00000000..85649fcc --- /dev/null +++ b/src/gui/styles/button.rs @@ -0,0 +1,89 @@ +//! Buttons style + +use crate::enums::element_type::ElementType; +use crate::get_colors; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::style_constants::{BORDER_BUTTON_RADIUS, BORDER_WIDTH, STARRED}; +use iced::widget::button; +use iced::{Background, Color, Vector}; + +impl From for iced::theme::Button { + fn from(tuple: StyleTuple) -> Self { + iced::theme::Button::Custom(Box::new(tuple)) + } +} + +impl button::StyleSheet for StyleTuple { + type Style = iced::Theme; + + fn active(&self, _: &Self::Style) -> button::Appearance { + let colors = get_colors(self.0); + button::Appearance { + background: Some(Background::Color(match self { + StyleTuple( + _, + ElementType::TabActive | ElementType::NotStarred | ElementType::BorderedRound, + ) => colors.primary, + StyleTuple(_, ElementType::Starred) => STARRED, + _ => colors.buttons, + })), + border_radius: match self { + StyleTuple(_, ElementType::TabActive | ElementType::TabInactive) => 0.0, + StyleTuple(_, ElementType::BorderedRound) => 12.0, + _ => BORDER_BUTTON_RADIUS, + }, + border_width: match self { + StyleTuple( + _, + ElementType::TabActive + | ElementType::TabInactive + | ElementType::Starred + | ElementType::NotStarred, + ) => 0.0, + _ => BORDER_WIDTH, + }, + shadow_offset: Vector::new(0.0, 0.0), + text_color: match self { + StyleTuple(_, ElementType::Starred) => Color::BLACK, + _ => colors.text_body, + }, + border_color: match self { + StyleTuple(_, ElementType::Alert) => Color::new(1.0, 0.0, 0.0, 1.0), + StyleTuple(_, ElementType::BorderedRound) => Color::BLACK, + _ => colors.secondary, + }, + } + } + + fn hovered(&self, _: &Self::Style) -> button::Appearance { + let colors = get_colors(self.0); + button::Appearance { + shadow_offset: Vector::new(2.0, 2.0), + background: Some(Background::Color(match self { + StyleTuple(_, ElementType::Starred) => STARRED, + _ => colors.primary, + })), + border_radius: match self { + StyleTuple(_, ElementType::TabActive | ElementType::TabInactive) => 0.0, + StyleTuple(_, ElementType::BorderedRound) => 12.0, + _ => BORDER_BUTTON_RADIUS, + }, + border_width: match self { + StyleTuple( + _, + ElementType::Starred | ElementType::NotStarred | ElementType::TabActive, + ) => 0.0, + _ => BORDER_WIDTH, + }, + border_color: match self { + StyleTuple(_, ElementType::TabInactive) => colors.buttons, + StyleTuple(_, ElementType::Alert) => Color::new(1.0, 0.0, 0.0, 1.0), + _ => colors.secondary, + }, + text_color: match self { + StyleTuple(_, ElementType::Starred) => Color::BLACK, + _ => colors.text_body, + }, + } + } +} diff --git a/src/gui/styles/checkbox.rs b/src/gui/styles/checkbox.rs new file mode 100644 index 00000000..eb9d73b7 --- /dev/null +++ b/src/gui/styles/checkbox.rs @@ -0,0 +1,41 @@ +//! Checkbox style + +use crate::get_colors; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::style_constants::BORDER_WIDTH; +use iced::widget::checkbox::Appearance; +use iced::Background; + +impl From for iced::theme::Checkbox { + fn from(tuple: StyleTuple) -> Self { + iced::theme::Checkbox::Custom(Box::new(tuple)) + } +} + +impl iced::widget::checkbox::StyleSheet for StyleTuple { + type Style = iced::Theme; + + fn active(&self, _: &Self::Style, is_checked: bool) -> Appearance { + let colors = get_colors(self.0); + Appearance { + background: Background::Color(colors.buttons), + checkmark_color: colors.text_body, + border_radius: 0.0, + border_width: if is_checked { BORDER_WIDTH } else { 0.0 }, + border_color: colors.secondary, + text_color: None, + } + } + + fn hovered(&self, _: &Self::Style, _is_checked: bool) -> Appearance { + let colors = get_colors(self.0); + Appearance { + background: Background::Color(colors.buttons), + checkmark_color: colors.text_body, + border_radius: 0.0, + border_width: BORDER_WIDTH, + border_color: colors.secondary, + text_color: Some(colors.secondary), + } + } +} diff --git a/src/gui/styles/container.rs b/src/gui/styles/container.rs new file mode 100644 index 00000000..c216ae54 --- /dev/null +++ b/src/gui/styles/container.rs @@ -0,0 +1,49 @@ +//! Containers style + +use crate::enums::element_type::ElementType; +use crate::get_colors; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::style_constants::{BORDER_ROUNDED_RADIUS, BORDER_WIDTH}; +use iced::widget::container::Appearance; +use iced::Theme; +use iced::{Background, Color}; + +impl From for iced::theme::Container { + fn from(tuple: StyleTuple) -> Self { + iced::theme::Container::Custom(Box::new(tuple)) + } +} + +impl iced::widget::container::StyleSheet for StyleTuple { + type Style = Theme; + + fn appearance(&self, _: &Self::Style) -> Appearance { + let colors = get_colors(self.0); + Appearance { + text_color: Some(match self { + StyleTuple(_, ElementType::Headers) => colors.text_headers, + _ => colors.text_body, + }), + background: Some(Background::Color(match self { + StyleTuple(_, ElementType::Headers) => colors.secondary, + _ => colors.primary, + })), + border_radius: match self { + StyleTuple(_, ElementType::BorderedRound | ElementType::Alert) => { + BORDER_ROUNDED_RADIUS + } + StyleTuple(_, ElementType::Tooltip) => 7.0, + _ => 0.0, + }, + border_width: match self { + StyleTuple(_, ElementType::Standard | ElementType::Headers) => 0.0, + StyleTuple(_, ElementType::Tooltip) => 1.0, + _ => BORDER_WIDTH, + }, + border_color: match self { + StyleTuple(_, ElementType::Alert) => Color::new(1.0, 0.0, 0.0, 1.0), + _ => colors.round_borders, + }, + } + } +} diff --git a/src/gui/styles/mod.rs b/src/gui/styles/mod.rs new file mode 100644 index 00000000..dfaec9c9 --- /dev/null +++ b/src/gui/styles/mod.rs @@ -0,0 +1,8 @@ +pub mod button; +pub mod checkbox; +pub mod container; +pub mod picklist; +pub mod radio; +pub mod scrollbar; +pub mod slider; +pub mod text_input; diff --git a/src/gui/styles/picklist.rs b/src/gui/styles/picklist.rs new file mode 100644 index 00000000..d318117d --- /dev/null +++ b/src/gui/styles/picklist.rs @@ -0,0 +1,61 @@ +//! Picklists style + +use crate::get_colors; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::style_constants::BORDER_WIDTH; +use iced::widget::pick_list; +use iced::Background; +use std::rc::Rc; + +impl From for iced::theme::PickList { + fn from(tuple: StyleTuple) -> Self { + iced::theme::PickList::Custom(Rc::new(tuple.clone()), Rc::new(tuple)) + } +} + +impl iced::overlay::menu::StyleSheet for StyleTuple { + type Style = iced::Theme; + + fn appearance(&self, _: &Self::Style) -> iced::overlay::menu::Appearance { + let colors = get_colors(self.0); + iced::overlay::menu::Appearance { + text_color: colors.text_body, + background: Background::Color(colors.buttons), + border_width: BORDER_WIDTH, + border_radius: 0.0, + border_color: colors.secondary, + selected_text_color: colors.text_body, + selected_background: Background::Color(colors.primary), + } + } +} + +impl pick_list::StyleSheet for StyleTuple { + type Style = iced::Theme; + + fn active(&self, _: &Self::Style) -> pick_list::Appearance { + let colors = get_colors(self.0); + pick_list::Appearance { + text_color: colors.text_body, + placeholder_color: colors.text_body, + handle_color: colors.text_body, + background: Background::Color(colors.buttons), + border_radius: 0.0, + border_width: BORDER_WIDTH, + border_color: colors.secondary, + } + } + + fn hovered(&self, _: &Self::Style) -> pick_list::Appearance { + let colors = get_colors(self.0); + pick_list::Appearance { + text_color: colors.text_body, + placeholder_color: colors.text_body, + handle_color: colors.text_body, + background: Background::Color(colors.primary), + border_radius: 0.0, + border_width: BORDER_WIDTH, + border_color: colors.secondary, + } + } +} diff --git a/src/gui/styles/radio.rs b/src/gui/styles/radio.rs new file mode 100644 index 00000000..900e6120 --- /dev/null +++ b/src/gui/styles/radio.rs @@ -0,0 +1,39 @@ +//! Radios style + +use crate::get_colors; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::style_constants::BORDER_WIDTH; +use iced::Background; +use iced::Theme; + +impl From for iced::theme::Radio { + fn from(tuple: StyleTuple) -> Self { + iced::theme::Radio::Custom(Box::new(tuple)) + } +} + +impl iced::widget::radio::StyleSheet for StyleTuple { + type Style = Theme; + + fn active(&self, _: &Self::Style, is_selected: bool) -> iced::widget::radio::Appearance { + let colors = get_colors(self.0); + iced::widget::radio::Appearance { + background: Background::Color(colors.buttons), + dot_color: colors.secondary, + border_width: if is_selected { BORDER_WIDTH } else { 0.0 }, + border_color: colors.secondary, + text_color: None, + } + } + + fn hovered(&self, _: &Self::Style, _is_selected: bool) -> iced::widget::radio::Appearance { + let colors = get_colors(self.0); + iced::widget::radio::Appearance { + background: Background::Color(colors.buttons), + dot_color: colors.secondary, + border_width: BORDER_WIDTH, + border_color: colors.secondary, + text_color: Some(colors.secondary), + } + } +} diff --git a/src/gui/styles/scrollbar.rs b/src/gui/styles/scrollbar.rs new file mode 100644 index 00000000..0a66abb9 --- /dev/null +++ b/src/gui/styles/scrollbar.rs @@ -0,0 +1,66 @@ +//! Scrollbars style + +use crate::get_colors; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::style_constants::{BORDER_ROUNDED_RADIUS, BORDER_WIDTH}; +use iced::widget::scrollable::{Scrollbar, Scroller}; +use iced::Background; +use iced::Theme; + +impl From for iced::theme::Scrollable { + fn from(tuple: StyleTuple) -> Self { + iced::theme::Scrollable::Custom(Box::new(tuple)) + } +} + +impl iced::widget::scrollable::StyleSheet for StyleTuple { + type Style = Theme; + + fn active(&self, _: &Self::Style) -> Scrollbar { + let colors = get_colors(self.0); + Scrollbar { + background: Some(Background::Color(colors.buttons)), + border_radius: BORDER_ROUNDED_RADIUS, + border_width: 0.0, + border_color: colors.round_borders, + scroller: Scroller { + color: colors.primary, + border_radius: BORDER_ROUNDED_RADIUS, + border_width: BORDER_WIDTH / 1.5, + border_color: colors.round_borders, + }, + } + } + + fn hovered(&self, _: &Self::Style) -> Scrollbar { + let colors = get_colors(self.0); + Scrollbar { + background: Some(Background::Color(colors.buttons)), + border_radius: BORDER_ROUNDED_RADIUS, + border_width: BORDER_WIDTH / 1.5, + border_color: colors.round_borders, + scroller: Scroller { + color: colors.secondary, + border_radius: BORDER_ROUNDED_RADIUS, + border_width: BORDER_WIDTH / 1.5, + border_color: colors.round_borders, + }, + } + } + + fn dragging(&self, _: &Self::Style) -> Scrollbar { + let colors = get_colors(self.0); + Scrollbar { + background: Some(Background::Color(colors.buttons)), + border_radius: BORDER_ROUNDED_RADIUS, + border_width: BORDER_WIDTH / 1.5, + border_color: colors.round_borders, + scroller: Scroller { + color: colors.secondary, + border_radius: BORDER_ROUNDED_RADIUS, + border_width: BORDER_WIDTH / 1.5, + border_color: colors.round_borders, + }, + } + } +} diff --git a/src/gui/styles/slider.rs b/src/gui/styles/slider.rs new file mode 100644 index 00000000..a5ef93b4 --- /dev/null +++ b/src/gui/styles/slider.rs @@ -0,0 +1,57 @@ +//! Slider style + +use crate::get_colors; +use crate::structs::style_tuple::StyleTuple; +use crate::utility::style_constants::BORDER_WIDTH; +use iced::widget::slider::Appearance; +use iced_native::widget::slider::Handle; +use iced_native::widget::vertical_slider::HandleShape; + +impl From for iced::theme::Slider { + fn from(tuple: StyleTuple) -> Self { + iced::theme::Slider::Custom(Box::new(tuple)) + } +} + +impl iced::widget::slider::StyleSheet for StyleTuple { + type Style = iced::Theme; + + fn active(&self, _: &Self::Style) -> Appearance { + let colors = get_colors(self.0); + Appearance { + rail_colors: (colors.secondary, colors.primary), + handle: Handle { + shape: HandleShape::Circle { radius: 7.0 }, + color: colors.primary, + border_width: BORDER_WIDTH, + border_color: colors.secondary, + }, + } + } + + fn hovered(&self, _: &Self::Style) -> Appearance { + let colors = get_colors(self.0); + Appearance { + rail_colors: (colors.secondary, colors.secondary), + handle: Handle { + shape: HandleShape::Circle { radius: 7.0 }, + color: colors.secondary, + border_width: BORDER_WIDTH, + border_color: colors.secondary, + }, + } + } + + fn dragging(&self, _: &Self::Style) -> Appearance { + let colors = get_colors(self.0); + Appearance { + rail_colors: (colors.secondary, colors.secondary), + handle: Handle { + shape: HandleShape::Circle { radius: 7.0 }, + color: colors.secondary, + border_width: BORDER_WIDTH, + border_color: colors.secondary, + }, + } + } +} diff --git a/src/gui/styles/text_input.rs b/src/gui/styles/text_input.rs new file mode 100644 index 00000000..63834a0e --- /dev/null +++ b/src/gui/styles/text_input.rs @@ -0,0 +1,66 @@ +//! Text Input style + +use crate::get_colors; +use crate::structs::style_tuple::StyleTuple; +use iced::widget::text_input::Appearance; +use iced::{Background, Color}; + +impl From for iced::theme::TextInput { + fn from(tuple: StyleTuple) -> Self { + iced::theme::TextInput::Custom(Box::new(tuple)) + } +} + +impl iced::widget::text_input::StyleSheet for StyleTuple { + type Style = iced::Theme; + + fn active(&self, _: &Self::Style) -> iced::widget::text_input::Appearance { + let colors = get_colors(self.0); + Appearance { + background: Background::Color(colors.buttons), + border_radius: 0.0, + border_width: 1.0, + border_color: colors.round_borders, + } + } + + fn focused(&self, _: &Self::Style) -> iced::widget::text_input::Appearance { + let colors = get_colors(self.0); + Appearance { + background: Background::Color(colors.primary), + border_radius: 0.0, + border_width: 1.0, + border_color: colors.secondary, + } + } + + fn placeholder_color(&self, _: &Self::Style) -> Color { + let color = get_colors(self.0).text_body; + Color { + a: if color.eq(&Color::BLACK) { 0.7 } else { 0.2 }, + ..color + } + } + + fn value_color(&self, _: &Self::Style) -> Color { + get_colors(self.0).text_body + } + + fn selection_color(&self, _: &Self::Style) -> Color { + let color = get_colors(self.0).text_body; + Color { + a: if color.eq(&Color::BLACK) { 0.4 } else { 0.05 }, + ..color + } + } + + fn hovered(&self, _: &Self::Style) -> iced::widget::text_input::Appearance { + let colors = get_colors(self.0); + Appearance { + background: Background::Color(colors.buttons), + border_radius: 0.0, + border_width: 1.0, + border_color: colors.secondary, + } + } +} diff --git a/src/main.rs b/src/main.rs index a46686ad..35cb13ac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,22 +1,30 @@ //! Module containing the entry point of application execution. +use std::cell::RefCell; +use std::rc::Rc; use std::sync::{Arc, Condvar, Mutex}; use std::{panic, process, thread}; use iced::window::Position; -use iced::{button, pick_list, scrollable, window, Application, Settings}; +use iced::{window, Application, Settings}; use pcap::Device; -use gui::style::{StyleType, FONT_SIZE_BODY}; +use utility::style_constants::FONT_SIZE_BODY; use crate::enums::app_protocol::AppProtocol; +use crate::enums::byte_multiple::ByteMultiple; use crate::enums::chart_type::ChartType; use crate::enums::ip_version::IpVersion; +use crate::enums::language::Language; use crate::enums::report_type::ReportType; +use crate::enums::running_page::RunningPage; use crate::enums::status::Status; +use crate::enums::style_type::StyleType; use crate::enums::trans_protocol::TransProtocol; +use crate::structs::config::Config; use crate::structs::filters::Filters; use crate::structs::info_traffic::InfoTraffic; +use crate::structs::palette::get_colors; use crate::structs::runtime_data::RunTimeData; use crate::structs::sniffer::Sniffer; use crate::structs::traffic_chart::TrafficChart; @@ -39,22 +47,22 @@ pub fn main() -> iced::Result { let mutex_map1 = Arc::new(Mutex::new(InfoTraffic::new())); let mutex_map2 = mutex_map1.clone(); - let runtime_data1 = Arc::new(Mutex::new(RunTimeData::new())); - let runtime_data2 = runtime_data1.clone(); - //shared tuple containing the application status and the relative condition variable let status_pair1 = Arc::new((Mutex::new(Status::Init), Condvar::new())); let status_pair2 = status_pair1.clone(); - let found_device = Arc::new(Mutex::new(Device::lookup().unwrap().unwrap())); + let found_device = Device::lookup().unwrap().unwrap(); + + let pcap_error = None; // None means no error - let pcap_error = Arc::new(Mutex::new(None)); // None means no error + let runtime_data1 = Rc::new(RefCell::new(RunTimeData::new())); + let runtime_data2 = runtime_data1.clone(); - let filters = Arc::new(Mutex::new(Filters { + let filters = Filters { ip: IpVersion::Other, transport: TransProtocol::Other, application: AppProtocol::Other, - })); + }; // to kill the main thread as soon as a secondary thread panics let orig_hook = panic::take_hook(); @@ -67,17 +75,29 @@ pub fn main() -> iced::Result { thread::Builder::new() .name("thread_write_report".to_string()) .spawn(move || { - sleep_and_write_report_loop(current_capture_id2, mutex_map2, status_pair2); + sleep_and_write_report_loop(¤t_capture_id2, &mutex_map2, &status_pair2); }) .unwrap(); + let mut config_result = confy::load::("sniffnet", None); + if config_result.is_err() { + // it happens when changing the Config struct fields during development or after new releases + confy::store("sniffnet", None, Config::default()).unwrap(); + config_result = confy::load::("sniffnet", None); + } + let config = config_result.unwrap(); + let style = config.style; + let notifications = config.notifications; + let language = config.language; + Sniffer::run(Settings { id: None, window: window::Settings { size: (1190, 670), // start size position: Position::Centered, - min_size: Some((1190, 500)), // min size allowed + min_size: Some((1190, 600)), // min size allowed max_size: None, + visible: true, resizable: true, decorations: true, transparent: false, @@ -92,24 +112,18 @@ pub fn main() -> iced::Result { filters, status_pair: status_pair1, pcap_error, - start: button::State::new(), - reset: button::State::new(), - mode: button::State::new(), - report: button::State::new(), - git: button::State::new(), - app: pick_list::State::new(), - scroll_adapters: scrollable::State::new(), - scroll_packets: scrollable::State::new(), - scroll_report: scrollable::State::new(), - style: StyleType::Night, - waiting: String::new(), - traffic_chart: TrafficChart::new(runtime_data2), - chart_type: ChartType::Packets, + style, + waiting: ".".to_string(), + traffic_chart: TrafficChart::new(runtime_data2, style, language), report_type: ReportType::MostRecent, + overlay: None, + notifications, + running_page: RunningPage::Overview, + language, }, - default_font: None, + default_font: Some(include_bytes!("../fonts/inconsolata-regular.ttf")), default_text_size: FONT_SIZE_BODY, - text_multithreading: false, + text_multithreading: true, antialiasing: false, exit_on_close_request: true, try_opengles_first: false, diff --git a/src/structs/address_port_pair.rs b/src/structs/address_port_pair.rs index d6ea6e03..8140c43f 100644 --- a/src/structs/address_port_pair.rs +++ b/src/structs/address_port_pair.rs @@ -5,7 +5,7 @@ use std::fmt; use crate::TransProtocol; /// Struct representing a network address:port pair. -#[derive(PartialEq, Eq, Hash, Debug)] +#[derive(PartialEq, Eq, Hash, Debug, Clone)] pub struct AddressPortPair { /// Network layer IPv4 or IPv6 source address. pub address1: String, @@ -20,7 +20,7 @@ pub struct AddressPortPair { } impl AddressPortPair { - /// Returns a new AddressPort element. + /// Returns a new `AddressPort` element. /// /// # Arguments /// @@ -53,14 +53,14 @@ impl fmt::Display for AddressPortPair { if self.address1.len() > 25 || self.address2.len() > 25 { write!( f, - "|{:^45}|{:>8} |{:^45}|{:>8} |", - self.address1, self.port1, self.address2, self.port2 + "|{:^45}|{:>8} |{:^45}|{:>8} | {} |", + self.address1, self.port1, self.address2, self.port2, self.trans_protocol ) } else { write!( f, - "|{:^25}|{:>8} |{:^25}|{:>8} |", - self.address1, self.port1, self.address2, self.port2 + "|{:^25}|{:>8} |{:^25}|{:>8} | {} |", + self.address1, self.port1, self.address2, self.port2, self.trans_protocol ) } } diff --git a/src/structs/config.rs b/src/structs/config.rs new file mode 100644 index 00000000..2711bfd4 --- /dev/null +++ b/src/structs/config.rs @@ -0,0 +1,14 @@ +//! Module defining the `Config` struct, which allows to save and reload +//! the application default configuration. + +use crate::enums::language::Language; +use crate::structs::notifications::Notifications; +use crate::StyleType; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Default)] +pub struct Config { + pub style: StyleType, + pub language: Language, + pub notifications: Notifications, +} diff --git a/src/structs/filters.rs b/src/structs/filters.rs index 92e13071..6685fb13 100644 --- a/src/structs/filters.rs +++ b/src/structs/filters.rs @@ -3,6 +3,7 @@ use crate::{AppProtocol, IpVersion, TransProtocol}; /// Possible filters applicable to network traffic +#[derive(Clone)] pub struct Filters { /// Internet Protocol version pub ip: IpVersion, diff --git a/src/structs/info_address_port_pair.rs b/src/structs/info_address_port_pair.rs index 2b086a4d..6b032eed 100644 --- a/src/structs/info_address_port_pair.rs +++ b/src/structs/info_address_port_pair.rs @@ -1,41 +1,49 @@ -//! Module defining the `IndoAddressPortPair` struct, useful to format the output report file and +//! Module defining the `InfoAddressPortPair` struct, useful to format the output report file and //! to keep track of statistics about the sniffed traffic. +use chrono::{DateTime, Local}; use std::fmt; +use std::ops::Add; use crate::enums::traffic_type::TrafficType; use crate::utility::get_formatted_strings::get_formatted_bytes_string; -use crate::{AppProtocol, TransProtocol}; +use crate::AppProtocol; /// Struct useful to format the output report file and to keep track of statistics about the sniffed traffic. /// -/// Each InfoAddressPortPair struct is associated to a single address:port pair. +/// Each `InfoAddressPortPair` struct is associated to a single address:port pair. +#[derive(Clone)] pub struct InfoAddressPortPair { /// Amount of bytes transmitted between the pair. pub transmitted_bytes: u128, /// Amount of packets transmitted between the pair. pub transmitted_packets: u128, /// First occurrence of information exchange featuring the associate address:port pair as a source or destination. - pub initial_timestamp: String, + pub initial_timestamp: DateTime, /// Last occurrence of information exchange featuring the associate address:port pair as a source or destination. - pub final_timestamp: String, - /// Transport layer protocol carried through the associate address:port pair (TCP or UPD). - pub trans_protocol: TransProtocol, - /// Set of application layer protocols carried through the associate address:port pair. + pub final_timestamp: DateTime, + /// Set of application layer protocols carried by the associated address:port pair. pub app_protocol: AppProtocol, /// Check if source or destination is an IPv6 address longer than 25 bytes (used for Display pub very_long_address: bool, /// Flag to determine which of the address is that of the sniffed adapter or remote pub traffic_type: TrafficType, + /// Country of the remote IP address + pub country: String, + /// Integer corresponding to the index inside the connections map + pub index: usize, + /// Flag that indicates if this connection is marked as favourite + pub is_favorite: bool, } impl InfoAddressPortPair { pub fn print_gui(&self) -> String { self.to_string() - .get(0..46) + .get(0..37) .unwrap() .to_string() .replace('|', "") + .add(&*format!(" {} ", &self.country)) } } @@ -51,24 +59,22 @@ impl fmt::Display for InfoAddressPortPair { if self.very_long_address { write!( f, - " {} |{:^9}|{:>10} |{:>10} | {} | {} |", - self.trans_protocol, + "{:^9}|{:>10} |{:>10} | {} | {} |", app_string, self.transmitted_packets, bytes_string, - self.initial_timestamp, - self.final_timestamp + self.initial_timestamp.to_string().get(0..19).unwrap(), + self.final_timestamp.to_string().get(0..19).unwrap() ) } else { write!( f, - " {} |{:^9}|{:>10} |{:>10} | {} | {} |{}", - self.trans_protocol, + "{:^9}|{:>10} |{:>10} | {} | {} |{}", app_string, self.transmitted_packets, bytes_string, - self.initial_timestamp, - self.final_timestamp, + self.initial_timestamp.to_string().get(0..19).unwrap(), + self.final_timestamp.to_string().get(0..19).unwrap(), " ".repeat(40) ) } diff --git a/src/structs/info_traffic.rs b/src/structs/info_traffic.rs index d91c0689..64f99342 100644 --- a/src/structs/info_traffic.rs +++ b/src/structs/info_traffic.rs @@ -29,10 +29,14 @@ pub struct InfoTraffic { pub addresses_last_interval: HashSet, /// Map of the application layer protocols with their packet count pub app_protocols: HashMap, + /// Collection of indexes of the favorite connections + pub favorite_connections: HashSet, + /// Flag to determine if data were exchanged from favorites in the last interval of time + pub favorite_featured_last_interval: Option<(AddressPortPair, InfoAddressPortPair)>, } impl InfoTraffic { - /// Constructs a new InfoTraffic element. + /// Constructs a new `InfoTraffic` element. pub fn new() -> Self { InfoTraffic { tot_received_bytes: 0, @@ -44,6 +48,8 @@ impl InfoTraffic { map: IndexMap::new(), addresses_last_interval: HashSet::new(), app_protocols: HashMap::new(), + favorite_connections: HashSet::new(), + favorite_featured_last_interval: None, } } } diff --git a/src/structs/mod.rs b/src/structs/mod.rs index a2c67176..66faf102 100644 --- a/src/structs/mod.rs +++ b/src/structs/mod.rs @@ -1,7 +1,11 @@ pub mod address_port_pair; +pub mod config; pub mod filters; pub mod info_address_port_pair; pub mod info_traffic; +pub mod notifications; +pub mod palette; pub mod runtime_data; pub mod sniffer; +pub mod style_tuple; pub mod traffic_chart; diff --git a/src/structs/notifications.rs b/src/structs/notifications.rs new file mode 100644 index 00000000..3513593b --- /dev/null +++ b/src/structs/notifications.rs @@ -0,0 +1,65 @@ +use crate::enums::sound::Sound; +use crate::ByteMultiple; +use serde::{Deserialize, Serialize}; + +/// Used to contain the notifications configuration set by the user +#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug, Copy)] +pub struct Notifications { + pub volume: u8, + pub packets_notification: PacketsNotification, + pub bytes_notification: BytesNotification, + pub favorite_notification: FavoriteNotification, +} + +impl Default for Notifications { + fn default() -> Self { + Notifications { + volume: 60, + packets_notification: PacketsNotification { + threshold: None, + sound: Sound::Gulp, + previous_threshold: 750, + }, + bytes_notification: BytesNotification { + threshold: None, + byte_multiple: ByteMultiple::KB, + sound: Sound::Pop, + previous_threshold: 800_000, + }, + favorite_notification: FavoriteNotification { + notify_on_favorite: false, + sound: Sound::Swhoosh, + }, + } + } +} + +#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug, Copy)] +pub struct PacketsNotification { + /// Threshold of received + sent bytes; if exceeded a notification is emitted + pub threshold: Option, + /// The sound to emit + pub sound: Sound, + /// The last used Some value for the threshold field + pub previous_threshold: u32, +} + +#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug, Copy)] +pub struct BytesNotification { + /// Threshold of received + sent bytes; if exceeded a notification is emitted + pub threshold: Option, + /// B, KB, MB or GB + pub byte_multiple: ByteMultiple, + /// The sound to emit + pub sound: Sound, + /// The last used Some value for the threshold field + pub previous_threshold: u64, +} + +#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug, Copy)] +pub struct FavoriteNotification { + /// Flag to determine if this notification is enabled + pub notify_on_favorite: bool, + /// The sound to emit + pub sound: Sound, +} diff --git a/src/structs/palette.rs b/src/structs/palette.rs new file mode 100644 index 00000000..8fc7c8f9 --- /dev/null +++ b/src/structs/palette.rs @@ -0,0 +1,57 @@ +//! Module defining the `Colors` struct, which defines the colors in use in the GUI. + +use crate::utility::style_constants::{DAY_STYLE, NIGHT_STYLE, RED_STYLE, TRY_STYLE}; +use crate::StyleType; +use iced::Color; +use plotters::style::RGBColor; + +/// Set of colors to apply to GUI +/// +/// Best practices: +/// - `primary` should be a kind of neutral color +/// - `primary` and `buttons` should be similar colors +/// - `secondary` and one of `incoming` or `outgoing` should be the same color +/// - `incoming` and `outgoing` should be complementary colors if possible +/// - `text_headers` should be black or white and must have a strong contrast with `secondary` +/// - `text_body` should be black or white and must have a strong contrast with `primary` +pub struct Palette { + /// Main color of the GUI (background, hovered buttons, active tab) + pub primary: Color, + /// Secondary color of the GUI (header, footer, buttons' borders, radio selection) + pub secondary: Color, + /// Color of active buttons (when not hovered) and inactive tabs + pub buttons: Color, + /// Color of incoming connections + pub incoming: Color, + /// Color of outgoing connections + pub outgoing: Color, + /// Color of header and footer text + pub text_headers: Color, + /// Color of body and buttons text + pub text_body: Color, + /// Color of round container borders and scrollbar borders + pub round_borders: Color, +} + +pub fn get_colors(style: StyleType) -> Palette { + match style { + StyleType::Night => NIGHT_STYLE, + StyleType::Day => DAY_STYLE, + StyleType::DeepSea => TRY_STYLE, + StyleType::MonAmour => RED_STYLE, + } +} + +pub fn to_rgb_color(color: Color) -> RGBColor { + RGBColor( + (color.r * 255.0) as u8, + (color.g * 255.0) as u8, + (color.b * 255.0) as u8, + ) +} + +impl Default for Palette { + fn default() -> Self { + get_colors(StyleType::Night) + } +} diff --git a/src/structs/runtime_data.rs b/src/structs/runtime_data.rs index 5dd5a959..3d103ca4 100644 --- a/src/structs/runtime_data.rs +++ b/src/structs/runtime_data.rs @@ -2,6 +2,9 @@ //! use std::collections::{HashMap, VecDeque}; +use crate::enums::logged_notification::LoggedNotification; +use crate::structs::address_port_pair::AddressPortPair; +use crate::structs::info_address_port_pair::InfoAddressPortPair; use crate::AppProtocol; /// Struct containing useful data to generate charts and to display statistics about network traffic @@ -9,56 +12,63 @@ pub struct RunTimeData { /// Total number of bytes (filtered and not filtered) pub all_bytes: u128, /// Sent bytes filtered and their time occurrence - pub sent_bytes: VecDeque<(u128, i128)>, + pub sent_bytes: VecDeque<(u32, i64)>, /// Received bytes filtered and their time occurrence - pub received_bytes: VecDeque<(u128, i128)>, + pub received_bytes: VecDeque<(u32, i64)>, /// Total number of packets (filtered and not filtered) pub all_packets: u128, /// Sent packets filtered and their time occurrence - pub sent_packets: VecDeque<(u128, i128)>, + pub sent_packets: VecDeque<(u32, i64)>, /// Received packets filtered and their time occurrence - pub received_packets: VecDeque<(u128, i128)>, + pub received_packets: VecDeque<(u32, i64)>, /// Application protocol with the respective number of filtered packets pub app_protocols: HashMap, + /// Connection entries to be displayed in report column + pub report_vec: Vec<(AddressPortPair, InfoAddressPortPair)>, /// Total sent bytes filtered - pub tot_sent_bytes: i128, + pub tot_sent_bytes: u128, /// Total received bytes filtered - pub tot_received_bytes: i128, + pub tot_received_bytes: u128, /// Total sent packets filtered - pub tot_sent_packets: i128, + pub tot_sent_packets: u128, /// Total received packets filtered - pub tot_received_packets: i128, + pub tot_received_packets: u128, /// Total sent bytes filtered before the current time interval - pub tot_sent_bytes_prev: i128, + pub tot_sent_bytes_prev: u128, /// Total received bytes filtered before the current time interval - pub tot_received_bytes_prev: i128, + pub tot_received_bytes_prev: u128, /// Total sent packets filtered before the current time interval - pub tot_sent_packets_prev: i128, + pub tot_sent_packets_prev: u128, /// Total received packets filtered before the current time interval - pub tot_received_packets_prev: i128, + pub tot_received_packets_prev: u128, /// Minimum number of sent bytes per time interval (computed on last 30 intervals) - pub min_sent_bytes: i128, + pub min_sent_bytes: i64, /// Minimum number of received bytes per time interval (computed on last 30 intervals) - pub max_received_bytes: i128, + pub max_received_bytes: i64, /// Minimum number of sent packets per time interval (computed on last 30 intervals) - pub min_sent_packets: i128, + pub min_sent_packets: i64, /// Minimum number of received packets per time interval (computed on last 30 intervals) - pub max_received_packets: i128, + pub max_received_packets: i64, + /// Flag to determine if data were exchanged from favorites in the last interval of time + pub favorite_featured_last_interval: Option<(AddressPortPair, InfoAddressPortPair)>, + /// Log of the received notifications + pub logged_notifications: VecDeque, /// Current time interval number - pub ticks: u128, + pub ticks: u32, } impl RunTimeData { - /// Constructs a new ChartsData element. + /// Constructs a new `ChartsData` element. pub fn new() -> Self { RunTimeData { all_bytes: 0, - sent_bytes: Default::default(), - received_bytes: Default::default(), + sent_bytes: VecDeque::default(), + received_bytes: VecDeque::default(), all_packets: 0, - sent_packets: Default::default(), - received_packets: Default::default(), - app_protocols: Default::default(), + sent_packets: VecDeque::default(), + received_packets: VecDeque::default(), + app_protocols: HashMap::default(), + report_vec: Vec::default(), tot_sent_bytes: 0, tot_received_bytes: 0, tot_sent_packets: 0, @@ -71,6 +81,8 @@ impl RunTimeData { max_received_bytes: 0, min_sent_packets: 0, max_received_packets: 0, + favorite_featured_last_interval: None, + logged_notifications: VecDeque::default(), ticks: 0, } } diff --git a/src/structs/sniffer.rs b/src/structs/sniffer.rs index 7d1418af..8007c05a 100644 --- a/src/structs/sniffer.rs +++ b/src/structs/sniffer.rs @@ -1,16 +1,19 @@ //! Module defining the `Sniffer` struct, which trace gui's component statuses and permits //! to share data among the different threads. -use std::sync::{Arc, Condvar, Mutex}; - -use iced::{button, pick_list, scrollable}; use pcap::Device; +use std::cell::RefCell; +use std::rc::Rc; +use std::sync::{Arc, Condvar, Mutex}; -use crate::enums::chart_type::ChartType; +use crate::enums::language::Language; +use crate::enums::overlay::MyOverlay; use crate::enums::report_type::ReportType; +use crate::enums::running_page::RunningPage; use crate::enums::status::Status; use crate::structs::filters::Filters; -use crate::{AppProtocol, InfoTraffic, RunTimeData, StyleType, TrafficChart}; +use crate::structs::notifications::Notifications; +use crate::{InfoTraffic, RunTimeData, StyleType, TrafficChart}; /// Struct on which the gui is based /// @@ -20,42 +23,30 @@ pub struct Sniffer { pub current_capture_id: Arc>, /// Capture data updated by thread parsing packets pub info_traffic: Arc>, - /// Capture data displayed in GUI - pub runtime_data: Arc>, - /// Network adapter to be analyzed - pub device: Arc>, - /// Active filters on the observed traffic - pub filters: Arc>, /// Status of the application (init or running) and the associated condition variable pub status_pair: Arc<(Mutex, Condvar)>, + /// Traffic data displayed in GUI + pub runtime_data: Rc>, + /// Network adapter to be analyzed + pub device: Device, + /// Active filters on the observed traffic + pub filters: Filters, /// Signals if a pcap error occurred - pub pcap_error: Arc>>, - /// Start button state - pub start: button::State, - /// Reset button state - pub reset: button::State, - /// Style button state - pub mode: button::State, - /// Full report button state - pub report: button::State, - /// GitHub button state - pub git: button::State, - /// Application protocol picklist state - pub app: pick_list::State, - /// Adapters scrollbar state - pub scroll_adapters: scrollable::State, - /// Packets information scrollbar state - pub scroll_packets: scrollable::State, - /// Relevant connections scrollbar state - pub scroll_report: scrollable::State, + pub pcap_error: Option, /// Application style (only values Day and Night are possible for this field) pub style: StyleType, /// Waiting string pub waiting: String, /// Chart displayed pub traffic_chart: TrafficChart, - /// Chart type to be displayed - pub chart_type: ChartType, /// Report type to be displayed pub report_type: ReportType, + /// Currently displayed overlay; None if no overlay is displayed + pub overlay: Option, + /// Contains the notifications configuration set by the user + pub notifications: Notifications, + /// Defines the current running page + pub running_page: RunningPage, + /// Language used in the GUI + pub language: Language, } diff --git a/src/structs/style_tuple.rs b/src/structs/style_tuple.rs new file mode 100644 index 00000000..b04416ac --- /dev/null +++ b/src/structs/style_tuple.rs @@ -0,0 +1,11 @@ +use crate::enums::element_type::ElementType; +use crate::StyleType; + +/// This tuple permits to specify the correct style depending on the style type and on the element type +pub struct StyleTuple(pub StyleType, pub ElementType); + +impl Clone for StyleTuple { + fn clone(&self) -> Self { + Self(self.0, self.1) + } +} diff --git a/src/structs/traffic_chart.rs b/src/structs/traffic_chart.rs index 02e60b01..bb2b6cda 100644 --- a/src/structs/traffic_chart.rs +++ b/src/structs/traffic_chart.rs @@ -1,75 +1,96 @@ //! This module defines the behavior of the `TrafficChart` struct, used to display charts in GUI run page -use std::cmp::max; -use std::sync::{Arc, Mutex}; +use std::cell::RefCell; +use std::rc::Rc; use iced::alignment::{Horizontal, Vertical}; -use iced::{Column, Container, Element}; +use iced::widget::{Column, Container}; +use iced::{Element, Font}; use plotters::style::RGBColor; use plotters_iced::{Chart, ChartBuilder, ChartWidget, DrawingBackend}; use crate::enums::message::Message; -use crate::gui::style::{ - CHARTS_LINE_BORDER, COLOR_CHART_MIX_DAY, COLOR_CHART_MIX_NIGHT, NOTOSANS, NOTOSANS_BOLD, - SPECIAL_DAY_RGB, SPECIAL_NIGHT_RGB, -}; -use crate::{ChartType, RunTimeData, StyleType}; +use crate::structs::palette::to_rgb_color; +use crate::utility::style_constants::{CHARTS_LINE_BORDER, COLOR_CHART_MIX, INCONSOLATA_BOLD}; +use crate::utility::translations::{incoming_translation, outgoing_translation}; +use crate::{get_colors, ChartType, Language, RunTimeData, StyleType}; /// Struct defining the chart to be displayed in gui run page pub struct TrafficChart { - charts_data: Arc>, + charts_data: Rc>, color_mix: f64, - font_color: RGBColor, - chart_type: ChartType, + color_incoming: RGBColor, + color_outgoing: RGBColor, + color_font: RGBColor, + pub chart_type: ChartType, + pub language: Language, } impl TrafficChart { - pub fn new(charts_data: Arc>) -> Self { + pub fn new( + charts_data: Rc>, + style: StyleType, + language: Language, + ) -> Self { TrafficChart { charts_data, - color_mix: 0.0, - font_color: Default::default(), + color_mix: COLOR_CHART_MIX, + color_incoming: to_rgb_color(get_colors(style).incoming), + color_outgoing: to_rgb_color(get_colors(style).outgoing), + color_font: to_rgb_color(get_colors(style).text_body), chart_type: ChartType::Packets, + language, } } - pub fn view(&mut self, mode: StyleType, chart_type: ChartType) -> Element { - self.color_mix = if mode == StyleType::Day { - COLOR_CHART_MIX_DAY - } else { - COLOR_CHART_MIX_NIGHT - }; - self.chart_type = chart_type; - self.font_color = if mode == StyleType::Day { - plotters::style::colors::BLACK - } else { - plotters::style::colors::WHITE - }; - - Container::new(Column::new().push(ChartWidget::new(self).resolve_font( - move |_, _| match mode { - StyleType::Night => NOTOSANS, - StyleType::Day => NOTOSANS_BOLD, - _ => NOTOSANS, - }, - ))) + pub fn view(&self) -> Element { + let color_font = self.color_font; + Container::new( + Column::new().push( + ChartWidget::new(self).resolve_font(move |_, _| match color_font { + RGBColor(255, 255, 255) => Font::Default, // if white non-bold + _ => INCONSOLATA_BOLD, + }), + ), + ) .align_x(Horizontal::Left) .align_y(Vertical::Bottom) .into() } + + pub fn change_kind(&mut self, kind: ChartType) { + self.chart_type = kind; + } + + pub fn change_language(&mut self, language: Language) { + self.language = language; + } + + pub fn change_colors(&mut self, style: StyleType) { + self.color_font = to_rgb_color(get_colors(style).text_body); + self.color_incoming = to_rgb_color(get_colors(style).incoming); + self.color_outgoing = to_rgb_color(get_colors(style).outgoing); + } } impl Chart for TrafficChart { - fn build_chart(&self, mut chart: ChartBuilder) { - use plotters::{prelude::*, style::Color}; + type State = (); - let charts_data_lock = self.charts_data.lock().unwrap(); + fn build_chart(&self, _state: &Self::State, mut chart: ChartBuilder) { + use plotters::prelude::*; - if charts_data_lock.ticks == 0 { + if self.charts_data.borrow().ticks == 0 { return; } - let tot_seconds = charts_data_lock.ticks - 1; - let first_time_displayed = max(0, charts_data_lock.ticks as i128 - 30) as u128; + let tot_seconds = self.charts_data.borrow().ticks - 1; + let first_time_displayed = if self.charts_data.borrow().ticks > 30 { + self.charts_data.borrow().ticks - 30 + } else { + 0 + }; + + let color_incoming = self.color_incoming; + let color_outgoing = self.color_outgoing; match self.chart_type { ChartType::Bytes => { @@ -80,25 +101,29 @@ impl Chart for TrafficChart { .set_label_area_size(LabelAreaPosition::Bottom, 50) .build_cartesian_2d( first_time_displayed..tot_seconds, - charts_data_lock.min_sent_bytes..charts_data_lock.max_received_bytes, + self.charts_data.borrow().min_sent_bytes + ..self.charts_data.borrow().max_received_bytes, ) .expect("Error drawing graph"); chart .configure_mesh() - .label_style(("notosans", 15).into_font().color(&self.font_color)) - .y_label_formatter(&|bytes| match bytes { - 0..=999 | -999..=-1 => { - format!("{bytes}") - } - 1000..=999_999 | -999_999..=-1000 => { - format!("{:.1} {}", *bytes as f64 / 1_000_f64, "k") - } - 1_000_000..=999_999_999 | -999_999_999..=-1_000_000 => { - format!("{:.1} {}", *bytes as f64 / 1_000_000_f64, "M") - } - _ => { - format!("{:.1} {}", *bytes as f64 / 1_000_000_000_f64, "G") + .label_style(("notosans", 13).into_font().color(&self.color_font)) + .y_label_formatter(&|bytes| { + let bytes_abs = bytes.abs(); + match bytes_abs { + 0..=999 => { + format!("{bytes_abs}") + } + 1000..=999_999 => { + format!("{:.1} {}", bytes_abs as f32 / 1_000_f32, "K") + } + 1_000_000..=999_999_999 => { + format!("{:.1} {}", bytes_abs as f32 / 1_000_000_f32, "M") + } + _ => { + format!("{:.1} {}", bytes_abs as f32 / 1_000_000_000_f32, "G") + } } }) .draw() @@ -106,40 +131,40 @@ impl Chart for TrafficChart { chart .draw_series( AreaSeries::new( - charts_data_lock.received_bytes.iter().copied(), + self.charts_data.borrow().received_bytes.iter().copied(), 0, - SPECIAL_NIGHT_RGB.mix(self.color_mix), + color_incoming.mix(self.color_mix), ) .border_style( - ShapeStyle::from(&SPECIAL_NIGHT_RGB).stroke_width(CHARTS_LINE_BORDER), + ShapeStyle::from(&color_incoming).stroke_width(CHARTS_LINE_BORDER), ), ) .expect("Error drawing graph") - .label("Incoming") - .legend(|(x, y)| { - Rectangle::new([(x, y - 5), (x + 25, y + 5)], SPECIAL_NIGHT_RGB.filled()) + .label(incoming_translation(self.language)) + .legend(move |(x, y)| { + Rectangle::new([(x, y - 5), (x + 25, y + 5)], color_incoming.filled()) }); chart .draw_series( AreaSeries::new( - charts_data_lock.sent_bytes.iter().copied(), + self.charts_data.borrow().sent_bytes.iter().copied(), 0, - SPECIAL_DAY_RGB.mix(self.color_mix), + color_outgoing.mix(self.color_mix), ) .border_style( - ShapeStyle::from(&SPECIAL_DAY_RGB).stroke_width(CHARTS_LINE_BORDER), + ShapeStyle::from(&color_outgoing).stroke_width(CHARTS_LINE_BORDER), ), ) .expect("Error drawing graph") - .label("Outgoing") - .legend(|(x, y)| { - Rectangle::new([(x, y - 5), (x + 25, y + 5)], SPECIAL_DAY_RGB.filled()) + .label(outgoing_translation(self.language)) + .legend(move |(x, y)| { + Rectangle::new([(x, y - 5), (x + 25, y + 5)], color_outgoing.filled()) }); chart .configure_series_labels() .position(SeriesLabelPosition::UpperRight) .border_style(BLACK) - .label_font(("notosans", 15).into_font().color(&self.font_color)) + .label_font(("notosans", 15).into_font().color(&self.color_font)) .draw() .expect("Error drawing graph"); } @@ -152,52 +177,54 @@ impl Chart for TrafficChart { .set_label_area_size(LabelAreaPosition::Bottom, 50) .build_cartesian_2d( first_time_displayed..tot_seconds, - charts_data_lock.min_sent_packets..charts_data_lock.max_received_packets, + self.charts_data.borrow().min_sent_packets + ..self.charts_data.borrow().max_received_packets, ) .expect("Error drawing graph"); chart .configure_mesh() - .label_style(("notosans", 15).into_font().color(&self.font_color)) + .label_style(("notosans", 13).into_font().color(&self.color_font)) + .y_label_formatter(&|packets| packets.abs().to_string()) .draw() .unwrap(); chart .draw_series( AreaSeries::new( - charts_data_lock.received_packets.iter().copied(), + self.charts_data.borrow().received_packets.iter().copied(), 0, - SPECIAL_NIGHT_RGB.mix(self.color_mix), + color_incoming.mix(self.color_mix), ) .border_style( - ShapeStyle::from(&SPECIAL_NIGHT_RGB).stroke_width(CHARTS_LINE_BORDER), + ShapeStyle::from(&color_incoming).stroke_width(CHARTS_LINE_BORDER), ), ) .expect("Error drawing graph") - .label("Incoming") - .legend(|(x, y)| { - Rectangle::new([(x, y - 5), (x + 25, y + 5)], SPECIAL_NIGHT_RGB.filled()) + .label(incoming_translation(self.language)) + .legend(move |(x, y)| { + Rectangle::new([(x, y - 5), (x + 25, y + 5)], color_incoming.filled()) }); chart .draw_series( AreaSeries::new( - charts_data_lock.sent_packets.iter().copied(), + self.charts_data.borrow().sent_packets.iter().copied(), 0, - SPECIAL_DAY_RGB.mix(self.color_mix), + color_outgoing.mix(self.color_mix), ) .border_style( - ShapeStyle::from(&SPECIAL_DAY_RGB).stroke_width(CHARTS_LINE_BORDER), + ShapeStyle::from(&color_outgoing).stroke_width(CHARTS_LINE_BORDER), ), ) .expect("Error drawing graph") - .label("Outgoing") - .legend(|(x, y)| { - Rectangle::new([(x, y - 5), (x + 25, y + 5)], SPECIAL_DAY_RGB.filled()) + .label(outgoing_translation(self.language)) + .legend(move |(x, y)| { + Rectangle::new([(x, y - 5), (x + 25, y + 5)], color_outgoing.filled()) }); chart .configure_series_labels() .position(SeriesLabelPosition::UpperRight) .border_style(BLACK) - .label_font(("notosans", 15).into_font().color(&self.font_color)) + .label_font(("notosans", 15).into_font().color(&self.color_font)) .draw() .expect("Error drawing graph"); } diff --git a/src/thread_parse_packets.rs b/src/thread_parse_packets.rs index 0d03c037..0c07150a 100644 --- a/src/thread_parse_packets.rs +++ b/src/thread_parse_packets.rs @@ -4,37 +4,37 @@ use std::sync::{Arc, Mutex}; use etherparse::PacketHeaders; -use pcap::{Capture, Device}; +use pcap::{Active, Capture, Device}; use crate::enums::traffic_type::TrafficType; use crate::structs::address_port_pair::AddressPortPair; use crate::structs::filters::Filters; +use crate::utility::countries::COUNTRY_MMDB; use crate::utility::manage_packets::{ - analyze_network_header, analyze_transport_header, is_multicast_address, modify_or_insert_in_map, + analyze_network_header, analyze_transport_header, is_broadcast_address, is_multicast_address, + modify_or_insert_in_map, }; use crate::{AppProtocol, InfoTraffic, IpVersion, TransProtocol}; /// The calling thread enters in a loop in which it waits for network packets, parses them according /// to the user specified filters, and inserts them into the shared map variable. pub fn parse_packets_loop( - current_capture_id: Arc>, - device: Arc>, - filters: Arc>, - info_traffic_mutex: Arc>, - pcap_error: Arc>>, + current_capture_id: &Arc>, + device: Device, + mut cap: Capture, + filters: &Filters, + info_traffic_mutex: &Arc>, ) { let capture_id = *current_capture_id.lock().unwrap(); let mut my_interface_addresses = Vec::new(); - for address in device.lock().unwrap().clone().addresses { + for address in device.addresses { my_interface_addresses.push(address.addr.to_string()); } - let filtri = filters.lock().unwrap(); - let network_layer_filter = filtri.ip; - let transport_layer_filter = filtri.transport; - let app_layer_filter = filtri.application; - drop(filtri); + let network_layer_filter = filters.ip; + let transport_layer_filter = filters.transport; + let app_layer_filter = filters.application; let mut port1 = 0; let mut port2 = 0; @@ -46,18 +46,7 @@ pub fn parse_packets_loop( let mut skip_packet; let mut reported_packet; - let cap_result = Capture::from_device(&*device.lock().unwrap().name) - .expect("Capture initialization error\n\r") - .promisc(true) - .snaplen(256) //limit stored packets slice dimension (to keep more in the buffer) - .immediate_mode(true) //parse packets ASAP! - .open(); - if cap_result.is_err() { - let err_string = cap_result.err().unwrap().to_string(); - *pcap_error.lock().unwrap() = Option::Some(err_string); - return; - } - let mut cap = cap_result.unwrap(); + let country_db_reader = maxminddb::Reader::from_source(COUNTRY_MMDB).unwrap(); loop { match cap.next_packet() { @@ -76,8 +65,8 @@ pub fn parse_packets_loop( continue; } Ok(value) => { - let mut address1 = "".to_string(); - let mut address2 = "".to_string(); + let mut address1 = String::new(); + let mut address2 = String::new(); network_protocol = IpVersion::Other; transport_protocol = TransProtocol::Other; application_protocol = AppProtocol::Other; @@ -115,6 +104,8 @@ pub fn parse_packets_loop( traffic_type = TrafficType::Incoming; } else if is_multicast_address(&address2) { traffic_type = TrafficType::Multicast; + } else if is_broadcast_address(&address2) { + traffic_type = TrafficType::Broadcast; } let key: AddressPortPair = AddressPortPair::new( @@ -135,11 +126,12 @@ pub fn parse_packets_loop( // if (port1 >= lowest_port && port1 <= highest_port) // || (port2 >= lowest_port && port2 <= highest_port) { modify_or_insert_in_map( - info_traffic_mutex.clone(), + info_traffic_mutex, key, exchanged_bytes, traffic_type, application_protocol, + &country_db_reader, ); reported_packet = true; // } @@ -160,16 +152,14 @@ pub fn parse_packets_loop( .and_modify(|n| *n += 1) .or_insert(1); - if traffic_type == TrafficType::Incoming - || traffic_type == TrafficType::Multicast - { - //increment number of received packets and bytes - info_traffic.tot_received_packets += 1; - info_traffic.tot_received_bytes += exchanged_bytes; - } else { + if traffic_type == TrafficType::Outgoing { //increment number of sent packets and bytes info_traffic.tot_sent_packets += 1; info_traffic.tot_sent_bytes += exchanged_bytes; + } else { + //increment number of received packets and bytes + info_traffic.tot_received_packets += 1; + info_traffic.tot_received_bytes += exchanged_bytes; } } } diff --git a/src/thread_write_report.rs b/src/thread_write_report.rs index 483958ab..a8008c70 100644 --- a/src/thread_write_report.rs +++ b/src/thread_write_report.rs @@ -13,24 +13,14 @@ use crate::InfoTraffic; /// The calling thread enters in a loop in which it sleeps for 1 second and then /// updates the output report containing detailed traffic information pub fn sleep_and_write_report_loop( - current_capture_id: Arc>, - info_traffic_mutex: Arc>, - status_pair: Arc<(Mutex, Condvar)>, + current_capture_id: &Arc>, + info_traffic_mutex: &Arc>, + status_pair: &Arc<(Mutex, Condvar)>, ) { let cvar = &status_pair.1; - // #[cfg(target_os = "windows")] - // std::process::Command::new("explorer") - // .arg("./sniffnet_report/report.txt") - // .spawn() - // .unwrap(); #[cfg(target_os = "macos")] std::env::set_current_dir(std::env::var("HOME").unwrap()).unwrap(); - // #[cfg(target_os = "linux")] - // std::process::Command::new("explorer") - // .arg("./sniffnet_report/report.txt") - // .spawn() - // .unwrap(); if fs::create_dir("./sniffnet_report").is_err() { fs::remove_dir_all("./sniffnet_report").unwrap(); @@ -39,10 +29,6 @@ pub fn sleep_and_write_report_loop( let path_report = "./sniffnet_report/report.txt".to_string(); - let mut _time_header = 0; - let mut _time_header_sort = 0; - let mut _time_header_sort_print = 0; - let mut capture_id = *current_capture_id.lock().unwrap(); let mut output = @@ -76,7 +62,7 @@ pub fn sleep_and_write_report_loop( .lock() .expect("Error acquiring mutex\n\r"); - for index in info_traffic.addresses_last_interval.iter() { + for index in &info_traffic.addresses_last_interval { let key_val = info_traffic.map.get_index(*index).unwrap(); let seek_pos = 166 * 3 + 206 * (*index) as u64; output.seek(SeekFrom::Start(seek_pos)).unwrap(); diff --git a/src/utility/countries.rs b/src/utility/countries.rs new file mode 100644 index 00000000..a4e5ce97 --- /dev/null +++ b/src/utility/countries.rs @@ -0,0 +1,762 @@ +use crate::enums::traffic_type::TrafficType; +use crate::structs::address_port_pair::AddressPortPair; +use iced::widget::{image::Handle, Image}; +use iced::Length; +use maxminddb::{geoip2, MaxMindDBError, Reader}; + +pub const COUNTRY_MMDB: &[u8] = include_bytes!("../../resources/DB/GeoLite2-Country.mmdb"); + +pub fn get_country_code( + traffic_type: TrafficType, + key: &AddressPortPair, + country_db_reader: &Reader<&[u8]>, +) -> String { + let address_to_lookup = match traffic_type { + TrafficType::Outgoing => &key.address2, + _ => &key.address1, + }; + + let country_result: Result = + country_db_reader.lookup(address_to_lookup.parse().unwrap()); + if let Ok(res1) = country_result { + if let Some(res2) = res1.country { + if let Some(res3) = res2.iso_code { + return res3.to_string().replace("ZZ", "//"); + } + } + } + String::new() +} + +pub const FLAGS_WIDTH: u16 = 15; + +pub const AD: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/andorra-16x16-32921.png"); +pub const AE: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/united-16x16-33114.png"); +pub const AF: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/afghanistan-16x16-32928.png"); +pub const AG: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/antigua-16x16-32910.png"); +pub const AI: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/anguilla-16x16-32924.png"); +pub const AL: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/albania-16x16-32909.png"); +pub const AM: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/armenia-16x16-32925.png"); +pub const AO: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/angola-16x16-32914.png"); +pub const AQ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/antarctica-16x16-33151.png"); +pub const AR: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/argentina-16x16-32919.png"); +pub const AS: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/american-16x16-32917.png"); +pub const AT: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/austria-16x16-32920.png"); +pub const AU: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/austallia-16x16-32912.png"); +pub const AW: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/aruba-16x16-32923.png"); +pub const AX: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/aland-16x16-32908.png"); +pub const AZ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/azerbaijan-16x16-32926.png"); +pub const BA: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/bosnia-16x16-32932.png"); +pub const BB: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/barbados-16x16-32913.png"); +pub const BD: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/bangladesh-16x16-32916.png"); +pub const BE: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/belgium-16x16-32911.png"); +pub const BF: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/burkina-16x16-32934.png"); +pub const BG: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/bulgaria-16x16-32973.png"); +pub const BH: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/bahrain-16x16-32974.png"); +pub const BI: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/burundi-16x16-32935.png"); +pub const BJ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/benin-16x16-32922.png"); +pub const BL: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/saint-16x16-33068.png"); +pub const BM: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/bermuda-16x16-32929.png"); +pub const BN: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/brunei-16x16-32944.png"); +pub const BO: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/bolivia-16x16-32945.png"); +pub const BQ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/bonaire-16x16-32930.png"); +pub const BR: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/brazil-16x16-32937.png"); +pub const BS: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/bahamas-16x16-32915.png"); +pub const BT: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/bhutan-16x16-32931.png"); +pub const BV: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/bouvet-16x16-33156.png"); +pub const BW: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/bostwana-16x16-32933.png"); +pub const BY: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/belarus-16x16-32918.png"); +pub const BZ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/belize-16x16-32927.png"); +pub const CA: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/canada-16x16-32938.png"); +pub const CC: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/cocos-16x16-32947.png"); +pub const CD: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/democratic-16x16-32952.png"); +pub const CF: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/central-16x16-32940.png"); +pub const CG: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/republic-16x16-33061.png"); +pub const CH: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/switzerland-16x16-33095.png"); +pub const CI: &[u8] = include_bytes!("../../resources/countries_flags/png-16/cote-16x16-32949.png"); +pub const CK: &[u8] = include_bytes!("../../resources/countries_flags/png-16/cook-16x16-32954.png"); +pub const CL: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/chile-16x16-32939.png"); +pub const CM: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/cameroon-16x16-32936.png"); +pub const CN: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/china-16x16-32942.png"); +pub const CO: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/colombia-16x16-32946.png"); +pub const CR: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/costa-16x16-32948.png"); +pub const CU: &[u8] = include_bytes!("../../resources/countries_flags/png-16/cuba-16x16-32951.png"); +pub const CV: &[u8] = include_bytes!("../../resources/countries_flags/png-16/cabo-16x16-32941.png"); +pub const CW: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/curacao-16x16-32950.png"); +pub const CX: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/christmas-16x16-32943.png"); +pub const CY: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/cyprus-16x16-32953.png"); +pub const CZ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/czech-16x16-32956.png"); +pub const DE: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/germany-16x16-32989.png"); +pub const DJ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/djibouti-16x16-32957.png"); +pub const DK: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/denmark-16x16-32955.png"); +pub const DM: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/dominica-16x16-32960.png"); +pub const DO: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/dominican-16x16-32993.png"); +pub const DZ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/algeria-16x16-32972.png"); +pub const EC: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/ecuador-16x16-32962.png"); +pub const EE: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/estonia-16x16-32959.png"); +pub const EG: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/egypt-16x16-32961.png"); +pub const EH: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/western-16x16-33139.png"); +pub const ER: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/eritrea-16x16-32964.png"); +pub const ES: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/spain-16x16-33105.png"); +pub const ET: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/ethiopia-16x16-32958.png"); +pub const FI: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/finland-16x16-32966.png"); +pub const FJ: &[u8] = include_bytes!("../../resources/countries_flags/png-16/fiji-16x16-32970.png"); +pub const FK: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/falkland-16x16-32963.png"); +pub const FM: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/federated-16x16-32969.png"); +pub const FO: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/faroe-16x16-32965.png"); +pub const FR: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/france-16x16-32967.png"); +pub const GA: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/gabon-16x16-32968.png"); +pub const GB: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/united-16x16-33115.png"); +pub const GD: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/grenada-16x16-33002.png"); +pub const GE: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/georgia-16x16-32979.png"); +pub const GF: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/france-16x16-32967.png"); +pub const GG: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/guernsey-16x16-32980.png"); +pub const GH: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/ghana-16x16-32990.png"); +pub const GI: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/gibraltar-16x16-32992.png"); +pub const GL: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/greenland-16x16-33003.png"); +pub const GM: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/gambia-16x16-32976.png"); +pub const GN: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/guinea-16x16-33008.png"); +pub const GP: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/guadeloupe-16x16-32982.png"); +pub const GQ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/equatorial-16x16-32971.png"); +pub const GR: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/greece-16x16-32991.png"); +pub const GS: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/south-16x16-33088.png"); +pub const GT: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/guatemala-16x16-33009.png"); +pub const GU: &[u8] = include_bytes!("../../resources/countries_flags/png-16/guam-16x16-33006.png"); +pub const GW: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/guinea-16x16-32983.png"); +pub const GY: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/guyana-16x16-33007.png"); +pub const HK: &[u8] = include_bytes!("../../resources/countries_flags/png-16/hong-16x16-32987.png"); +pub const HM: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/heard-16x16-33153.png"); +pub const HN: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/honduras-16x16-33020.png"); +pub const HR: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/croatia-16x16-32995.png"); +pub const HT: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/haiti-16x16-32984.png"); +pub const HU: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/hungary-16x16-33019.png"); +pub const ID: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/indonesia-16x16-32994.png"); +pub const IE: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/ireland-16x16-32996.png"); +pub const IL: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/israel-16x16-32997.png"); +pub const IM: &[u8] = include_bytes!("../../resources/countries_flags/png-16/isle-16x16-32998.png"); +pub const IN: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/india-16x16-32988.png"); +pub const IO: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/british-16x16-33159.png"); +pub const IQ: &[u8] = include_bytes!("../../resources/countries_flags/png-16/iraq-16x16-33017.png"); +pub const IR: &[u8] = include_bytes!("../../resources/countries_flags/png-16/iran-16x16-33022.png"); +pub const IS: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/iceland-16x16-33152.png"); +pub const IT: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/italy-16x16-32999.png"); +pub const JE: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/jersey-16x16-33004.png"); +pub const JM: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/jamaica-16x16-33000.png"); +pub const JO: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/jordan-16x16-33005.png"); +pub const JP: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/japan-16x16-33001.png"); +pub const KE: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/kenya-16x16-33010.png"); +pub const KG: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/kyrgyzstan-16x16-33014.png"); +pub const KH: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/cambodia-16x16-32978.png"); +pub const KI: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/kiribati-16x16-33012.png"); +pub const KM: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/comoros-16x16-32981.png"); +pub const KN: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/saint-16x16-33070.png"); +pub const KP: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/north-16x16-33045.png"); +pub const KR: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/south-16x16-33086.png"); +pub const KW: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/kuwait-16x16-33013.png"); +pub const KY: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/cayman-16x16-32986.png"); +pub const KZ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/kazakhstan-16x16-33021.png"); +pub const LA: &[u8] = include_bytes!("../../resources/countries_flags/png-16/laos-16x16-33018.png"); +pub const LB: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/lebanon-16x16-33015.png"); +pub const LC: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/saint-16x16-33071.png"); +pub const LI: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/liechtenstein-16x16-33016.png"); +pub const LK: &[u8] = include_bytes!("../../resources/countries_flags/png-16/sri-16x16-33091.png"); +pub const LR: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/liberia-16x16-33032.png"); +pub const LS: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/lesotho-16x16-33029.png"); +pub const LT: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/lithuania-16x16-33043.png"); +pub const LU: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/luxembourg-16x16-33041.png"); +pub const LV: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/latvia-16x16-33031.png"); +pub const LY: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/libya-16x16-33026.png"); +pub const MA: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/morocco-16x16-33027.png"); +pub const MC: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/monaco-16x16-33053.png"); +pub const MD: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/moldova-16x16-33055.png"); +pub const ME: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/montenegro-16x16-33056.png"); +pub const MF: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/saint-16x16-33068.png"); +pub const MG: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/madagascar-16x16-33042.png"); +pub const MH: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/marshall-16x16-33054.png"); +pub const MK: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/former-16x16-33023.png"); +pub const ML: &[u8] = include_bytes!("../../resources/countries_flags/png-16/mali-16x16-33025.png"); +pub const MM: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/myanmar-16x16-33118.png"); +pub const MN: &[u8] = include_bytes!("../../resources/countries_flags/png-16/mn-16x16-33117.png"); +pub const MO: &[u8] = include_bytes!("../../resources/countries_flags/png-16/mo-16x16-33127.png"); +pub const MP: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/northern-16x16-33128.png"); +pub const MQ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/martinique-16x16-33119.png"); +pub const MR: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/mauritania-16x16-33125.png"); +pub const MS: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/montserrat-16x16-33126.png"); +pub const MT: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/malta-16x16-33120.png"); +pub const MU: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/mauritius-16x16-33121.png"); +pub const MV: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/maldives-16x16-33122.png"); +pub const MW: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/malawi-16x16-33116.png"); +pub const MX: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/mexico-16x16-33133.png"); +pub const MY: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/malaysia-16x16-33134.png"); +pub const MZ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/mozambique-16x16-33033.png"); +pub const NA: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/namibia-16x16-33132.png"); +pub const NC: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/france-16x16-32967.png"); +pub const NE: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/niger-16x16-33038.png"); +pub const NF: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/norfolk-16x16-33044.png"); +pub const NG: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/nigeria-16x16-33039.png"); +pub const NI: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/nicaragua-16x16-33037.png"); +pub const NL: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/netherlands-16x16-33035.png"); +pub const NO: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/norway-16x16-33155.png"); +pub const NP: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/nepal-16x16-33028.png"); +pub const NR: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/nauru-16x16-33030.png"); +pub const NU: &[u8] = include_bytes!("../../resources/countries_flags/png-16/niue-16x16-33040.png"); +pub const NZ: &[u8] = include_bytes!("../../resources/countries_flags/png-16/new-16x16-33036.png"); +pub const OM: &[u8] = include_bytes!("../../resources/countries_flags/png-16/oman-16x16-33046.png"); +pub const PA: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/panama-16x16-33049.png"); +pub const PE: &[u8] = include_bytes!("../../resources/countries_flags/png-16/peru-16x16-33051.png"); +pub const PF: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/french-16x16-33024.png"); +pub const PG: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/papua-16x16-33050.png"); +pub const PH: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/philippines-16x16-33052.png"); +pub const PK: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/pakistan-16x16-33047.png"); +pub const PL: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/poland-16x16-33057.png"); +pub const PM: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/france-16x16-32967.png"); +pub const PN: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/itcairn-16x16-33034.png"); +pub const PR: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/puerto-16x16-33059.png"); +pub const PS: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/state-16x16-33089.png"); +pub const PT: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/portugal-16x16-33058.png"); +pub const PW: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/palau-16x16-33048.png"); +pub const PY: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/paraguay-16x16-33066.png"); +pub const QA: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/qatar-16x16-33060.png"); +pub const RE: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/france-16x16-32967.png"); +pub const RO: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/romania-16x16-33063.png"); +pub const RS: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/serbia-16x16-33099.png"); +pub const RU: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/russia-16x16-33064.png"); +pub const RW: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/rwanda-16x16-33067.png"); +pub const SA: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/saudi-16x16-33076.png"); +pub const SB: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/solomon-16x16-33083.png"); +pub const SC: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/seychelles-16x16-33078.png"); +pub const SD: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/sudan-16x16-33090.png"); +pub const SE: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/sweden-16x16-33096.png"); +pub const SG: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/singapore-16x16-33080.png"); +pub const SH: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/united-16x16-33115.png"); +pub const SI: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/slovenia-16x16-33084.png"); +pub const SJ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/svalbard-16x16-33093.png"); +pub const SK: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/slovakia-16x16-33082.png"); +pub const SL: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/sierra-16x16-33079.png"); +pub const SM: &[u8] = include_bytes!("../../resources/countries_flags/png-16/san-16x16-33074.png"); +pub const SN: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/senegal-16x16-33077.png"); +pub const SO: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/somalia-16x16-33085.png"); +pub const SR: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/suriname-16x16-33092.png"); +pub const SS: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/south-16x16-33087.png"); +pub const ST: &[u8] = include_bytes!("../../resources/countries_flags/png-16/sao-16x16-33075.png"); +pub const SV: &[u8] = include_bytes!("../../resources/countries_flags/png-16/el-16x16-33011.png"); +pub const SX: &[u8] = include_bytes!("../../resources/countries_flags/png-16/sint-16x16-33081.png"); +pub const SY: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/syrian-16x16-33097.png"); +pub const SZ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/swaziland-16x16-33094.png"); +pub const TC: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/turks-16x16-33112.png"); +pub const TD: &[u8] = include_bytes!("../../resources/countries_flags/png-16/chad-16x16-32985.png"); +pub const TF: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/french-16x16-32977.png"); +pub const TG: &[u8] = include_bytes!("../../resources/countries_flags/png-16/togo-16x16-33106.png"); +pub const TH: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/thailand-16x16-33102.png"); +pub const TJ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/tajikistan-16x16-33100.png"); +pub const TK: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/tokelau-16x16-33104.png"); +pub const TL: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/timor-16x16-33103.png"); +pub const TM: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/turkmenistan-16x16-33111.png"); +pub const TN: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/tunisia-16x16-33110.png"); +pub const TO: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/tonga-16x16-33107.png"); +pub const TR: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/turkey-16x16-33109.png"); +pub const TT: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/trinidad-16x16-33108.png"); +pub const TV: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/tuvalu-16x16-33113.png"); +pub const TW: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/taiwan-16x16-33098.png"); +pub const TZ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/tanzania-16x16-33101.png"); +pub const UA: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/ukraine-16x16-33145.png"); +pub const UG: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/uganda-16x16-33129.png"); +pub const UM: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/united-16x16-33135.png"); +pub const US: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/united-16x16-33137.png"); +pub const UY: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/uruguay-16x16-33140.png"); +pub const UZ: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/uzbekistan-16x16-33141.png"); +pub const VA: &[u8] = include_bytes!("../../resources/countries_flags/png-16/holy-16x16-33136.png"); +pub const VC: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/saint-16x16-33131.png"); +pub const VE: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/venezuela-16x16-33138.png"); +pub const VG: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/virgin-16x16-33147.png"); +pub const VI: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/virgin-16x16-33149.png"); +pub const VN: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/vietnam-16x16-33148.png"); +pub const VU: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/vanuatu-16x16-33142.png"); +pub const WF: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/wallis-16x16-33144.png"); +pub const WS: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/samoa-16x16-33124.png"); +pub const YE: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/yemen-16x16-33143.png"); +pub const YT: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/mayotte-16x16-33123.png"); +pub const ZA: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/south-16x16-33130.png"); +pub const ZM: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/zambia-16x16-33146.png"); +pub const ZW: &[u8] = + include_bytes!("../../resources/countries_flags/png-16/zimbabwe-16x16-33150.png"); +pub const UNKNOWN: &[u8] = include_bytes!("../../resources/countries_flags/png-16/question.png"); + +pub fn get_flag(country: &str) -> Image { + match country { + "AD" => Image::new(Handle::from_memory(Vec::from(AD))).width(Length::Units(FLAGS_WIDTH)), + "AE" => Image::new(Handle::from_memory(Vec::from(AE))).width(Length::Units(FLAGS_WIDTH)), + "AF" => Image::new(Handle::from_memory(Vec::from(AF))).width(Length::Units(FLAGS_WIDTH)), + "AG" => Image::new(Handle::from_memory(Vec::from(AG))).width(Length::Units(FLAGS_WIDTH)), + "AI" => Image::new(Handle::from_memory(Vec::from(AI))).width(Length::Units(FLAGS_WIDTH)), + "AL" => Image::new(Handle::from_memory(Vec::from(AL))).width(Length::Units(FLAGS_WIDTH)), + "AM" => Image::new(Handle::from_memory(Vec::from(AM))).width(Length::Units(FLAGS_WIDTH)), + "AO" => Image::new(Handle::from_memory(Vec::from(AO))).width(Length::Units(FLAGS_WIDTH)), + "AQ" => Image::new(Handle::from_memory(Vec::from(AQ))).width(Length::Units(FLAGS_WIDTH)), + "AR" => Image::new(Handle::from_memory(Vec::from(AR))).width(Length::Units(FLAGS_WIDTH)), + "AS" => Image::new(Handle::from_memory(Vec::from(AS))).width(Length::Units(FLAGS_WIDTH)), + "AT" => Image::new(Handle::from_memory(Vec::from(AT))).width(Length::Units(FLAGS_WIDTH)), + "AU" => Image::new(Handle::from_memory(Vec::from(AU))).width(Length::Units(FLAGS_WIDTH)), + "AW" => Image::new(Handle::from_memory(Vec::from(AW))).width(Length::Units(FLAGS_WIDTH)), + "AX" => Image::new(Handle::from_memory(Vec::from(AX))).width(Length::Units(FLAGS_WIDTH)), + "AZ" => Image::new(Handle::from_memory(Vec::from(AZ))).width(Length::Units(FLAGS_WIDTH)), + "BA" => Image::new(Handle::from_memory(Vec::from(BA))).width(Length::Units(FLAGS_WIDTH)), + "BB" => Image::new(Handle::from_memory(Vec::from(BB))).width(Length::Units(FLAGS_WIDTH)), + "BD" => Image::new(Handle::from_memory(Vec::from(BD))).width(Length::Units(FLAGS_WIDTH)), + "BE" => Image::new(Handle::from_memory(Vec::from(BE))).width(Length::Units(FLAGS_WIDTH)), + "BF" => Image::new(Handle::from_memory(Vec::from(BF))).width(Length::Units(FLAGS_WIDTH)), + "BG" => Image::new(Handle::from_memory(Vec::from(BG))).width(Length::Units(FLAGS_WIDTH)), + "BH" => Image::new(Handle::from_memory(Vec::from(BH))).width(Length::Units(FLAGS_WIDTH)), + "BI" => Image::new(Handle::from_memory(Vec::from(BI))).width(Length::Units(FLAGS_WIDTH)), + "BJ" => Image::new(Handle::from_memory(Vec::from(BJ))).width(Length::Units(FLAGS_WIDTH)), + "BL" => Image::new(Handle::from_memory(Vec::from(BL))).width(Length::Units(FLAGS_WIDTH)), + "BM" => Image::new(Handle::from_memory(Vec::from(BM))).width(Length::Units(FLAGS_WIDTH)), + "BN" => Image::new(Handle::from_memory(Vec::from(BN))).width(Length::Units(FLAGS_WIDTH)), + "BO" => Image::new(Handle::from_memory(Vec::from(BO))).width(Length::Units(FLAGS_WIDTH)), + "BQ" => Image::new(Handle::from_memory(Vec::from(BQ))).width(Length::Units(FLAGS_WIDTH)), + "BR" => Image::new(Handle::from_memory(Vec::from(BR))).width(Length::Units(FLAGS_WIDTH)), + "BS" => Image::new(Handle::from_memory(Vec::from(BS))).width(Length::Units(FLAGS_WIDTH)), + "BT" => Image::new(Handle::from_memory(Vec::from(BT))).width(Length::Units(FLAGS_WIDTH)), + "BV" => Image::new(Handle::from_memory(Vec::from(BV))).width(Length::Units(FLAGS_WIDTH)), + "BW" => Image::new(Handle::from_memory(Vec::from(BW))).width(Length::Units(FLAGS_WIDTH)), + "BY" => Image::new(Handle::from_memory(Vec::from(BY))).width(Length::Units(FLAGS_WIDTH)), + "BZ" => Image::new(Handle::from_memory(Vec::from(BZ))).width(Length::Units(FLAGS_WIDTH)), + "CA" => Image::new(Handle::from_memory(Vec::from(CA))).width(Length::Units(FLAGS_WIDTH)), + "CC" => Image::new(Handle::from_memory(Vec::from(CC))).width(Length::Units(FLAGS_WIDTH)), + "CD" => Image::new(Handle::from_memory(Vec::from(CD))).width(Length::Units(FLAGS_WIDTH)), + "CF" => Image::new(Handle::from_memory(Vec::from(CF))).width(Length::Units(FLAGS_WIDTH)), + "CG" => Image::new(Handle::from_memory(Vec::from(CG))).width(Length::Units(FLAGS_WIDTH)), + "CH" => Image::new(Handle::from_memory(Vec::from(CH))).width(Length::Units(FLAGS_WIDTH)), + "CI" => Image::new(Handle::from_memory(Vec::from(CI))).width(Length::Units(FLAGS_WIDTH)), + "CK" => Image::new(Handle::from_memory(Vec::from(CK))).width(Length::Units(FLAGS_WIDTH)), + "CL" => Image::new(Handle::from_memory(Vec::from(CL))).width(Length::Units(FLAGS_WIDTH)), + "CM" => Image::new(Handle::from_memory(Vec::from(CM))).width(Length::Units(FLAGS_WIDTH)), + "CN" => Image::new(Handle::from_memory(Vec::from(CN))).width(Length::Units(FLAGS_WIDTH)), + "CO" => Image::new(Handle::from_memory(Vec::from(CO))).width(Length::Units(FLAGS_WIDTH)), + "CR" => Image::new(Handle::from_memory(Vec::from(CR))).width(Length::Units(FLAGS_WIDTH)), + "CU" => Image::new(Handle::from_memory(Vec::from(CU))).width(Length::Units(FLAGS_WIDTH)), + "CV" => Image::new(Handle::from_memory(Vec::from(CV))).width(Length::Units(FLAGS_WIDTH)), + "CW" => Image::new(Handle::from_memory(Vec::from(CW))).width(Length::Units(FLAGS_WIDTH)), + "CX" => Image::new(Handle::from_memory(Vec::from(CX))).width(Length::Units(FLAGS_WIDTH)), + "CY" => Image::new(Handle::from_memory(Vec::from(CY))).width(Length::Units(FLAGS_WIDTH)), + "CZ" => Image::new(Handle::from_memory(Vec::from(CZ))).width(Length::Units(FLAGS_WIDTH)), + "DE" => Image::new(Handle::from_memory(Vec::from(DE))).width(Length::Units(FLAGS_WIDTH)), + "DJ" => Image::new(Handle::from_memory(Vec::from(DJ))).width(Length::Units(FLAGS_WIDTH)), + "DK" => Image::new(Handle::from_memory(Vec::from(DK))).width(Length::Units(FLAGS_WIDTH)), + "DM" => Image::new(Handle::from_memory(Vec::from(DM))).width(Length::Units(FLAGS_WIDTH)), + "DO" => Image::new(Handle::from_memory(Vec::from(DO))).width(Length::Units(FLAGS_WIDTH)), + "DZ" => Image::new(Handle::from_memory(Vec::from(DZ))).width(Length::Units(FLAGS_WIDTH)), + "EC" => Image::new(Handle::from_memory(Vec::from(EC))).width(Length::Units(FLAGS_WIDTH)), + "EE" => Image::new(Handle::from_memory(Vec::from(EE))).width(Length::Units(FLAGS_WIDTH)), + "EG" => Image::new(Handle::from_memory(Vec::from(EG))).width(Length::Units(FLAGS_WIDTH)), + "EH" => Image::new(Handle::from_memory(Vec::from(EH))).width(Length::Units(FLAGS_WIDTH)), + "ER" => Image::new(Handle::from_memory(Vec::from(ER))).width(Length::Units(FLAGS_WIDTH)), + "ES" => Image::new(Handle::from_memory(Vec::from(ES))).width(Length::Units(FLAGS_WIDTH)), + "ET" => Image::new(Handle::from_memory(Vec::from(ET))).width(Length::Units(FLAGS_WIDTH)), + "FI" => Image::new(Handle::from_memory(Vec::from(FI))).width(Length::Units(FLAGS_WIDTH)), + "FJ" => Image::new(Handle::from_memory(Vec::from(FJ))).width(Length::Units(FLAGS_WIDTH)), + "FK" => Image::new(Handle::from_memory(Vec::from(FK))).width(Length::Units(FLAGS_WIDTH)), + "FM" => Image::new(Handle::from_memory(Vec::from(FM))).width(Length::Units(FLAGS_WIDTH)), + "FO" => Image::new(Handle::from_memory(Vec::from(FO))).width(Length::Units(FLAGS_WIDTH)), + "FR" => Image::new(Handle::from_memory(Vec::from(FR))).width(Length::Units(FLAGS_WIDTH)), + "GA" => Image::new(Handle::from_memory(Vec::from(GA))).width(Length::Units(FLAGS_WIDTH)), + "GB" | "EN" => { + Image::new(Handle::from_memory(Vec::from(GB))).width(Length::Units(FLAGS_WIDTH)) + } + "GD" => Image::new(Handle::from_memory(Vec::from(GD))).width(Length::Units(FLAGS_WIDTH)), + "GE" => Image::new(Handle::from_memory(Vec::from(GE))).width(Length::Units(FLAGS_WIDTH)), + "GF" => Image::new(Handle::from_memory(Vec::from(GF))).width(Length::Units(FLAGS_WIDTH)), + "GG" => Image::new(Handle::from_memory(Vec::from(GG))).width(Length::Units(FLAGS_WIDTH)), + "GH" => Image::new(Handle::from_memory(Vec::from(GH))).width(Length::Units(FLAGS_WIDTH)), + "GI" => Image::new(Handle::from_memory(Vec::from(GI))).width(Length::Units(FLAGS_WIDTH)), + "GL" => Image::new(Handle::from_memory(Vec::from(GL))).width(Length::Units(FLAGS_WIDTH)), + "GM" => Image::new(Handle::from_memory(Vec::from(GM))).width(Length::Units(FLAGS_WIDTH)), + "GN" => Image::new(Handle::from_memory(Vec::from(GN))).width(Length::Units(FLAGS_WIDTH)), + "GP" => Image::new(Handle::from_memory(Vec::from(GP))).width(Length::Units(FLAGS_WIDTH)), + "GQ" => Image::new(Handle::from_memory(Vec::from(GQ))).width(Length::Units(FLAGS_WIDTH)), + "GR" => Image::new(Handle::from_memory(Vec::from(GR))).width(Length::Units(FLAGS_WIDTH)), + "GS" => Image::new(Handle::from_memory(Vec::from(GS))).width(Length::Units(FLAGS_WIDTH)), + "GT" => Image::new(Handle::from_memory(Vec::from(GT))).width(Length::Units(FLAGS_WIDTH)), + "GU" => Image::new(Handle::from_memory(Vec::from(GU))).width(Length::Units(FLAGS_WIDTH)), + "GW" => Image::new(Handle::from_memory(Vec::from(GW))).width(Length::Units(FLAGS_WIDTH)), + "GY" => Image::new(Handle::from_memory(Vec::from(GY))).width(Length::Units(FLAGS_WIDTH)), + "HK" => Image::new(Handle::from_memory(Vec::from(HK))).width(Length::Units(FLAGS_WIDTH)), + "HM" => Image::new(Handle::from_memory(Vec::from(HM))).width(Length::Units(FLAGS_WIDTH)), + "HN" => Image::new(Handle::from_memory(Vec::from(HN))).width(Length::Units(FLAGS_WIDTH)), + "HR" => Image::new(Handle::from_memory(Vec::from(HR))).width(Length::Units(FLAGS_WIDTH)), + "HT" => Image::new(Handle::from_memory(Vec::from(HT))).width(Length::Units(FLAGS_WIDTH)), + "HU" => Image::new(Handle::from_memory(Vec::from(HU))).width(Length::Units(FLAGS_WIDTH)), + "ID" => Image::new(Handle::from_memory(Vec::from(ID))).width(Length::Units(FLAGS_WIDTH)), + "IE" => Image::new(Handle::from_memory(Vec::from(IE))).width(Length::Units(FLAGS_WIDTH)), + "IL" => Image::new(Handle::from_memory(Vec::from(IL))).width(Length::Units(FLAGS_WIDTH)), + "IM" => Image::new(Handle::from_memory(Vec::from(IM))).width(Length::Units(FLAGS_WIDTH)), + "IN" => Image::new(Handle::from_memory(Vec::from(IN))).width(Length::Units(FLAGS_WIDTH)), + "IO" => Image::new(Handle::from_memory(Vec::from(IO))).width(Length::Units(FLAGS_WIDTH)), + "IQ" => Image::new(Handle::from_memory(Vec::from(IQ))).width(Length::Units(FLAGS_WIDTH)), + "IR" => Image::new(Handle::from_memory(Vec::from(IR))).width(Length::Units(FLAGS_WIDTH)), + "IS" => Image::new(Handle::from_memory(Vec::from(IS))).width(Length::Units(FLAGS_WIDTH)), + "IT" => Image::new(Handle::from_memory(Vec::from(IT))).width(Length::Units(FLAGS_WIDTH)), + "JE" => Image::new(Handle::from_memory(Vec::from(JE))).width(Length::Units(FLAGS_WIDTH)), + "JM" => Image::new(Handle::from_memory(Vec::from(JM))).width(Length::Units(FLAGS_WIDTH)), + "JO" => Image::new(Handle::from_memory(Vec::from(JO))).width(Length::Units(FLAGS_WIDTH)), + "JP" => Image::new(Handle::from_memory(Vec::from(JP))).width(Length::Units(FLAGS_WIDTH)), + "KE" => Image::new(Handle::from_memory(Vec::from(KE))).width(Length::Units(FLAGS_WIDTH)), + "KG" => Image::new(Handle::from_memory(Vec::from(KG))).width(Length::Units(FLAGS_WIDTH)), + "KH" => Image::new(Handle::from_memory(Vec::from(KH))).width(Length::Units(FLAGS_WIDTH)), + "KI" => Image::new(Handle::from_memory(Vec::from(KI))).width(Length::Units(FLAGS_WIDTH)), + "KM" => Image::new(Handle::from_memory(Vec::from(KM))).width(Length::Units(FLAGS_WIDTH)), + "KN" => Image::new(Handle::from_memory(Vec::from(KN))).width(Length::Units(FLAGS_WIDTH)), + "KP" => Image::new(Handle::from_memory(Vec::from(KP))).width(Length::Units(FLAGS_WIDTH)), + "KR" => Image::new(Handle::from_memory(Vec::from(KR))).width(Length::Units(FLAGS_WIDTH)), + "KW" => Image::new(Handle::from_memory(Vec::from(KW))).width(Length::Units(FLAGS_WIDTH)), + "KY" => Image::new(Handle::from_memory(Vec::from(KY))).width(Length::Units(FLAGS_WIDTH)), + "KZ" => Image::new(Handle::from_memory(Vec::from(KZ))).width(Length::Units(FLAGS_WIDTH)), + "LA" => Image::new(Handle::from_memory(Vec::from(LA))).width(Length::Units(FLAGS_WIDTH)), + "LB" => Image::new(Handle::from_memory(Vec::from(LB))).width(Length::Units(FLAGS_WIDTH)), + "LC" => Image::new(Handle::from_memory(Vec::from(LC))).width(Length::Units(FLAGS_WIDTH)), + "LI" => Image::new(Handle::from_memory(Vec::from(LI))).width(Length::Units(FLAGS_WIDTH)), + "LK" => Image::new(Handle::from_memory(Vec::from(LK))).width(Length::Units(FLAGS_WIDTH)), + "LR" => Image::new(Handle::from_memory(Vec::from(LR))).width(Length::Units(FLAGS_WIDTH)), + "LS" => Image::new(Handle::from_memory(Vec::from(LS))).width(Length::Units(FLAGS_WIDTH)), + "LT" => Image::new(Handle::from_memory(Vec::from(LT))).width(Length::Units(FLAGS_WIDTH)), + "LU" => Image::new(Handle::from_memory(Vec::from(LU))).width(Length::Units(FLAGS_WIDTH)), + "LV" => Image::new(Handle::from_memory(Vec::from(LV))).width(Length::Units(FLAGS_WIDTH)), + "LY" => Image::new(Handle::from_memory(Vec::from(LY))).width(Length::Units(FLAGS_WIDTH)), + "MA" => Image::new(Handle::from_memory(Vec::from(MA))).width(Length::Units(FLAGS_WIDTH)), + "MC" => Image::new(Handle::from_memory(Vec::from(MC))).width(Length::Units(FLAGS_WIDTH)), + "MD" => Image::new(Handle::from_memory(Vec::from(MD))).width(Length::Units(FLAGS_WIDTH)), + "ME" => Image::new(Handle::from_memory(Vec::from(ME))).width(Length::Units(FLAGS_WIDTH)), + "MF" => Image::new(Handle::from_memory(Vec::from(MF))).width(Length::Units(FLAGS_WIDTH)), + "MG" => Image::new(Handle::from_memory(Vec::from(MG))).width(Length::Units(FLAGS_WIDTH)), + "MH" => Image::new(Handle::from_memory(Vec::from(MH))).width(Length::Units(FLAGS_WIDTH)), + "MK" => Image::new(Handle::from_memory(Vec::from(MK))).width(Length::Units(FLAGS_WIDTH)), + "ML" => Image::new(Handle::from_memory(Vec::from(ML))).width(Length::Units(FLAGS_WIDTH)), + "MM" => Image::new(Handle::from_memory(Vec::from(MM))).width(Length::Units(FLAGS_WIDTH)), + "MN" => Image::new(Handle::from_memory(Vec::from(MN))).width(Length::Units(FLAGS_WIDTH)), + "MO" => Image::new(Handle::from_memory(Vec::from(MO))).width(Length::Units(FLAGS_WIDTH)), + "MP" => Image::new(Handle::from_memory(Vec::from(MP))).width(Length::Units(FLAGS_WIDTH)), + "MQ" => Image::new(Handle::from_memory(Vec::from(MQ))).width(Length::Units(FLAGS_WIDTH)), + "MR" => Image::new(Handle::from_memory(Vec::from(MR))).width(Length::Units(FLAGS_WIDTH)), + "MS" => Image::new(Handle::from_memory(Vec::from(MS))).width(Length::Units(FLAGS_WIDTH)), + "MT" => Image::new(Handle::from_memory(Vec::from(MT))).width(Length::Units(FLAGS_WIDTH)), + "MU" => Image::new(Handle::from_memory(Vec::from(MU))).width(Length::Units(FLAGS_WIDTH)), + "MV" => Image::new(Handle::from_memory(Vec::from(MV))).width(Length::Units(FLAGS_WIDTH)), + "MW" => Image::new(Handle::from_memory(Vec::from(MW))).width(Length::Units(FLAGS_WIDTH)), + "MX" => Image::new(Handle::from_memory(Vec::from(MX))).width(Length::Units(FLAGS_WIDTH)), + "MY" => Image::new(Handle::from_memory(Vec::from(MY))).width(Length::Units(FLAGS_WIDTH)), + "MZ" => Image::new(Handle::from_memory(Vec::from(MZ))).width(Length::Units(FLAGS_WIDTH)), + "NA" => Image::new(Handle::from_memory(Vec::from(NA))).width(Length::Units(FLAGS_WIDTH)), + "NC" => Image::new(Handle::from_memory(Vec::from(NC))).width(Length::Units(FLAGS_WIDTH)), + "NE" => Image::new(Handle::from_memory(Vec::from(NE))).width(Length::Units(FLAGS_WIDTH)), + "NF" => Image::new(Handle::from_memory(Vec::from(NF))).width(Length::Units(FLAGS_WIDTH)), + "NG" => Image::new(Handle::from_memory(Vec::from(NG))).width(Length::Units(FLAGS_WIDTH)), + "NI" => Image::new(Handle::from_memory(Vec::from(NI))).width(Length::Units(FLAGS_WIDTH)), + "NL" => Image::new(Handle::from_memory(Vec::from(NL))).width(Length::Units(FLAGS_WIDTH)), + "NO" => Image::new(Handle::from_memory(Vec::from(NO))).width(Length::Units(FLAGS_WIDTH)), + "NP" => Image::new(Handle::from_memory(Vec::from(NP))).width(Length::Units(FLAGS_WIDTH)), + "NR" => Image::new(Handle::from_memory(Vec::from(NR))).width(Length::Units(FLAGS_WIDTH)), + "NU" => Image::new(Handle::from_memory(Vec::from(NU))).width(Length::Units(FLAGS_WIDTH)), + "NZ" => Image::new(Handle::from_memory(Vec::from(NZ))).width(Length::Units(FLAGS_WIDTH)), + "OM" => Image::new(Handle::from_memory(Vec::from(OM))).width(Length::Units(FLAGS_WIDTH)), + "PA" => Image::new(Handle::from_memory(Vec::from(PA))).width(Length::Units(FLAGS_WIDTH)), + "PE" => Image::new(Handle::from_memory(Vec::from(PE))).width(Length::Units(FLAGS_WIDTH)), + "PF" => Image::new(Handle::from_memory(Vec::from(PF))).width(Length::Units(FLAGS_WIDTH)), + "PG" => Image::new(Handle::from_memory(Vec::from(PG))).width(Length::Units(FLAGS_WIDTH)), + "PH" => Image::new(Handle::from_memory(Vec::from(PH))).width(Length::Units(FLAGS_WIDTH)), + "PK" => Image::new(Handle::from_memory(Vec::from(PK))).width(Length::Units(FLAGS_WIDTH)), + "PL" => Image::new(Handle::from_memory(Vec::from(PL))).width(Length::Units(FLAGS_WIDTH)), + "PM" => Image::new(Handle::from_memory(Vec::from(PM))).width(Length::Units(FLAGS_WIDTH)), + "PN" => Image::new(Handle::from_memory(Vec::from(PN))).width(Length::Units(FLAGS_WIDTH)), + "PR" => Image::new(Handle::from_memory(Vec::from(PR))).width(Length::Units(FLAGS_WIDTH)), + "PS" => Image::new(Handle::from_memory(Vec::from(PS))).width(Length::Units(FLAGS_WIDTH)), + "PT" => Image::new(Handle::from_memory(Vec::from(PT))).width(Length::Units(FLAGS_WIDTH)), + "PW" => Image::new(Handle::from_memory(Vec::from(PW))).width(Length::Units(FLAGS_WIDTH)), + "PY" => Image::new(Handle::from_memory(Vec::from(PY))).width(Length::Units(FLAGS_WIDTH)), + "QA" => Image::new(Handle::from_memory(Vec::from(QA))).width(Length::Units(FLAGS_WIDTH)), + "RE" => Image::new(Handle::from_memory(Vec::from(RE))).width(Length::Units(FLAGS_WIDTH)), + "RO" => Image::new(Handle::from_memory(Vec::from(RO))).width(Length::Units(FLAGS_WIDTH)), + "RS" => Image::new(Handle::from_memory(Vec::from(RS))).width(Length::Units(FLAGS_WIDTH)), + "RU" => Image::new(Handle::from_memory(Vec::from(RU))).width(Length::Units(FLAGS_WIDTH)), + "RW" => Image::new(Handle::from_memory(Vec::from(RW))).width(Length::Units(FLAGS_WIDTH)), + "SA" => Image::new(Handle::from_memory(Vec::from(SA))).width(Length::Units(FLAGS_WIDTH)), + "SB" => Image::new(Handle::from_memory(Vec::from(SB))).width(Length::Units(FLAGS_WIDTH)), + "SC" => Image::new(Handle::from_memory(Vec::from(SC))).width(Length::Units(FLAGS_WIDTH)), + "SD" => Image::new(Handle::from_memory(Vec::from(SD))).width(Length::Units(FLAGS_WIDTH)), + "SE" => Image::new(Handle::from_memory(Vec::from(SE))).width(Length::Units(FLAGS_WIDTH)), + "SG" => Image::new(Handle::from_memory(Vec::from(SG))).width(Length::Units(FLAGS_WIDTH)), + "SH" => Image::new(Handle::from_memory(Vec::from(SH))).width(Length::Units(FLAGS_WIDTH)), + "SI" => Image::new(Handle::from_memory(Vec::from(SI))).width(Length::Units(FLAGS_WIDTH)), + "SJ" => Image::new(Handle::from_memory(Vec::from(SJ))).width(Length::Units(FLAGS_WIDTH)), + "SK" => Image::new(Handle::from_memory(Vec::from(SK))).width(Length::Units(FLAGS_WIDTH)), + "SL" => Image::new(Handle::from_memory(Vec::from(SL))).width(Length::Units(FLAGS_WIDTH)), + "SM" => Image::new(Handle::from_memory(Vec::from(SM))).width(Length::Units(FLAGS_WIDTH)), + "SN" => Image::new(Handle::from_memory(Vec::from(SN))).width(Length::Units(FLAGS_WIDTH)), + "SO" => Image::new(Handle::from_memory(Vec::from(SO))).width(Length::Units(FLAGS_WIDTH)), + "SR" => Image::new(Handle::from_memory(Vec::from(SR))).width(Length::Units(FLAGS_WIDTH)), + "SS" => Image::new(Handle::from_memory(Vec::from(SS))).width(Length::Units(FLAGS_WIDTH)), + "ST" => Image::new(Handle::from_memory(Vec::from(ST))).width(Length::Units(FLAGS_WIDTH)), + "SV" => Image::new(Handle::from_memory(Vec::from(SV))).width(Length::Units(FLAGS_WIDTH)), + "SX" => Image::new(Handle::from_memory(Vec::from(SX))).width(Length::Units(FLAGS_WIDTH)), + "SY" => Image::new(Handle::from_memory(Vec::from(SY))).width(Length::Units(FLAGS_WIDTH)), + "SZ" => Image::new(Handle::from_memory(Vec::from(SZ))).width(Length::Units(FLAGS_WIDTH)), + "TC" => Image::new(Handle::from_memory(Vec::from(TC))).width(Length::Units(FLAGS_WIDTH)), + "TD" => Image::new(Handle::from_memory(Vec::from(TD))).width(Length::Units(FLAGS_WIDTH)), + "TF" => Image::new(Handle::from_memory(Vec::from(TF))).width(Length::Units(FLAGS_WIDTH)), + "TG" => Image::new(Handle::from_memory(Vec::from(TG))).width(Length::Units(FLAGS_WIDTH)), + "TH" => Image::new(Handle::from_memory(Vec::from(TH))).width(Length::Units(FLAGS_WIDTH)), + "TJ" => Image::new(Handle::from_memory(Vec::from(TJ))).width(Length::Units(FLAGS_WIDTH)), + "TK" => Image::new(Handle::from_memory(Vec::from(TK))).width(Length::Units(FLAGS_WIDTH)), + "TL" => Image::new(Handle::from_memory(Vec::from(TL))).width(Length::Units(FLAGS_WIDTH)), + "TM" => Image::new(Handle::from_memory(Vec::from(TM))).width(Length::Units(FLAGS_WIDTH)), + "TN" => Image::new(Handle::from_memory(Vec::from(TN))).width(Length::Units(FLAGS_WIDTH)), + "TO" => Image::new(Handle::from_memory(Vec::from(TO))).width(Length::Units(FLAGS_WIDTH)), + "TR" => Image::new(Handle::from_memory(Vec::from(TR))).width(Length::Units(FLAGS_WIDTH)), + "TT" => Image::new(Handle::from_memory(Vec::from(TT))).width(Length::Units(FLAGS_WIDTH)), + "TV" => Image::new(Handle::from_memory(Vec::from(TV))).width(Length::Units(FLAGS_WIDTH)), + "TW" => Image::new(Handle::from_memory(Vec::from(TW))).width(Length::Units(FLAGS_WIDTH)), + "TZ" => Image::new(Handle::from_memory(Vec::from(TZ))).width(Length::Units(FLAGS_WIDTH)), + "UA" => Image::new(Handle::from_memory(Vec::from(UA))).width(Length::Units(FLAGS_WIDTH)), + "UG" => Image::new(Handle::from_memory(Vec::from(UG))).width(Length::Units(FLAGS_WIDTH)), + "UM" => Image::new(Handle::from_memory(Vec::from(UM))).width(Length::Units(FLAGS_WIDTH)), + "US" => Image::new(Handle::from_memory(Vec::from(US))).width(Length::Units(FLAGS_WIDTH)), + "UY" => Image::new(Handle::from_memory(Vec::from(UY))).width(Length::Units(FLAGS_WIDTH)), + "UZ" => Image::new(Handle::from_memory(Vec::from(UZ))).width(Length::Units(FLAGS_WIDTH)), + "VA" => Image::new(Handle::from_memory(Vec::from(VA))).width(Length::Units(FLAGS_WIDTH)), + "VC" => Image::new(Handle::from_memory(Vec::from(VC))).width(Length::Units(FLAGS_WIDTH)), + "VE" => Image::new(Handle::from_memory(Vec::from(VE))).width(Length::Units(FLAGS_WIDTH)), + "VG" => Image::new(Handle::from_memory(Vec::from(VG))).width(Length::Units(FLAGS_WIDTH)), + "VI" => Image::new(Handle::from_memory(Vec::from(VI))).width(Length::Units(FLAGS_WIDTH)), + "VN" => Image::new(Handle::from_memory(Vec::from(VN))).width(Length::Units(FLAGS_WIDTH)), + "VU" => Image::new(Handle::from_memory(Vec::from(VU))).width(Length::Units(FLAGS_WIDTH)), + "WF" => Image::new(Handle::from_memory(Vec::from(WF))).width(Length::Units(FLAGS_WIDTH)), + "WS" => Image::new(Handle::from_memory(Vec::from(WS))).width(Length::Units(FLAGS_WIDTH)), + "YE" => Image::new(Handle::from_memory(Vec::from(YE))).width(Length::Units(FLAGS_WIDTH)), + "YT" => Image::new(Handle::from_memory(Vec::from(YT))).width(Length::Units(FLAGS_WIDTH)), + "ZA" => Image::new(Handle::from_memory(Vec::from(ZA))).width(Length::Units(FLAGS_WIDTH)), + "ZM" => Image::new(Handle::from_memory(Vec::from(ZM))).width(Length::Units(FLAGS_WIDTH)), + "ZW" => Image::new(Handle::from_memory(Vec::from(ZW))).width(Length::Units(FLAGS_WIDTH)), + _ => Image::new(Handle::from_memory(Vec::from(UNKNOWN))).width(Length::Units(15)), + } +} diff --git a/src/utility/get_formatted_strings.rs b/src/utility/get_formatted_strings.rs index a393e7e7..2473aaf3 100644 --- a/src/utility/get_formatted_strings.rs +++ b/src/utility/get_formatted_strings.rs @@ -1,17 +1,19 @@ use std::cmp::Ordering; use std::collections::HashMap; -use std::sync::{Arc, Mutex}; use iced::Color; use thousands::Separable; use crate::enums::traffic_type::TrafficType; -use crate::gui::style::{SPECIAL_DAY, SPECIAL_NIGHT}; use crate::structs::filters::Filters; -use crate::{AppProtocol, IpVersion, TransProtocol}; +use crate::utility::translations::{active_filters_translation, none_translation}; +use crate::{get_colors, AppProtocol, IpVersion, Language, StyleType, TransProtocol}; + +/// Application version number (to be displayed in gui footer) +pub const APP_VERSION: &str = env!("CARGO_PKG_VERSION"); /// Computes the String representing the percentage of filtered bytes/packets -pub fn get_percentage_string(observed: u128, filtered: i128) -> String { +pub fn get_percentage_string(observed: u128, filtered: u128) -> String { if format!("{:.1}", 100.0 * (filtered) as f32 / observed as f32).eq("0.0") { "<0.1%".to_string() } else { @@ -20,50 +22,52 @@ pub fn get_percentage_string(observed: u128, filtered: i128) -> String { } /// Computes the String representing the active filters -pub fn get_active_filters_string(filters: Arc>) -> String { - let filters_lock = filters.lock().unwrap(); - if filters_lock.ip.eq(&IpVersion::Other) - && filters_lock.application.eq(&AppProtocol::Other) - && filters_lock.transport.eq(&TransProtocol::Other) +pub fn get_active_filters_string(filters: &Filters, language: Language) -> String { + if filters.ip.eq(&IpVersion::Other) + && filters.application.eq(&AppProtocol::Other) + && filters.transport.eq(&TransProtocol::Other) { - "Active filters:\n none".to_string() + format!( + "{}\n {}", + active_filters_translation(language), + none_translation(language) + ) } else { - let mut ret_val = "Active filters:".to_string(); - if filters_lock.ip.ne(&IpVersion::Other) { - ret_val.push_str(&format!("\n {}", filters_lock.ip)); + let mut ret_val = active_filters_translation(language).to_string(); + if filters.ip.ne(&IpVersion::Other) { + ret_val.push_str(&format!("\n {}", filters.ip)); } - if filters_lock.transport.ne(&TransProtocol::Other) { - ret_val.push_str(&format!("\n {}", filters_lock.transport)); + if filters.transport.ne(&TransProtocol::Other) { + ret_val.push_str(&format!("\n {}", filters.transport)); } - if filters_lock.application.ne(&AppProtocol::Other) { - ret_val.push_str(&format!("\n {}", filters_lock.application)); + if filters.application.ne(&AppProtocol::Other) { + ret_val.push_str(&format!("\n {}", filters.application)); } ret_val } } /// Computes the String representing the active filters, without line breaks -pub fn get_active_filters_string_nobr(filters: Arc>) -> String { - let filters_lock = filters.lock().unwrap(); - let mut ret_val = "Active filters:".to_string(); - if filters_lock.ip.ne(&IpVersion::Other) { - ret_val.push_str(&format!(" {}", filters_lock.ip)); +pub fn get_active_filters_string_nobr(filters: &Filters, language: Language) -> String { + let mut ret_val = active_filters_translation(language).to_string(); + if filters.ip.ne(&IpVersion::Other) { + ret_val.push_str(&format!(" {}", filters.ip)); } - if filters_lock.transport.ne(&TransProtocol::Other) { - ret_val.push_str(&format!(" {}", filters_lock.transport)); + if filters.transport.ne(&TransProtocol::Other) { + ret_val.push_str(&format!(" {}", filters.transport)); } - if filters_lock.application.ne(&AppProtocol::Other) { - ret_val.push_str(&format!(" {}", filters_lock.application)); + if filters.application.ne(&AppProtocol::Other) { + ret_val.push_str(&format!(" {}", filters.application)); } ret_val } /// Returns the color to be used for a specific connection of the relevant connections table in gui run page -pub fn get_connection_color(traffic_type: TrafficType) -> Color { - if traffic_type == TrafficType::Incoming || traffic_type == TrafficType::Multicast { - SPECIAL_NIGHT +pub fn get_connection_color(traffic_type: TrafficType, style: StyleType) -> Color { + if traffic_type == TrafficType::Outgoing { + get_colors(style).outgoing } else { - SPECIAL_DAY + get_colors(style).incoming } } @@ -76,8 +80,8 @@ pub fn get_connection_color(traffic_type: TrafficType) -> Color { /// * `app_count` - Map of app layer protocols with the relative sniffed packets count /// /// * `tot_packets` - Total number of sniffed packets -pub fn get_app_count_string(app_count: HashMap, tot_packets: u128) -> String { - let mut ret_val = "".to_string(); +pub fn get_app_count_string(app_count: &HashMap, tot_packets: u128) -> String { + let mut ret_val = String::new(); if app_count.is_empty() { return ret_val; @@ -135,16 +139,16 @@ pub fn get_app_count_string(app_count: HashMap, tot_packets: ret_val } -/// Returns a String representing a quantity of bytes with their proper multiple (kB, MB, GB, TB) +/// Returns a String representing a quantity of bytes with their proper multiple (KB, MB, GB, TB) pub fn get_formatted_bytes_string(bytes: u128) -> String { - let mut multiple_transmitted = "".to_string(); + let mut multiple_transmitted = String::new(); let mut n = bytes as f32; match bytes { 0..=999 => {} 1_000..=999_999 => { n /= 1000_f32; - multiple_transmitted.push('k'); + multiple_transmitted.push('K'); } // kilo 1_000_000..=999_999_999 => { n /= 1_000_000_f32; @@ -160,11 +164,11 @@ pub fn get_formatted_bytes_string(bytes: u128) -> String { } // tera } - if !multiple_transmitted.is_empty() { - // with multiple - format!("{n:.1} {multiple_transmitted}B") - } else { + if multiple_transmitted.is_empty() { // no multiple - format!("{n} B") + format!("{n} ") + } else { + // with multiple + format!("{n:.1} {multiple_transmitted} ") } } diff --git a/src/utility/manage_charts_data.rs b/src/utility/manage_charts_data.rs index 5b5a0552..8dff54b8 100644 --- a/src/utility/manage_charts_data.rs +++ b/src/utility/manage_charts_data.rs @@ -1,19 +1,18 @@ +use std::cell::RefMut; use std::collections::VecDeque; -use std::sync::{Arc, Mutex}; use crate::RunTimeData; /// This function is invoked every second by the application subscription /// /// It updates data (packets and bytes per second) to be displayed in the charts of gui run page -pub fn update_charts_data(charts_data_mutex: Arc>) { - let mut charts_data = charts_data_mutex.lock().unwrap(); +pub fn update_charts_data(mut charts_data: RefMut) { let tot_seconds = charts_data.ticks; charts_data.ticks += 1; - let sent_bytes_entry = charts_data.tot_sent_bytes_prev - charts_data.tot_sent_bytes; + let sent_bytes_entry = charts_data.tot_sent_bytes - charts_data.tot_sent_bytes_prev; let received_bytes_entry = charts_data.tot_received_bytes - charts_data.tot_received_bytes_prev; - let sent_packets_entry = charts_data.tot_sent_packets_prev - charts_data.tot_sent_packets; + let sent_packets_entry = charts_data.tot_sent_packets - charts_data.tot_sent_packets_prev; let received_packets_entry = charts_data.tot_received_packets - charts_data.tot_received_packets_prev; @@ -21,10 +20,11 @@ pub fn update_charts_data(charts_data_mutex: Arc>) { if charts_data.sent_bytes.len() >= 30 { charts_data.sent_bytes.pop_front(); } - charts_data - .sent_bytes - .push_back((tot_seconds, sent_bytes_entry)); - charts_data.min_sent_bytes = get_min(charts_data.sent_bytes.clone()); + charts_data.sent_bytes.push_back(( + tot_seconds, + ->::try_into(sent_bytes_entry).unwrap(), + )); + charts_data.min_sent_bytes = get_min(&charts_data.sent_bytes.clone()); charts_data.tot_sent_bytes_prev = charts_data.tot_sent_bytes; // update received bytes traffic data if charts_data.received_bytes.len() >= 30 { @@ -32,18 +32,19 @@ pub fn update_charts_data(charts_data_mutex: Arc>) { } charts_data .received_bytes - .push_back((tot_seconds, received_bytes_entry)); - charts_data.max_received_bytes = get_max(charts_data.received_bytes.clone()); + .push_back((tot_seconds, received_bytes_entry.try_into().unwrap())); + charts_data.max_received_bytes = get_max(&charts_data.received_bytes.clone()); charts_data.tot_received_bytes_prev = charts_data.tot_received_bytes; // update sent packets traffic data if charts_data.sent_packets.len() >= 30 { charts_data.sent_packets.pop_front(); } - charts_data - .sent_packets - .push_back((tot_seconds, sent_packets_entry)); - charts_data.min_sent_packets = get_min(charts_data.sent_packets.clone()); + charts_data.sent_packets.push_back(( + tot_seconds, + ->::try_into(sent_packets_entry).unwrap(), + )); + charts_data.min_sent_packets = get_min(&charts_data.sent_packets.clone()); charts_data.tot_sent_packets_prev = charts_data.tot_sent_packets; // update received packets traffic data if charts_data.received_packets.len() >= 30 { @@ -51,13 +52,13 @@ pub fn update_charts_data(charts_data_mutex: Arc>) { } charts_data .received_packets - .push_back((tot_seconds, received_packets_entry)); - charts_data.max_received_packets = get_max(charts_data.received_packets.clone()); + .push_back((tot_seconds, received_packets_entry.try_into().unwrap())); + charts_data.max_received_packets = get_max(&charts_data.received_packets.clone()); charts_data.tot_received_packets_prev = charts_data.tot_received_packets; } /// Finds the minimum y value to be displayed in charts -fn get_min(deque: VecDeque<(u128, i128)>) -> i128 { +fn get_min(deque: &VecDeque<(u32, i64)>) -> i64 { let mut min = 0; for (_, x) in deque.iter() { if *x < min { @@ -68,7 +69,7 @@ fn get_min(deque: VecDeque<(u128, i128)>) -> i128 { } /// Finds the maximum y value to be displayed in charts -fn get_max(deque: VecDeque<(u128, i128)>) -> i128 { +fn get_max(deque: &VecDeque<(u32, i64)>) -> i64 { let mut max = 0; for (_, x) in deque.iter() { if *x > max { diff --git a/src/utility/manage_notifications.rs b/src/utility/manage_notifications.rs new file mode 100644 index 00000000..74ce9eea --- /dev/null +++ b/src/utility/manage_notifications.rs @@ -0,0 +1,98 @@ +use crate::enums::logged_notification::{ + BytesThresholdExceeded, FavoriteTransmitted, LoggedNotification, PacketsThresholdExceeded, +}; +use crate::enums::sound::{play_sound, Sound}; +use crate::structs::notifications::Notifications; +use crate::RunTimeData; +use chrono::Local; +use std::cell::RefMut; + +pub fn notify_and_log(mut runtime_data: RefMut, notifications: Notifications) { + let mut already_emitted_sound = false; + // packets threshold + if notifications.packets_notification.threshold.is_some() { + let sent_packets_entry = runtime_data.tot_sent_packets - runtime_data.tot_sent_packets_prev; + let received_packets_entry = + runtime_data.tot_received_packets - runtime_data.tot_received_packets_prev; + if received_packets_entry + sent_packets_entry + > u128::from(notifications.packets_notification.threshold.unwrap()) + { + // log this notification + if runtime_data.logged_notifications.len() >= 30 { + runtime_data.logged_notifications.pop_back(); + } + runtime_data.logged_notifications.push_front( + LoggedNotification::PacketsThresholdExceeded(PacketsThresholdExceeded { + notification: notifications.packets_notification, + incoming: received_packets_entry.try_into().unwrap(), + outgoing: sent_packets_entry.try_into().unwrap(), + timestamp: Local::now().to_string().get(11..19).unwrap().to_string(), + }), + ); + if notifications.packets_notification.sound.ne(&Sound::None) { + // emit sound + play_sound( + notifications.packets_notification.sound, + notifications.volume, + ); + already_emitted_sound = true; + } + } + } + // bytes threshold + if notifications.bytes_notification.threshold.is_some() { + let sent_bytes_entry = runtime_data.tot_sent_bytes - runtime_data.tot_sent_bytes_prev; + let received_bytes_entry = + runtime_data.tot_received_bytes - runtime_data.tot_received_bytes_prev; + if received_bytes_entry + sent_bytes_entry + > u128::from(notifications.bytes_notification.threshold.unwrap()) + { + //log this notification + if runtime_data.logged_notifications.len() >= 30 { + runtime_data.logged_notifications.pop_back(); + } + runtime_data.logged_notifications.push_front( + LoggedNotification::BytesThresholdExceeded(BytesThresholdExceeded { + notification: notifications.bytes_notification, + incoming: received_bytes_entry.try_into().unwrap(), + outgoing: sent_bytes_entry.try_into().unwrap(), + timestamp: Local::now().to_string().get(11..19).unwrap().to_string(), + }), + ); + if !already_emitted_sound && notifications.bytes_notification.sound.ne(&Sound::None) { + // emit sound + play_sound(notifications.bytes_notification.sound, notifications.volume); + already_emitted_sound = true; + } + } + } + // from favorites + if notifications.favorite_notification.notify_on_favorite + && runtime_data.favorite_featured_last_interval.is_some() + { + //log this notification + if runtime_data.logged_notifications.len() >= 30 { + runtime_data.logged_notifications.pop_back(); + } + let favorite_featured = runtime_data + .favorite_featured_last_interval + .as_ref() + .unwrap() + .clone(); + runtime_data + .logged_notifications + .push_front(LoggedNotification::FavoriteTransmitted( + FavoriteTransmitted { + connection: favorite_featured, + timestamp: Local::now().to_string().get(11..19).unwrap().to_string(), + }, + )); + if !already_emitted_sound && notifications.favorite_notification.sound.ne(&Sound::None) { + // emit sound + play_sound( + notifications.favorite_notification.sound, + notifications.volume, + ); + } + } +} diff --git a/src/utility/manage_packets.rs b/src/utility/manage_packets.rs index 56a5a616..18f193e4 100644 --- a/src/utility/manage_packets.rs +++ b/src/utility/manage_packets.rs @@ -2,11 +2,14 @@ use std::sync::{Arc, Mutex}; use chrono::Local; use etherparse::{IpHeader, TransportHeader}; +use maxminddb::Reader; +use pcap::{Active, Capture, Device}; use crate::enums::app_protocol::from_port_to_application_protocol; use crate::enums::traffic_type::TrafficType; use crate::structs::address_port_pair::AddressPortPair; use crate::structs::info_address_port_pair::InfoAddressPortPair; +use crate::utility::countries::get_country_code; use crate::{AppProtocol, InfoTraffic, IpVersion, TransProtocol}; /// This function analyzes the network layer header passed as parameter and updates variables @@ -32,13 +35,13 @@ pub fn analyze_network_header( .replace(']', "") .replace(',', ".") .replace(' ', ""); - *exchanged_bytes = ipv4header.payload_len as u128; + *exchanged_bytes = u128::from(ipv4header.payload_len); } Some(IpHeader::Version6(ipv6header, _)) => { *network_protocol = IpVersion::IPv6; *address1 = ipv6_from_long_dec_to_short_hex(ipv6header.source); *address2 = ipv6_from_long_dec_to_short_hex(ipv6header.destination); - *exchanged_bytes = ipv6header.payload_length as u128; + *exchanged_bytes = u128::from(ipv6header.payload_length); } _ => { *skip_packet = true; @@ -83,39 +86,57 @@ pub fn analyze_transport_header( /// Function to insert the source and destination of a packet into the shared map containing the analyzed traffic. pub fn modify_or_insert_in_map( - info_traffic_mutex: Arc>, + info_traffic_mutex: &Arc>, key: AddressPortPair, exchanged_bytes: u128, traffic_type: TrafficType, application_protocol: AppProtocol, + country_db_reader: &Reader<&[u8]>, ) { - let now = Local::now().to_string().get(0..19).unwrap().to_string(); - let trans_protocol = key.trans_protocol; + let now = Local::now(); let very_long_address = key.address1.len() > 25 || key.address2.len() > 25; let mut info_traffic = info_traffic_mutex .lock() .expect("Error acquiring mutex\n\r"); let len = info_traffic.map.len(); let index = info_traffic.map.get_index_of(&key).unwrap_or(len); + let country = if index == len { + // first occurrence of key => retrieve country code + get_country_code(traffic_type, &key, country_db_reader) + } else { + // this key already occurred + String::new() + }; + let is_already_featured = info_traffic.favorite_featured_last_interval.is_some(); + let mut update_favorite_featured = false; info_traffic .map - .entry(key) + .entry(key.clone()) .and_modify(|info| { info.transmitted_bytes += exchanged_bytes; info.transmitted_packets += 1; - info.final_timestamp = now.clone(); + info.final_timestamp = now; + if info.is_favorite && !is_already_featured { + update_favorite_featured = true; + } }) .or_insert(InfoAddressPortPair { transmitted_bytes: exchanged_bytes, transmitted_packets: 1, - initial_timestamp: now.clone(), + initial_timestamp: now, final_timestamp: now, - trans_protocol, app_protocol: application_protocol, very_long_address, traffic_type, + country, + index, + is_favorite: false, }); info_traffic.addresses_last_interval.insert(index); + if update_favorite_featured { + let info = info_traffic.map.get(&key).unwrap().clone(); + info_traffic.favorite_featured_last_interval = Some((key, info)); + } } /// Determines if the input address is a multicast address or not. @@ -146,6 +167,47 @@ pub fn is_multicast_address(address: &str) -> bool { ret_val } +/// Determines if the input address is a broadcast address or not. +/// +/// # Arguments +/// +/// * `address` - string representing an IPv4 or IPv6 network address. +pub fn is_broadcast_address(address: &str) -> bool { + let mut ret_val = false; + if !address.contains(':') { + //IPv4 address + let groups: Vec = address + .split('.') + .map(|str| str.parse::().unwrap()) + .collect(); + if *groups.first().unwrap() == 255 + && *groups.get(1).unwrap() == 255 + && *groups.get(2).unwrap() == 255 + && *groups.get(3).unwrap() == 255 + { + ret_val = true; + } + // still missing a check for directed broadcast! + } + ret_val +} + +/// Determines if the capture opening resolves into an Error +pub fn get_capture_result(device: &Device) -> (Option, Option>) { + let cap_result = Capture::from_device(&*device.name) + .expect("Capture initialization error\n\r") + .promisc(true) + .snaplen(256) //limit stored packets slice dimension (to keep more in the buffer) + .immediate_mode(true) //parse packets ASAP! + .open(); + if cap_result.is_err() { + let err_string = cap_result.err().unwrap().to_string(); + (Some(err_string), None) + } else { + (None, cap_result.ok()) + } +} + // Test for this function at the end of this file (run with cargo test) /// Function to convert a long decimal ipv6 address to a /// shorter compressed ipv6 address @@ -162,16 +224,16 @@ pub fn is_multicast_address(address: &str) -> bool { /// ``` pub fn ipv6_from_long_dec_to_short_hex(ipv6_long: [u8; 16]) -> String { //from hex to dec, paying attention to the correct number of digits - let mut ipv6_hex = "".to_string(); + let mut ipv6_hex = String::new(); for i in 0..=15 { - //pari: primo byte del gruppo + //even: first byte of the group if i % 2 == 0 { if *ipv6_long.get(i).unwrap() == 0 { continue; } ipv6_hex.push_str(&format!("{:x}", ipv6_long.get(i).unwrap())); } - //dispari: secondo byte del gruppo + //odd: second byte of the group else if *ipv6_long.get(i - 1).unwrap() == 0 { ipv6_hex.push_str(&format!("{:x}:", ipv6_long.get(i).unwrap())); } else { @@ -215,7 +277,7 @@ pub fn ipv6_from_long_dec_to_short_hex(ipv6_long: [u8; 16]) -> String { } //from longest sequence of consecutive zeros to '::' - let mut ipv6_hex_compressed = "".to_string(); + let mut ipv6_hex_compressed = String::new(); for _ in 0..longest_zero_sequence { to_compress.remove(longest_zero_sequence_start); } @@ -240,11 +302,11 @@ pub fn ipv6_from_long_dec_to_short_hex(ipv6_long: [u8; 16]) -> String { } #[cfg(test)] -mod ipv6_format_tests { +mod test { use crate::utility::manage_packets::ipv6_from_long_dec_to_short_hex; #[test] - fn simple_test() { + fn ipv6_simple_test() { let result = ipv6_from_long_dec_to_short_hex([ 255, 10, 10, 255, 255, 10, 10, 255, 255, 10, 10, 255, 255, 10, 10, 255, ]); @@ -252,7 +314,7 @@ mod ipv6_format_tests { } #[test] - fn zeros_in_the_middle() { + fn ipv6_zeros_in_the_middle() { let result = ipv6_from_long_dec_to_short_hex([ 255, 10, 10, 255, 0, 0, 0, 0, 28, 4, 4, 28, 255, 1, 0, 0, ]); @@ -260,84 +322,84 @@ mod ipv6_format_tests { } #[test] - fn leading_zeros() { + fn ipv6_leading_zeros() { let result = ipv6_from_long_dec_to_short_hex([0, 0, 0, 0, 0, 0, 0, 0, 28, 4, 4, 28, 255, 1, 0, 10]); assert_eq!(result, "::1c04:41c:ff01:a".to_string()); } #[test] - fn tail_one_after_zeros() { + fn ipv6_tail_one_after_zeros() { let result = ipv6_from_long_dec_to_short_hex([28, 4, 4, 28, 255, 1, 0, 10, 0, 0, 0, 0, 0, 0, 0, 1]); assert_eq!(result, "1c04:41c:ff01:a::1".to_string()); } #[test] - fn tail_zeros() { + fn ipv6_tail_zeros() { let result = ipv6_from_long_dec_to_short_hex([28, 4, 4, 28, 255, 1, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0]); assert_eq!(result, "1c04:41c:ff01:a::".to_string()); } #[test] - fn multiple_zero_sequences_first_longer() { + fn ipv6_multiple_zero_sequences_first_longer() { let result = ipv6_from_long_dec_to_short_hex([32, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1]); assert_eq!(result, "2000::101:0:0:1".to_string()); } #[test] - fn multiple_zero_sequences_first_longer_head() { + fn ipv6_multiple_zero_sequences_first_longer_head() { let result = ipv6_from_long_dec_to_short_hex([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1]); assert_eq!(result, "::101:0:0:1".to_string()); } #[test] - fn multiple_zero_sequences_second_longer() { + fn ipv6_multiple_zero_sequences_second_longer() { let result = ipv6_from_long_dec_to_short_hex([1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 118]); assert_eq!(result, "100:0:0:1::376".to_string()); } #[test] - fn multiple_zero_sequences_second_longer_tail() { + fn ipv6_multiple_zero_sequences_second_longer_tail() { let result = ipv6_from_long_dec_to_short_hex([32, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0]); assert_eq!(result, "2000:0:0:1:101::".to_string()); } #[test] - fn multiple_zero_sequences_equal_length() { + fn ipv6_multiple_zero_sequences_equal_length() { let result = ipv6_from_long_dec_to_short_hex([118, 3, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1]); assert_eq!(result, "7603::1:101:0:0:1".to_string()); } #[test] - fn all_zeros() { + fn ipv6_all_zeros() { let result = ipv6_from_long_dec_to_short_hex([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); assert_eq!(result, "::".to_string()); } #[test] - fn x_all_zeros() { + fn ipv6_x_all_zeros() { let result = ipv6_from_long_dec_to_short_hex([161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); assert_eq!(result, "a100::".to_string()); } #[test] - fn all_zeros_x() { + fn ipv6_all_zeros_x() { let result = ipv6_from_long_dec_to_short_hex([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176]); assert_eq!(result, "::b0".to_string()); } #[test] - fn many_zeros_but_no_compression() { + fn ipv6_many_zeros_but_no_compression() { let result = ipv6_from_long_dec_to_short_hex([0, 16, 16, 0, 0, 1, 7, 0, 0, 2, 216, 0, 1, 0, 0, 1]); assert_eq!(result, "10:1000:1:700:2:d800:100:1".to_string()); diff --git a/src/utility/manage_report_data.rs b/src/utility/manage_report_data.rs new file mode 100644 index 00000000..30798a7d --- /dev/null +++ b/src/utility/manage_report_data.rs @@ -0,0 +1,51 @@ +use crate::structs::address_port_pair::AddressPortPair; +use crate::structs::info_address_port_pair::InfoAddressPortPair; +use crate::{InfoTraffic, ReportType, RunTimeData}; +use std::cell::RefMut; +use std::cmp::min; +use std::sync::{Arc, Mutex}; + +pub fn update_report_data( + mut runtime_data: RefMut, + info_traffic: &Arc>, + report_type: ReportType, +) { + let info_traffic_lock = info_traffic.lock().unwrap(); + runtime_data.report_vec = Vec::default(); + + if report_type.ne(&ReportType::Favorites) { + let mut sorted_vec: Vec<(&AddressPortPair, &InfoAddressPortPair)> = + info_traffic_lock.map.iter().collect(); + + match report_type { + ReportType::MostRecent => { + sorted_vec.sort_by(|&(_, a), &(_, b)| b.final_timestamp.cmp(&a.final_timestamp)); + } + ReportType::MostPackets => { + sorted_vec + .sort_by(|&(_, a), &(_, b)| b.transmitted_packets.cmp(&a.transmitted_packets)); + } + ReportType::MostBytes => { + sorted_vec + .sort_by(|&(_, a), &(_, b)| b.transmitted_bytes.cmp(&a.transmitted_bytes)); + } + ReportType::Favorites => {} + } + + let n_entry = min(sorted_vec.len(), 15); + for i in 0..n_entry { + let key_val = *sorted_vec.get(i).unwrap(); + runtime_data + .report_vec + .push((key_val.0.clone(), key_val.1.clone())); + } + } else { + // favorites + for index in &info_traffic_lock.favorite_connections { + let key_val = info_traffic_lock.map.get_index(*index).unwrap(); + runtime_data + .report_vec + .push((key_val.0.clone(), key_val.1.clone())); + } + } +} diff --git a/src/utility/mod.rs b/src/utility/mod.rs index 1b365b3b..88a78978 100644 --- a/src/utility/mod.rs +++ b/src/utility/mod.rs @@ -1,3 +1,8 @@ +pub mod countries; pub mod get_formatted_strings; pub mod manage_charts_data; +pub mod manage_notifications; pub mod manage_packets; +pub mod manage_report_data; +pub mod style_constants; +pub mod translations; diff --git a/src/utility/style_constants.rs b/src/utility/style_constants.rs new file mode 100644 index 00000000..3a37872b --- /dev/null +++ b/src/utility/style_constants.rs @@ -0,0 +1,197 @@ +//! Module defining the constants used for aesthetic purposes (colors, borders...) + +use crate::{get_colors, StyleType}; +use iced::{Color, Font}; +use plotters::style::RGBColor; + +use crate::structs::palette::{to_rgb_color, Palette}; + +pub const COLOR_CHART_MIX: f64 = 1.0; + +// night theme +const PRIMARY_NIGHT: Color = Color { + r: 0.2, + g: 0.2, + b: 0.2, + a: 1.0, +}; +const SECONDARY_NIGHT: Color = Color { + r: 0.7, + g: 0.35, + b: 0.0, + a: 1.0, +}; +const BUTTONS_NIGHT: Color = Color { + r: 0.1, + g: 0.1, + b: 0.1, + a: 1.0, +}; +pub const NIGHT_STYLE: Palette = Palette { + primary: PRIMARY_NIGHT, + secondary: SECONDARY_NIGHT, + buttons: BUTTONS_NIGHT, + incoming: SECONDARY_NIGHT, + outgoing: SECONDARY_DAY, + text_headers: Color::BLACK, + text_body: Color::WHITE, + round_borders: Color::BLACK, +}; + +// day theme +const PRIMARY_DAY: Color = Color::WHITE; +const SECONDARY_DAY: Color = Color { + r: 0.0, + g: 0.35, + b: 0.7, + a: 1.0, +}; +const BUTTONS_DAY: Color = Color { + r: 0.8, + g: 0.8, + b: 0.8, + a: 1.0, +}; +pub const DAY_STYLE: Palette = Palette { + primary: PRIMARY_DAY, + secondary: SECONDARY_DAY, + buttons: BUTTONS_DAY, + incoming: SECONDARY_DAY, + outgoing: SECONDARY_NIGHT, + text_headers: Color::WHITE, + text_body: Color::BLACK, + round_borders: Color::BLACK, +}; + +// try theme +const PRIMARY_TRY: Color = Color { + r: 28.0 / 255.0, + g: 49.0 / 255.0, + b: 94.0 / 255.0, + a: 1.0, +}; +const SECONDARY_TRY: Color = Color { + r: 34.0 / 255.0, + g: 124.0 / 255.0, + b: 112.0 / 255.0, + a: 1.0, +}; +const BUTTONS_TRY: Color = Color { + r: 48.0 / 255.0, + g: 71.0 / 255.0, + b: 94.0 / 255.0, + a: 1.0, +}; +const OUTGOING_TRY: Color = Color { + r: 230.0 / 255.0, + g: 226.0 / 255.0, + b: 195.0 / 255.0, + a: 1.0, +}; +pub const TRY_STYLE: Palette = Palette { + primary: PRIMARY_TRY, + secondary: SECONDARY_TRY, + buttons: BUTTONS_TRY, + incoming: SECONDARY_TRY, + outgoing: OUTGOING_TRY, + text_headers: Color::BLACK, + text_body: Color::WHITE, + round_borders: Color::BLACK, +}; + +// red theme +const SECONDARY_RED: Color = Color { + r: 127.0 / 255.0, + g: 102.0 / 255.0, + b: 157.0 / 255.0, + a: 1.0, +}; +const PRIMARY_RED: Color = Color { + r: 245.0 / 255.0, + g: 245.0 / 255.0, + b: 220.0 / 255.0, + a: 1.0, +}; +const BUTTONS_RED: Color = Color { + r: 222.0 / 255.0, + g: 186.0 / 255.0, + b: 206.0 / 255.0, + a: 1.0, +}; +const OUTGOING_RED: Color = Color { + r: 90.0 / 255.0, + g: 164.0 / 255.0, + b: 105.0 / 255.0, + a: 1.0, +}; +pub const RED_STYLE: Palette = Palette { + primary: PRIMARY_RED, + secondary: SECONDARY_RED, + buttons: BUTTONS_RED, + incoming: SECONDARY_RED, + outgoing: OUTGOING_RED, + text_headers: Color::WHITE, + text_body: Color::BLACK, + round_borders: Color::BLACK, +}; + +// gui Text fonts +// pub const INCONSOLATA: Font = Font::External { +// name: "inconsolata_regular", +// bytes: include_bytes!("../../fonts/inconsolata-regular.ttf"), +// }; +pub const INCONSOLATA_BOLD: Font = Font::External { + name: "inconsolata_bold", + bytes: include_bytes!("../../fonts/inconsolata-bold.ttf"), +}; + +pub fn get_font(style: StyleType) -> Font { + match to_rgb_color(get_colors(style).text_body) { + RGBColor(255, 255, 255) => Font::Default, + _ => INCONSOLATA_BOLD, + } +} + +pub fn get_font_headers(style: StyleType) -> Font { + match to_rgb_color(get_colors(style).text_headers) { + RGBColor(255, 255, 255) => Font::Default, + _ => INCONSOLATA_BOLD, + } +} + +//font to display icons +pub const ICONS: Font = Font::External { + name: "icons", + bytes: include_bytes!("../../fonts/icons.ttf"), +}; + +// palettes pictures +pub const YETI_DAY: &[u8] = include_bytes!("../../resources/palettes/YetiDay.png"); +pub const YETI_NIGHT: &[u8] = include_bytes!("../../resources/palettes/YetiNight.png"); +pub const DEEP_SEA: &[u8] = include_bytes!("../../resources/palettes/DeepSea.png"); +pub const MON_AMOUR: &[u8] = include_bytes!("../../resources/palettes/MonAmour.png"); + +// font sizes +pub const FONT_SIZE_FOOTER: u16 = 15; +pub const FONT_SIZE_BODY: u16 = 18; +pub const FONT_SIZE_SUBTITLE: u16 = 22; +pub const FONT_SIZE_TITLE: u16 = 24; + +// border styles +pub const BORDER_WIDTH: f32 = 2.0; +pub const CHARTS_LINE_BORDER: u32 = 1; +pub const BORDER_ROUNDED_RADIUS: f32 = 15.0; +pub const BORDER_BUTTON_RADIUS: f32 = 180.0; + +// body proportions +pub const HEIGHT_HEADER: u16 = 2; +pub const HEIGHT_BODY: u16 = 12; +pub const HEIGHT_FOOTER: u16 = 1; + +// stars yellow colors +pub const STARRED: Color = Color { + r: 245.0 / 255.0, + g: 193.0 / 255.0, + b: 39.0 / 255.0, + a: 1.0, +}; diff --git a/src/utility/translations.rs b/src/utility/translations.rs new file mode 100644 index 00000000..95047d7d --- /dev/null +++ b/src/utility/translations.rs @@ -0,0 +1,507 @@ +use crate::enums::language::Language; +use iced::widget::Text; + +pub fn choose_adapters_translation(language: Language) -> Text<'static> { + Text::new(match language { + Language::EN => "Select network adapter to inspect", + Language::IT => "Seleziona la scheda di rete da ispezionare", + }) +} + +pub fn application_protocol_translation(language: Language) -> &'static str { + match language { + Language::EN => "Application protocol", + Language::IT => "Protocollo applicativo", + } +} + +pub fn select_filters_translation(language: Language) -> Text<'static> { + Text::new(match language { + Language::EN => "Select filters to be applied on network traffic", + Language::IT => "Seleziona i filtri da applicare al traffico di rete", + }) +} + +pub fn start_translation(language: Language) -> &'static str { + match language { + Language::EN => "Start!", + Language::IT => "Avvia!", + } +} + +pub fn address_translation(language: Language) -> &'static str { + match language { + Language::EN => "\nAddress:", + Language::IT => "\nIndirizzo:", + } +} + +pub fn addresses_translation(language: Language) -> &'static str { + match language { + Language::EN => "\nAddresses:", + Language::IT => "\nIndirizzi:", + } +} + +pub fn ip_version_translation(language: Language) -> Text<'static> { + Text::new(match language { + Language::EN => "IP version", + Language::IT => "Versione IP", + }) +} + +pub fn transport_protocol_translation(language: Language) -> &'static str { + match language { + Language::EN => "Transport protocol", + Language::IT => "Protocollo di trasporto", + } +} + +pub fn traffic_rate_translation(language: Language) -> Text<'static> { + Text::new(match language { + Language::EN => "Traffic rate:", + Language::IT => "Intensità del traffico:", + }) +} + +pub fn relevant_connections_translation(language: Language) -> Text<'static> { + Text::new(match language { + Language::EN => "Relevant connections:", + Language::IT => "Connessioni rilevanti:", + }) +} + +pub fn settings_translation(language: Language) -> &'static str { + match language { + Language::EN => "Settings", + Language::IT => "Impostazioni", + } +} + +pub fn yes_translation(language: Language) -> Text<'static> { + Text::new(match language { + Language::EN => "Yes", + Language::IT => "Sì", + }) +} + +pub fn ask_quit_translation(language: Language) -> Text<'static> { + Text::new(match language { + Language::EN => "Are you sure you want to quit this analysis?", + Language::IT => "Sei sicuro di voler interrompere questa analisi?", + }) +} + +pub fn quit_analysis_translation(language: Language) -> String { + match language { + Language::EN => "Quit analysis".to_string(), + Language::IT => "Interrompi analisi".to_string(), + } +} + +pub fn ask_clear_all_translation(language: Language) -> Text<'static> { + Text::new(match language { + Language::EN => "Are you sure you want to clear notifications?", + Language::IT => "Sei sicuro di voler eliminare le notifiche?", + }) +} + +pub fn clear_all_translation(language: Language) -> String { + match language { + Language::EN => "Clear all".to_string(), + Language::IT => "Elimina tutte".to_string(), + } +} + +pub fn hide_translation(language: Language) -> &'static str { + match language { + Language::EN => "Hide", + Language::IT => "Nascondi", + } +} + +pub fn no_addresses_translation(language: Language, adapter: &str) -> Text<'static> { + Text::new(match language { + Language::EN => format!("No traffic can be observed because the adapter you selected has no active addresses...\n\n\ + Network adapter: {adapter}\n\n\ + If you are sure you are connected to the internet, try choosing a different adapter."), + Language::IT => format!("Non è osservabile alcun traffico perché l'adattatore di rete selezionato non ha indirizzi attivi...\n\n\ + Adattatore di rete: {adapter}\n\n\ + Se sei sicuro di essere connesso ad internet, prova a scegliere un adattatore diverso."), + }) +} + +pub fn waiting_translation(language: Language, adapter: &str) -> Text<'static> { + Text::new(match language { + Language::EN => format!("No traffic has been observed yet. Waiting for network packets...\n\n\ + Network adapter: {adapter}\n\n\ + Are you sure you are connected to the internet and you have selected the correct adapter?"), + Language::IT => format!("Nessun tipo di traffico è stato osservato finora. Attendo pacchetti di rete...\n\n\ + Adattatore di rete: {adapter}\n\n\ + Sei sicuro di esser connesso ad internet e di aver selezionato l'adattatore corretto?"), + }) +} + +pub fn some_observed_translation( + language: Language, + observed: &str, + filters: &str, +) -> Text<'static> { + Text::new(match language { + Language::EN => format!("Total intercepted packets: {observed}\n\n\ + Filtered packets: 0\n\n\ + Some packets have been intercepted, but still none has been selected according to the filters you specified...\n\n{filters}"), + Language::IT => format!("Totale pacchetti intercettati: {observed}\n\n\ + Pacchetti filtrati: 0\n\n\ + Alcuni pacchetti sono stati intercettati, ma ancora nessuno è stato selezionato secondo i filtri specificati...\n\n{filters}"), + }) +} + +pub fn filtered_packets_translation( + language: Language, + filtered: &str, + percentage: &str, +) -> Text<'static> { + Text::new(match language { + Language::EN => format!("Filtered packets:\n {filtered} ({percentage} of the total)"), + Language::IT => format!("Pacchetti filtrati:\n {filtered} ({percentage} del totale)"), + }) +} + +pub fn filtered_bytes_translation( + language: Language, + filtered: &str, + percentage: &str, +) -> Text<'static> { + Text::new(match language { + Language::EN => format!("Filtered bytes:\n {filtered} ({percentage} of the total)"), + Language::IT => format!("Byte filtrati:\n {filtered} ({percentage} del totale)"), + }) +} + +pub fn filtered_application_translation(language: Language) -> Text<'static> { + Text::new(match language { + Language::EN => "Filtered packets per application protocol:", + Language::IT => "Pacchetti filtrati per protocollo applicativo:", + }) +} + +pub fn no_favorites_translation(language: Language) -> Text<'static> { + Text::new(match language { + Language::EN => "Nothing to show at the moment.\n\ + To add a connection to your favorites, click on the star symbol near the connection.", + Language::IT => "Nulla da vedere per il momento.\n\ + Per aggiungere una connessione ai tuoi preferiti, clicca sul simbolo della stella vicino alla connessione.", + }) +} + +pub fn error_translation(language: Language, error: &str) -> Text<'static> { + Text::new(match language { + Language::EN => format!( + "An error occurred! \n\n\ + {error}" + ), + Language::IT => format!( + "Si è verificato un errore! \n\n\ + {error}" + ), + }) +} + +pub fn both_translation(language: Language) -> &'static str { + match language { + Language::EN => "both", + Language::IT => "entrambi", + } +} + +// pub fn all_protocols_translation(language: Language) -> &'static str { +// match language { +// Language::EN => "All protocols", +// Language::IT => "Tutti i protocolli", +// } +// } + +pub fn packets_chart_translation(language: Language) -> &'static str { + match language { + Language::EN => "packets per second", + Language::IT => "pacchetti al secondo", + } +} + +pub fn bytes_chart_translation(language: Language) -> &'static str { + match language { + Language::EN => "bytes per second", + Language::IT => "byte al secondo", + } +} + +pub fn recent_report_translation(language: Language) -> &'static str { + match language { + Language::EN => "most recent", + Language::IT => "più recenti", + } +} + +pub fn packets_report_translation(language: Language) -> &'static str { + match language { + Language::EN => "most packets", + Language::IT => "più pacchetti", + } +} + +pub fn bytes_report_translation(language: Language) -> &'static str { + match language { + Language::EN => "most bytes", + Language::IT => "più byte", + } +} + +pub fn favorite_report_translation(language: Language) -> &'static str { + match language { + Language::EN => "favorites", + Language::IT => "preferiti", + } +} + +pub fn notifications_title_translation(language: Language) -> Text<'static> { + Text::new(match language { + Language::EN => "Customize your notifications", + Language::IT => "Personalizza le tue notifiche", + }) +} + +pub fn appearance_title_translation(language: Language) -> Text<'static> { + Text::new(match language { + Language::EN => "Choose your favorite theme", + Language::IT => "Scegli il tuo tema preferito", + }) +} + +pub fn languages_title_translation(language: Language) -> Text<'static> { + Text::new(match language { + Language::EN => "Select your language", + Language::IT => "Seleziona la lingua", + }) +} + +pub fn active_filters_translation(language: Language) -> &'static str { + match language { + Language::EN => "Active filters:", + Language::IT => "Filtri attivi:", + } +} + +pub fn none_translation(language: Language) -> &'static str { + match language { + Language::EN => "none", + Language::IT => "nessuno", + } +} + +pub fn yeti_night_translation(language: Language) -> &'static str { + match language { + Language::EN => "Sniffnet's original dark theme", + Language::IT => "Il tema scuro originale di Sniffnet", + } +} + +pub fn yeti_day_translation(language: Language) -> &'static str { + match language { + Language::EN => "Sniffnet's original light theme", + Language::IT => "Il tema chiaro originale di Sniffnet", + } +} + +pub fn deep_sea_translation(language: Language) -> &'static str { + match language { + Language::EN => "To dive into network traffic", + Language::IT => "Per immergersi nel traffico di rete", + } +} + +pub fn mon_amour_translation(language: Language) -> &'static str { + match language { + Language::EN => "Lovely theme made for dreamers", + Language::IT => "Tema incantevole fatto per i sognatori", + } +} + +pub fn incoming_translation(language: Language) -> &'static str { + match language { + Language::EN => "Incoming", + Language::IT => "In entrata", + } +} + +pub fn outgoing_translation(language: Language) -> &'static str { + match language { + Language::EN => "Outgoing", + Language::IT => "In uscita", + } +} + +pub fn notifications_translation(language: Language) -> &'static str { + match language { + Language::EN => "Notifications", + Language::IT => "Notifiche", + } +} + +pub fn style_translation(language: Language) -> &'static str { + match language { + Language::EN => "Style", + Language::IT => "Stile", + } +} + +pub fn language_translation(language: Language) -> &'static str { + match language { + Language::EN => "Language", + Language::IT => "Lingua", + } +} + +pub fn overview_translation(language: Language) -> &'static str { + match language { + Language::EN => "Overview", + Language::IT => "Panoramica", + } +} + +// pub fn inspect_translation(language: Language) -> &'static str { +// match language { +// Language::EN => "Inspect", +// Language::IT => "Ispeziona", +// } +// } + +pub fn packets_threshold_translation(language: Language) -> &'static str { + match language { + Language::EN => "Notify me when a packets threshold is exceeded", + Language::IT => "Notificami quando una soglia di pacchetti è superata", + } +} + +pub fn bytes_threshold_translation(language: Language) -> &'static str { + match language { + Language::EN => "Notify me when a bytes threshold is exceeded", + Language::IT => "Notificami quando una soglia di byte è superata", + } +} + +pub fn per_second_translation(language: Language) -> &'static str { + match language { + Language::EN => "(per second)", + Language::IT => "(al secondo)", + } +} + +pub fn specify_multiples_translation(language: Language) -> &'static str { + match language { + Language::EN => "; you can also specify 'K', 'M' and 'G'", + Language::IT => "; puoi anche specificare 'K', 'M' e 'G'", + } +} + +pub fn favorite_notification_translation(language: Language) -> &'static str { + match language { + Language::EN => "Notify me when new data are exchanged from my favorites", + Language::IT => "Notificami quando nuovi dati sono scambiati dai miei preferiti", + } +} + +pub fn threshold_translation(language: Language) -> String { + match language { + Language::EN => "Threshold: ".to_string(), + Language::IT => "Soglia: ".to_string(), + } +} + +pub fn volume_translation(language: Language, value: u8) -> String { + match language { + Language::EN => format!("Volume: {value:^3}%"), + Language::IT => format!("Volume: {value:^3}%"), + } +} + +pub fn sound_translation(language: Language) -> &'static str { + match language { + Language::EN => "Sound:", + Language::IT => "Suono:", + } +} + +pub fn open_report_translation(language: Language) -> &'static str { + match language { + Language::EN => "Open full report", + Language::IT => "Apri report completo", + } +} + +pub fn bytes_exceeded_translation(language: Language) -> &'static str { + match language { + Language::EN => "Bytes threshold exceeded!", + Language::IT => "Soglia di Byte superata!", + } +} + +pub fn bytes_exceeded_value_translation(language: Language, value: &str) -> String { + let trimmed_value = value.trim(); + match language { + Language::EN => format!("{trimmed_value} bytes have been exchanged"), + Language::IT => format!("{trimmed_value} byte sono stati scambiati"), + } +} + +pub fn packets_exceeded_translation(language: Language) -> &'static str { + match language { + Language::EN => "Packets threshold exceeded!", + Language::IT => "Soglia di pacchetti superata!", + } +} + +pub fn packets_exceeded_value_translation(language: Language, value: u32) -> String { + match language { + Language::EN => format!("{value} packets have been exchanged"), + Language::IT => format!("{value} pacchetti sono stati scambiati"), + } +} + +pub fn favorite_transmitted_translation(language: Language) -> &'static str { + match language { + Language::EN => "New data exchanged from favorites!", + Language::IT => "Nuovi dati scambiati dai preferiti!", + } +} + +pub fn no_notifications_set_translation(language: Language) -> Text<'static> { + Text::new(match language { + Language::EN => "You haven't enabled notifications yet!\n\n\ + After you will enable them, this page will display a log of your notifications\n\n\ + You can enable notifications from settings:", + Language::IT => "Non hai ancora abilitato le notifiche!\n\n\ + Dopo che le avrai abilitate, questa pagina mostrerà una collezione delle tue notifiche\n\n\ + Puoi abilitare le notifiche dalle impostazioni:", + }) +} + +pub fn no_notifications_received_translation(language: Language) -> Text<'static> { + Text::new(match language { + Language::EN => { + "Nothing to see at the moment...\n\n\ + When you will receive a notification, it will be displayed here" + } + Language::IT => { + "Nulla da vedere al momento...\n\n\ + Quando riceverai una notifica, essa verrà mostrata qui" + } + }) +} + +pub fn only_last_30_translation(language: Language) -> &'static str { + match language { + Language::EN => "Only the last 30 notifications are displayed", + Language::IT => "Solo le ultime 30 notifiche sono mostrate", + } +}