email-client

A gtk4 Email Client
git clone git://archive.git.mtrnord.blog/erooster-mail/email-client.git
Log | Files | Refs | LICENSE

commit 32db64f848835201a32bfa4570434782a80c0a8c
parent 0811cefca0af60456f082f3fcbd49734bc4e1d7a
Author: MTRNord <mtrnord1@gmail.com>
Date:   Wed, 22 Feb 2023 12:20:19 +0100

add thunderbird autoconfig parsing, add basic login_view and login, add basic imap state, add color_eyre

Diffstat:
MCargo.lock | 778+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
MCargo.toml | 12+++++++++++-
Mbuild-aux/de.nordgedanken.Email.Devel.yaml | 6++----
Asrc/imap_state.rs | 18++++++++++++++++++
Asrc/login_view.rs | 323+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main.rs | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++--------
6 files changed, 1012 insertions(+), 186 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -3,6 +3,21 @@ version = 3 [[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" + +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli", +] + +[[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -18,13 +33,10 @@ dependencies = [ ] [[package]] -name = "android_system_properties" -version = "0.1.5" +name = "aliasable" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" [[package]] name = "anyhow" @@ -33,12 +45,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" [[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] name = "ascii-canvas" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -76,12 +82,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] name = "base64" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + +[[package]] name = "bindgen" version = "0.63.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -234,7 +261,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "nom 7.1.3", + "nom", ] [[package]] @@ -258,13 +285,10 @@ version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" dependencies = [ - "iana-time-zone", "js-sys", "num-integer", "num-traits", - "time 0.1.45", "wasm-bindgen", - "winapi", ] [[package]] @@ -279,13 +303,30 @@ dependencies = [ ] [[package]] -name = "codespan-reporting" -version = "0.11.1" +name = "color-eyre" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" dependencies = [ - "termcolor", - "unicode-width", + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", ] [[package]] @@ -295,6 +336,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[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" @@ -359,50 +410,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] -name = "cxx" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] name = "dbus" version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -471,6 +478,15 @@ dependencies = [ ] [[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + +[[package]] name = "exr" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -487,6 +503,16 @@ dependencies = [ ] [[package]] +name = "eyre" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] name = "fastrand" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -531,7 +557,22 @@ dependencies = [ "futures-sink", "nanorand", "pin-project", - "spin", + "spin 0.9.5", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", ] [[package]] @@ -736,6 +777,12 @@ dependencies = [ ] [[package]] +name = "gimli" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" + +[[package]] name = "gio" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -951,6 +998,25 @@ dependencies = [ ] [[package]] +name = "h2" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] name = "half" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -999,27 +1065,74 @@ dependencies = [ ] [[package]] -name = "iana-time-zone" -version = "0.1.53" +name = "http" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "winapi", + "bytes", + "fnv", + "itoa", ] [[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" dependencies = [ - "cxx", - "cxx-build", + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", ] [[package]] @@ -1053,29 +1166,36 @@ dependencies = [ [[package]] name = "imap" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c617c55def8c42129e0dd503f11d7ee39d73f5c7e01eff55768b3879ff1d107d" +version = "3.0.0-alpha.10" +source = "git+https://github.com/erooster-mail/rust-imap.git?branch=MTRNord/clippy#38abe294b7332a4fde7095b52e838f3a55ebf1da" dependencies = [ - "base64", + "base64 0.21.0", "bufstream", "chrono", "imap-proto", "lazy_static", - "nom 5.1.2", + "nom", + "ouroboros", "regex", + "rustls-connector", ] [[package]] name = "imap-proto" -version = "0.10.2" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16a6def1d5ac8975d70b3fd101d57953fe3278ef2ee5d7816cba54b1d1dfc22f" +checksum = "f73b1b63179418b20aa81002d616c5f21b4ba257da9bca6989ea64dc573933e0" dependencies = [ - "nom 5.1.2", + "nom", ] [[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] name = "indexmap" version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1095,6 +1215,12 @@ dependencies = [ ] [[package]] +name = "ipnet" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" + +[[package]] name = "itertools" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1104,6 +1230,12 @@ dependencies = [ ] [[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[package]] name = "jpeg-decoder" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1168,19 +1300,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] -name = "lexical-core" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if", - "ryu", - "static_assertions", -] - -[[package]] name = "libc" version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1206,15 +1325,6 @@ dependencies = [ ] [[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - -[[package]] name = "lock_api" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1243,21 +1353,27 @@ dependencies = [ "dirs-next", "objc-foundation", "objc_id", - "time 0.3.19", + "time", ] [[package]] name = "mail-client" version = "0.1.0" dependencies = [ + "color-eyre", "glib-build-tools", "gtk4", "imap", "notify-rust", + "once_cell", + "quick-xml 0.27.1", "relm4", "relm4-components", "relm4-macros", + "reqwest", + "rustls-connector", "sequoia-openpgp", + "serde", "tokio", "tracing", "tracing-subscriber", @@ -1303,6 +1419,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ac78937f19a0c7807e45a931eac41f766f210173ec664ec046d58e6d388a5cb" [[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1372,17 +1494,6 @@ checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" [[package]] name = "nom" -version = "5.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" -dependencies = [ - "lexical-core", - "memchr", - "version_check", -] - -[[package]] -name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" @@ -1494,18 +1605,62 @@ dependencies = [ ] [[package]] +name = "object" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +dependencies = [ + "memchr", +] + +[[package]] name = "once_cell" version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "ouroboros" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db" +dependencies = [ + "aliasable", + "ouroboros_macro", +] + +[[package]] +name = "ouroboros_macro" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" +dependencies = [ + "Inflector", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] name = "pango" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1561,6 +1716,12 @@ 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 = "pest" version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1704,6 +1865,16 @@ dependencies = [ ] [[package]] +name = "quick-xml" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc053f057dd768a56f62cd7e434c42c831d296968997e9ac1f76ea7c2d14c41" +dependencies = [ + "memchr", + "serde", +] + +[[package]] name = "quote" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1861,6 +2032,66 @@ dependencies = [ ] [[package]] +name = "reqwest" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" +dependencies = [ + "base64 0.21.0", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-rustls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1876,6 +2107,51 @@ dependencies = [ ] [[package]] +name = "rustls" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-connector" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6a18f8d10f71bce9bca6eaeb80429460e652f3bcf0381f0c5f8954abf7b3b8" +dependencies = [ + "log", + "rustls", + "rustls-native-certs", + "webpki", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +dependencies = [ + "base64 0.21.0", +] + +[[package]] name = "rustversion" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1888,6 +2164,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" [[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] name = "scoped_threadpool" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1900,10 +2185,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] -name = "scratch" -version = "1.0.3" +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +dependencies = [ + "core-foundation-sys", + "libc", +] [[package]] name = "semver" @@ -1930,7 +2242,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70af2f594bf5261eb87be5060db1e40d6445686d2bb3ec41c014cf53701130a2" dependencies = [ "anyhow", - "base64", + "base64 0.13.1", "buffered-reader", "bzip2", "chrono", @@ -1957,6 +2269,43 @@ 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.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] [[package]] name = "sha1collisiondetection" @@ -2031,6 +2380,12 @@ dependencies = [ [[package]] name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc" @@ -2039,12 +2394,6 @@ dependencies = [ ] [[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] name = "string_cache" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2108,7 +2457,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c58de036c4d2e20717024de2a3c4bf56c301f07b21bc8ef9b57189fce06f1f3b" dependencies = [ - "quick-xml", + "quick-xml 0.23.1", "strum", "windows", ] @@ -2139,15 +2488,6 @@ dependencies = [ ] [[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - -[[package]] name = "thiserror" version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2199,17 +2539,6 @@ dependencies = [ [[package]] name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - -[[package]] -name = "time" version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53250a3b3fed8ff8fd988587d8925d26a83ac3845d9e03b220b37f34c2b8d6c2" @@ -2280,6 +2609,31 @@ dependencies = [ ] [[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-util" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] name = "toml" version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2306,6 +2660,12 @@ dependencies = [ ] [[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] name = "tracing" version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2339,6 +2699,16 @@ dependencies = [ ] [[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] name = "tracing-log" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2384,6 +2754,12 @@ dependencies = [ ] [[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] name = "typenum" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2423,18 +2799,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[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 = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] name = "valuable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2459,16 +2846,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +name = "want" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] [[package]] name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" @@ -2502,6 +2893,18 @@ dependencies = [ ] [[package]] +name = "wasm-bindgen-futures" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] name = "wasm-bindgen-macro" version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2531,6 +2934,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki", +] + +[[package]] name = "weezl" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2553,15 +2985,6 @@ 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-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2692,6 +3115,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] name = "xxhash-rust" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml @@ -15,10 +15,20 @@ tracing = "0.1.37" tokio = { version = "1.25.0", features = ["full"] } sequoia-openpgp = "1.13.0" notify-rust = { version = "4.7.1", default-features = false, features = ["d", "images"] } +# Needs to be in sync with imap crate version +rustls-connector = { version = "0.16.1"} +color-eyre = "0.6.2" +reqwest = { version = "0.11.14", features = ["rustls", "rustls-tls"], default-features = false } +quick-xml = { version = "0.27.1", features = ["serde", "serialize"] } +serde = { version = "1.0.152", features = ["derive"] } +once_cell = "1.17.1" [dependencies.imap] -version = "2.4.1" +version = "3.0.0-alpha.10" +git = "https://github.com/erooster-mail/rust-imap.git" +branch = "MTRNord/clippy" default-features = false +features = ["rustls-tls"] [build-dependencies] glib-build-tools = "0.17" diff --git a/build-aux/de.nordgedanken.Email.Devel.yaml b/build-aux/de.nordgedanken.Email.Devel.yaml @@ -12,8 +12,7 @@ finish-args: - --device=dri - --share=network - --socket=session-bus - - --env=GTK_DEBUG=interactive - - --env=RUST_LOG=mail_client=debug + #- --env=GTK_DEBUG=interactive - --env=G_MESSAGES_DEBUG=none - --env=RUST_BACKTRACE=1 build-options: @@ -33,4 +32,4 @@ modules: - -Dprofile=development sources: - type: dir - path: ../ -\ No newline at end of file + path: ../ diff --git a/src/imap_state.rs b/src/imap_state.rs @@ -0,0 +1,18 @@ +use imap::Session; +use relm4::SharedState; +use rustls_connector::TlsStream; +use std::net::TcpStream; + +pub enum ImapSession { + TLS(Session<TlsStream<TcpStream>>), + TCP(Session<TcpStream>), + None, +} + +impl Default for ImapSession { + fn default() -> Self { + Self::None + } +} + +pub static IMAP_SESSION: SharedState<ImapSession> = SharedState::new(); diff --git a/src/login_view.rs b/src/login_view.rs @@ -0,0 +1,323 @@ +use crate::imap_state::ImapSession; +use crate::imap_state::IMAP_SESSION; +use crate::AppMsg; +use color_eyre::{eyre::bail, Result}; +use gtk::prelude::*; +use once_cell::sync::Lazy; +use quick_xml::de::from_str; +use relm4::component::AsyncComponent; +use relm4::component::AsyncComponentParts; +use relm4::loading_widgets::LoadingWidgets; +use relm4::prelude::*; +use relm4::AsyncComponentSender; +use relm4::{view, Worker, WorkerController}; +use reqwest::StatusCode; +use serde::Deserialize; +use std::convert::identity; +use tokio::runtime::Runtime; + +static RUNTIME: Lazy<Runtime> = Lazy::new(|| Runtime::new().unwrap()); + +pub struct LoginView { + // stores entered values + email: gtk::EntryBuffer, + password: gtk::PasswordEntryBuffer, + login_worker: WorkerController<AsyncLoginHandler>, +} + +#[derive(Debug)] +pub enum LoginMsg { + Finished, + StartLogin, +} + +#[relm4::component(async, pub)] +impl AsyncComponent for LoginView { + type Init = (); + type Input = LoginMsg; + type Output = AppMsg; + type CommandOutput = LoginMsg; + + view! { + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_halign: gtk::Align::Fill, + set_valign: gtk::Align::Fill, + set_hexpand: true, + set_vexpand: true, + + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_margin_all: 8, + set_spacing: 8, + set_halign: gtk::Align::Center, + set_valign: gtk::Align::Center, + + gtk::Entry { + set_tooltip_text: Some("Username"), + set_buffer: &model.email, + }, + gtk::Entry { + set_tooltip_text: Some("Password"), + set_buffer: &model.password, + set_visibility: false, + }, + gtk::Button { + set_label: "Login", + connect_clicked => LoginMsg::StartLogin, + }, + } + } + } + + fn init_loading_widgets(root: &mut Self::Root) -> Option<LoadingWidgets> { + view! { + #[local_ref] + root { + // This will be removed automatically by + // LoadingWidgets when the full view has loaded + #[name(spinner)] + gtk::Spinner { + start: (), + set_halign: gtk::Align::Center, + } + } + } + Some(LoadingWidgets::new(root, spinner)) + } + + async fn init( + _: Self::Init, + root: Self::Root, + sender: AsyncComponentSender<Self>, + ) -> AsyncComponentParts<Self> { + // TODO: Check if logged in and exit early if needed + let model = LoginView { + email: gtk::EntryBuffer::new(None::<String>), + password: gtk::PasswordEntryBuffer::new(), + login_worker: AsyncLoginHandler::builder() + .detach_worker(()) + .forward(sender.input_sender(), identity), + }; + + // Insert the code generation of the view! macro here + let widgets = view_output!(); + + AsyncComponentParts { model, widgets } + } + + async fn update( + &mut self, + msg: Self::Input, + sender: AsyncComponentSender<Self>, + _root: &Self::Root, + ) { + tracing::info!("Got msg1: {:?}", msg); + match msg { + LoginMsg::StartLogin => { + tracing::info!("Starting login"); + self.login_worker + .sender() + .send(AsyncLoginHandlerMsg::StartLogin( + self.email.text().to_string(), + self.password.text().to_string(), + )) + .unwrap(); + } + LoginMsg::Finished => { + tracing::info!("Login finished"); + sender.output(AppMsg::ToMainView).unwrap(); + } + _ => {} + } + } +} + +#[derive(Debug)] +enum AsyncLoginHandlerMsg { + StartLogin(String, String), +} + +struct AsyncLoginHandler; + +impl Worker for AsyncLoginHandler { + type Init = (); + type Input = AsyncLoginHandlerMsg; + type Output = LoginMsg; + + fn init(_init: Self::Init, _sender: ComponentSender<Self>) -> Self { + Self + } + + fn update(&mut self, msg: AsyncLoginHandlerMsg, sender: ComponentSender<Self>) { + tracing::info!("Got msg: {:?}", msg); + match msg { + AsyncLoginHandlerMsg::StartLogin(email, password) => { + RUNTIME.block_on(async move { + tracing::info!("Starting login inner"); + let server_url = email.split('@').last().unwrap().to_string(); + let config = get_autoconfig(server_url, email.clone()).await; + match config { + Ok(config) => { + tracing::info!("Got config: {:?}", config); + + let incoming_server = config + .email_provider + .incoming_servers + .iter() + .find(|d| d.socket_type == "SSL") + .unwrap(); + + let client = imap::ClientBuilder::new( + incoming_server.hostname.clone(), + incoming_server.port.parse::<u16>().unwrap(), + ) + .rustls() + .unwrap(); + + // TODO: Use OAUth2 if https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat#OAuth2 is set + + let auth_data = match incoming_server.username.as_str() { + "%EMAILADDRESS%" => PlainAuth { email, password }, + "%EMAILLOCALPART%" => { + let email = email.split('@').next().unwrap().to_string(); + PlainAuth { email, password } + } + "%EMAILDOMAIN%" => { + let email = email.split('@').last().unwrap().to_string(); + PlainAuth { email, password } + } + _ => { + tracing::error!("Username type not supported"); + return; + } + }; + + // the client we have here is unauthenticated. + // to do anything useful with the e-mails, we need to log in + // FIXME: Use correct authentication method + let imap_session = client + .authenticate("PLAIN", &auth_data) + .map_err(|e| e.0) + .unwrap(); + + *IMAP_SESSION.write() = ImapSession::TLS(imap_session); + sender.output(LoginMsg::Finished).unwrap(); + } + Err(e) => { + tracing::warn!("Unable to get config: {:?}", e); + } + } + }); + } + }; + } +} + +struct PlainAuth { + email: String, + password: String, +} + +impl imap::Authenticator for PlainAuth { + type Response = String; + fn process(&self, _: &[u8]) -> Self::Response { + format!("\0{}\0{}", self.email, self.password) + } +} + +async fn get_autoconfig(server_url: String, email: String) -> Result<AutoconfigXML> { + // First check subdomain with email + // TODO: Parse xml + let resp = reqwest::get(format!( + "https://autoconfig.{server_url}/mail/config-v1.1.xml?emailaddress={email}" + )) + .await; + + match resp { + Ok(resp) => { + if resp.status() != StatusCode::OK { + tracing::info!("Not found. Trying well-known"); + return get_autoconfig_wellknown(server_url).await; + } + + let xml_text = resp.text().await?; + let parsed_xml: AutoconfigXML = from_str(&xml_text)?; + + Ok(parsed_xml) + } + Err(_) => { + tracing::info!("Not found. Trying well-known"); + get_autoconfig_wellknown(server_url).await + } + } +} + +async fn get_autoconfig_wellknown(server_url: String) -> Result<AutoconfigXML> { + let resp = reqwest::get(format!( + "https://{server_url}/.well-known/autoconfig/mail/config-v1.1.xml" + )) + .await?; + + if resp.status() != StatusCode::OK { + // TODO: Check DNS + bail!("Unable to find server autoconfig"); + } + + let xml_text = resp.text().await?; + let parsed_xml: AutoconfigXML = from_str(&xml_text)?; + Ok(parsed_xml) +} + +#[derive(Debug, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +struct AutoconfigXML { + #[serde(rename = "@version")] + version: String, + email_provider: EmailProviderXML, +} + +#[derive(Debug, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +struct EmailProviderXML { + #[serde(rename = "@id")] + id: String, + #[serde(rename = "domain", default)] + domains: Vec<String>, + display_name: String, + display_short_name: String, + documentation: Option<DocumentationXML>, + #[serde(rename = "incomingServer", default)] + incoming_servers: Vec<IncomingServerXML>, + #[serde(rename = "outgoingServer", default)] + outgoing_servers: Vec<OutgoingServerXML>, +} + +#[derive(Debug, Deserialize, PartialEq)] +struct DocumentationXML { + url: String, +} + +#[derive(Debug, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +struct IncomingServerXML { + #[serde(rename = "@type", default)] + servertype: String, + hostname: String, + port: String, + socket_type: String, + authentication: String, + username: String, +} + +#[derive(Debug, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +struct OutgoingServerXML { + #[serde(rename = "@type", default)] + servertype: String, + hostname: String, + port: String, + socket_type: String, + authentication: String, + username: String, +} diff --git a/src/main.rs b/src/main.rs @@ -1,5 +1,10 @@ +use color_eyre::Result; use gtk::{gdk::Display, gio, prelude::*, Application}; +use login_view::LoginView; use main_view::MainView; +use relm4::component::AsyncComponent; +use relm4::component::AsyncComponentController; +use relm4::component::AsyncController; use relm4::prelude::*; use std::convert::identity; @@ -7,29 +12,56 @@ use std::convert::identity; mod config; mod folder_view; +mod imap_state; +mod login_view; mod main_view; struct App { main_view: Controller<MainView>, + login_view: AsyncController<LoginView>, + active_child: Child, } #[derive(Debug)] -enum Msg {} +pub enum AppMsg { + ToMainView, +} + +#[derive(Debug)] +enum Child { + LoginView, + MainView, +} #[relm4::component] -impl Component for App { +impl SimpleComponent for App { type Init = (); - type Input = (); + type Input = AppMsg; type Output = (); - type CommandOutput = Msg; view! { #[root] - main_window = gtk::ApplicationWindow { + #[name(main_window)] + gtk::ApplicationWindow { set_title: Some("Email"), set_default_size: (1280, 720), - model.main_view.widget(), + match model.active_child { + Child::LoginView => { + gtk::Box { + set_halign: gtk::Align::Fill, + set_valign: gtk::Align::Fill, + model.login_view.widget(), + } + }, + Child::MainView => { + gtk::Box { + set_halign: gtk::Align::Fill, + set_valign: gtk::Align::Fill, + model.main_view.widget(), + } + } + }, } } @@ -38,17 +70,29 @@ impl Component for App { root: &Self::Root, sender: ComponentSender<Self>, ) -> ComponentParts<Self> { + // TODO: Check if we are logged in and if not go to login + // FIXME: Remove Placeholder let model = App { - main_view: MainView::builder() + active_child: Child::LoginView, + main_view: MainView::builder().launch(()).detach(), + login_view: LoginView::builder() .launch(()) .forward(sender.input_sender(), identity), }; let widgets = view_output!(); ComponentParts { model, widgets } } + + fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) { + match msg { + AppMsg::ToMainView => self.active_child = Child::MainView, + } + } } -fn main() { +fn main() -> Result<()> { + color_eyre::install()?; + // Show traces to find potential performance bottlenecks, for example tracing_subscriber::fmt() .with_span_events(tracing_subscriber::fmt::format::FmtSpan::FULL) @@ -73,6 +117,7 @@ fn main() { app.connect_startup(|_| load_css()); let app = RelmApp::with_app(app); app.run::<App>(()); + Ok(()) } fn load_css() {