mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-24 20:10:23 +00:00
update pimalaya libs, prepare v0.9.0
This commit is contained in:
parent
f61a1f6669
commit
7ad1772c83
37 changed files with 498 additions and 436 deletions
21
CHANGELOG.md
21
CHANGELOG.md
|
@ -7,20 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.9.0] - 2023-08-28
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Added 3 new cargo features:
|
- Added 3 new cargo features:
|
||||||
- `cmds-pgp`: enables the commands PGP backend (enabled by default, same behaviour as before)
|
- `pgp-commands`: enables the commands PGP backend (enabled by default, same behaviour as before)
|
||||||
- `gpg`: enables the GPG backend (requires the `gpgme` lib on the system)
|
- `pgp-gpg`: enables the GPG backend (requires the `gpgme` lib on the system)
|
||||||
- `native-pgp`: enables the native PGP backend
|
- `pgp-native`: enables the native PGP backend
|
||||||
- Added account configuration `pgp` to configure the way PGP operations are performed.
|
- Added account configuration `pgp` to configure the way PGP operations are performed.
|
||||||
|
|
||||||
### Removed
|
### Changed
|
||||||
|
|
||||||
- Removed account configuration `email-writing-encrypt-cmd`.
|
- Moved `email-writing-encrypt-cmd`to `pgp.encrypt-cmd`.
|
||||||
- Removed account configuration `email-reading-decrypt-cmd`.
|
- Moved `email-reading-decrypt-cmd` to `pgp-decrypt-cmd`.
|
||||||
- Removed account configuration `email-writing-sign-cmd`.
|
- Moved `email-writing-sign-cmd` to `pgp.sign-cmd`.
|
||||||
- Removed account configuration `email-reading-verify-cmd`.
|
- Moved `email-reading-verify-cmd` to `pgp.verify-cmd`.
|
||||||
|
|
||||||
## [0.8.4] - 2023-07-18
|
## [0.8.4] - 2023-07-18
|
||||||
|
|
||||||
|
@ -603,7 +605,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Password from command [#22]
|
- Password from command [#22]
|
||||||
- Set up README [#20]
|
- Set up README [#20]
|
||||||
|
|
||||||
[Unreleased]: https://github.com/soywod/himalaya/compare/v0.8.4...HEAD
|
[Unreleased]: https://github.com/soywod/himalaya/compare/v0.9.0...HEAD
|
||||||
|
[0.9.0]: https://github.com/soywod/himalaya/compare/v0.8.4...v0.9.0
|
||||||
[0.8.4]: https://github.com/soywod/himalaya/compare/v0.8.3...v0.8.4
|
[0.8.4]: https://github.com/soywod/himalaya/compare/v0.8.3...v0.8.4
|
||||||
[0.8.3]: https://github.com/soywod/himalaya/compare/v0.8.2...v0.8.3
|
[0.8.3]: https://github.com/soywod/himalaya/compare/v0.8.2...v0.8.3
|
||||||
[0.8.2]: https://github.com/soywod/himalaya/compare/v0.8.1...v0.8.2
|
[0.8.2]: https://github.com/soywod/himalaya/compare/v0.8.1...v0.8.2
|
||||||
|
|
284
Cargo.lock
generated
284
Cargo.lock
generated
|
@ -997,6 +997,54 @@ dependencies = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "email-lib"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b24c6a2ef2ffbfe518b531ee5cc252ed6014e3cbfe1734e7cece299dbd12eb1b"
|
||||||
|
dependencies = [
|
||||||
|
"advisory-lock",
|
||||||
|
"ammonia",
|
||||||
|
"async-trait",
|
||||||
|
"chrono",
|
||||||
|
"convert_case",
|
||||||
|
"dirs",
|
||||||
|
"futures",
|
||||||
|
"html-escape",
|
||||||
|
"imap",
|
||||||
|
"imap-proto",
|
||||||
|
"keyring-lib",
|
||||||
|
"log",
|
||||||
|
"mail-builder",
|
||||||
|
"mail-parser",
|
||||||
|
"mail-send",
|
||||||
|
"maildirpp",
|
||||||
|
"md5",
|
||||||
|
"mml-lib",
|
||||||
|
"notmuch",
|
||||||
|
"oauth-lib",
|
||||||
|
"once_cell",
|
||||||
|
"ouroboros",
|
||||||
|
"pgp-lib",
|
||||||
|
"process-lib",
|
||||||
|
"rayon",
|
||||||
|
"regex",
|
||||||
|
"rfc2047-decoder",
|
||||||
|
"rusqlite",
|
||||||
|
"rustls 0.21.1",
|
||||||
|
"rustls-native-certs",
|
||||||
|
"secret-lib",
|
||||||
|
"shellexpand",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"tokio-rustls 0.24.0",
|
||||||
|
"tree_magic",
|
||||||
|
"urlencoding",
|
||||||
|
"utf7-imap",
|
||||||
|
"uuid",
|
||||||
|
"webpki-roots 0.22.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "email_address"
|
name = "email_address"
|
||||||
version = "0.2.4"
|
version = "0.2.4"
|
||||||
|
@ -1430,7 +1478,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "himalaya"
|
name = "himalaya"
|
||||||
version = "0.9.0-beta"
|
version = "0.9.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -1443,19 +1491,20 @@ dependencies = [
|
||||||
"coredump",
|
"coredump",
|
||||||
"dialoguer",
|
"dialoguer",
|
||||||
"dirs",
|
"dirs",
|
||||||
|
"email-lib",
|
||||||
"email_address",
|
"email_address",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"erased-serde",
|
"erased-serde",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
|
"keyring-lib",
|
||||||
"log",
|
"log",
|
||||||
"md5",
|
"md5",
|
||||||
|
"mml-lib",
|
||||||
|
"oauth-lib",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"pimalaya-email",
|
"process-lib",
|
||||||
"pimalaya-keyring",
|
|
||||||
"pimalaya-oauth2",
|
|
||||||
"pimalaya-process",
|
|
||||||
"pimalaya-secret",
|
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
|
"secret-lib",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"shellexpand",
|
"shellexpand",
|
||||||
|
@ -1827,6 +1876,17 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "keyring-lib"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8dcc9433b6eaf33f2f6a8d3a53b598a5d0b8be224c41bd98d1ec936ef4d02d69"
|
||||||
|
dependencies = [
|
||||||
|
"keyring",
|
||||||
|
"log",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -2117,6 +2177,28 @@ dependencies = [
|
||||||
"windows-sys 0.42.0",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mml-lib"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f87247d31f8b76ac7e5d2e23395a83f54978a8716318db6e66a026f50f9288e3"
|
||||||
|
dependencies = [
|
||||||
|
"async-recursion",
|
||||||
|
"chumsky 0.9.0",
|
||||||
|
"gpgme",
|
||||||
|
"keyring-lib",
|
||||||
|
"log",
|
||||||
|
"mail-builder",
|
||||||
|
"mail-parser",
|
||||||
|
"nanohtml2text",
|
||||||
|
"pgp-lib",
|
||||||
|
"process-lib",
|
||||||
|
"secret-lib",
|
||||||
|
"shellexpand",
|
||||||
|
"thiserror",
|
||||||
|
"tree_magic",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nanohtml2text"
|
name = "nanohtml2text"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
|
@ -2234,6 +2316,20 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oauth-lib"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e1484d9864dbf6b55b3785380631a253fa0ff7f8e1bbb078bfd7effd11283d61"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"oauth2",
|
||||||
|
"reqwest",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oauth2"
|
name = "oauth2"
|
||||||
version = "4.3.0"
|
version = "4.3.0"
|
||||||
|
@ -2465,6 +2561,27 @@ dependencies = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pgp-lib"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d61233a437ba3de6396593cb27fda4e48ba7c7415756caffe9f9d5d0d07378c"
|
||||||
|
dependencies = [
|
||||||
|
"async-recursion",
|
||||||
|
"futures",
|
||||||
|
"hyper",
|
||||||
|
"hyper-rustls 0.24.1",
|
||||||
|
"log",
|
||||||
|
"pgp",
|
||||||
|
"rand",
|
||||||
|
"sha1",
|
||||||
|
"smallvec",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"url",
|
||||||
|
"z-base-32",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf"
|
name = "phf"
|
||||||
version = "0.10.1"
|
version = "0.10.1"
|
||||||
|
@ -2503,138 +2620,6 @@ dependencies = [
|
||||||
"siphasher",
|
"siphasher",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pimalaya-email"
|
|
||||||
version = "0.14.1-beta"
|
|
||||||
source = "git+https://git.sr.ht/~soywod/pimalaya#b75297ae474a231eb13c9bd7c04b5dc877026948"
|
|
||||||
dependencies = [
|
|
||||||
"advisory-lock",
|
|
||||||
"ammonia",
|
|
||||||
"async-trait",
|
|
||||||
"chrono",
|
|
||||||
"convert_case",
|
|
||||||
"dirs",
|
|
||||||
"futures",
|
|
||||||
"html-escape",
|
|
||||||
"imap",
|
|
||||||
"imap-proto",
|
|
||||||
"log",
|
|
||||||
"mail-builder",
|
|
||||||
"mail-parser",
|
|
||||||
"mail-send",
|
|
||||||
"maildirpp",
|
|
||||||
"md5",
|
|
||||||
"notmuch",
|
|
||||||
"once_cell",
|
|
||||||
"ouroboros",
|
|
||||||
"pimalaya-email-tpl",
|
|
||||||
"pimalaya-keyring",
|
|
||||||
"pimalaya-oauth2",
|
|
||||||
"pimalaya-pgp",
|
|
||||||
"pimalaya-process",
|
|
||||||
"pimalaya-secret",
|
|
||||||
"rayon",
|
|
||||||
"regex",
|
|
||||||
"rfc2047-decoder",
|
|
||||||
"rusqlite",
|
|
||||||
"rustls 0.21.1",
|
|
||||||
"rustls-native-certs",
|
|
||||||
"shellexpand",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
"tokio-rustls 0.24.0",
|
|
||||||
"tree_magic",
|
|
||||||
"urlencoding",
|
|
||||||
"utf7-imap",
|
|
||||||
"uuid",
|
|
||||||
"webpki-roots 0.22.6",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pimalaya-email-tpl"
|
|
||||||
version = "0.3.2-beta"
|
|
||||||
source = "git+https://git.sr.ht/~soywod/pimalaya#b75297ae474a231eb13c9bd7c04b5dc877026948"
|
|
||||||
dependencies = [
|
|
||||||
"async-recursion",
|
|
||||||
"chumsky 0.9.0",
|
|
||||||
"gpgme",
|
|
||||||
"log",
|
|
||||||
"mail-builder",
|
|
||||||
"mail-parser",
|
|
||||||
"nanohtml2text",
|
|
||||||
"pimalaya-keyring",
|
|
||||||
"pimalaya-pgp",
|
|
||||||
"pimalaya-process",
|
|
||||||
"pimalaya-secret",
|
|
||||||
"shellexpand",
|
|
||||||
"thiserror",
|
|
||||||
"tree_magic",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pimalaya-keyring"
|
|
||||||
version = "0.0.6-beta"
|
|
||||||
source = "git+https://git.sr.ht/~soywod/pimalaya#b75297ae474a231eb13c9bd7c04b5dc877026948"
|
|
||||||
dependencies = [
|
|
||||||
"keyring",
|
|
||||||
"log",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pimalaya-oauth2"
|
|
||||||
version = "0.0.5-beta"
|
|
||||||
source = "git+https://git.sr.ht/~soywod/pimalaya#b75297ae474a231eb13c9bd7c04b5dc877026948"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"oauth2",
|
|
||||||
"reqwest",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
"url",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pimalaya-pgp"
|
|
||||||
version = "0.0.1"
|
|
||||||
source = "git+https://git.sr.ht/~soywod/pimalaya#b75297ae474a231eb13c9bd7c04b5dc877026948"
|
|
||||||
dependencies = [
|
|
||||||
"async-recursion",
|
|
||||||
"futures",
|
|
||||||
"hyper",
|
|
||||||
"hyper-rustls 0.24.1",
|
|
||||||
"log",
|
|
||||||
"pgp",
|
|
||||||
"rand",
|
|
||||||
"sha1",
|
|
||||||
"smallvec",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
"url",
|
|
||||||
"z-base-32",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pimalaya-process"
|
|
||||||
version = "0.0.6-beta"
|
|
||||||
source = "git+https://git.sr.ht/~soywod/pimalaya#b75297ae474a231eb13c9bd7c04b5dc877026948"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pimalaya-secret"
|
|
||||||
version = "0.0.6-beta"
|
|
||||||
source = "git+https://git.sr.ht/~soywod/pimalaya#b75297ae474a231eb13c9bd7c04b5dc877026948"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"pimalaya-keyring",
|
|
||||||
"pimalaya-process",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
|
@ -2746,6 +2731,17 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "process-lib"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe824234b824573ff3a80ddf3a6b19e6ffba966798d071f280723ee02a7273ce"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "psm"
|
name = "psm"
|
||||||
version = "0.1.21"
|
version = "0.1.21"
|
||||||
|
@ -3184,6 +3180,18 @@ dependencies = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "secret-lib"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d46e99ae858a1978ec3e6e887966514900229fc0df99935a2c61102854f9195e"
|
||||||
|
dependencies = [
|
||||||
|
"keyring-lib",
|
||||||
|
"log",
|
||||||
|
"process-lib",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.7.0"
|
version = "2.7.0"
|
||||||
|
|
187
Cargo.toml
187
Cargo.toml
|
@ -1,74 +1,149 @@
|
||||||
[package]
|
[package]
|
||||||
name = "himalaya"
|
name = "himalaya"
|
||||||
description = "CLI to manage your emails."
|
description = "CLI to manage emails."
|
||||||
version = "0.9.0-beta"
|
version = "0.9.0"
|
||||||
authors = ["soywod <clement.douin@posteo.net>"]
|
authors = ["soywod <clement.douin@posteo.net>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
categories = ["command-line-interface", "command-line-utilities", "email"]
|
categories = ["command-line-interface", "command-line-utilities", "email"]
|
||||||
keywords = ["cli", "mail", "email", "client", "imap"]
|
keywords = ["cli", "mail", "email", "client", "imap"]
|
||||||
homepage = "https://pimalaya.org/himalaya/"
|
homepage = "https://pimalaya.org/"
|
||||||
documentation = "https://pimalaya.org/himalaya/"
|
documentation = "https://pimalaya.org/himalaya/"
|
||||||
repository = "https://github.com/soywod/himalaya"
|
repository = "https://github.com/soywod/himalaya/"
|
||||||
|
metadata.docs.rs.all-features = true
|
||||||
[package.metadata.docs.rs]
|
|
||||||
all-features = true
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["imap-backend", "smtp-sender", "cmds-pgp"]
|
default = ["imap-backend", "smtp-sender", "pgp-commands"]
|
||||||
|
|
||||||
# backends
|
# backends
|
||||||
imap-backend = ["pimalaya-email/imap-backend"]
|
imap-backend = ["email-lib/imap-backend"]
|
||||||
notmuch-backend = ["pimalaya-email/notmuch-backend"]
|
notmuch-backend = ["email-lib/notmuch-backend"]
|
||||||
cmds-pgp = ["pimalaya-email/cmds-pgp"]
|
|
||||||
gpg = ["pimalaya-email/gpg"]
|
|
||||||
native-pgp = ["pimalaya-email/native-pgp"]
|
|
||||||
|
|
||||||
# senders
|
# senders
|
||||||
smtp-sender = ["pimalaya-email/smtp-sender"]
|
smtp-sender = ["email-lib/smtp-sender"]
|
||||||
|
|
||||||
[dev-dependencies]
|
# pgp
|
||||||
async-trait = "0.1"
|
pgp-commands = ["email-lib/pgp-commands"]
|
||||||
tempfile = "3.3"
|
pgp-gpg = ["email-lib/pgp-gpg"]
|
||||||
|
pgp-native = ["email-lib/pgp-native"]
|
||||||
|
|
||||||
[dependencies]
|
[dev-dependencies.async-trait]
|
||||||
anyhow = "1.0"
|
version = "0.1"
|
||||||
atty = "0.2"
|
|
||||||
chrono = "0.4.24"
|
|
||||||
clap = "4.0"
|
|
||||||
clap_complete = "4.0"
|
|
||||||
clap_mangen = "0.2"
|
|
||||||
console = "0.15.2"
|
|
||||||
dialoguer = "0.10.2"
|
|
||||||
dirs = "4.0.0"
|
|
||||||
email_address = "0.2.4"
|
|
||||||
env_logger = "0.8"
|
|
||||||
erased-serde = "0.3"
|
|
||||||
indicatif = "0.17"
|
|
||||||
log = "0.4"
|
|
||||||
md5 = "0.7.0"
|
|
||||||
once_cell = "1.16.0"
|
|
||||||
pimalaya-email = { git = "https://git.sr.ht/~soywod/pimalaya", default-features = false }
|
|
||||||
pimalaya-keyring = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
|
||||||
pimalaya-oauth2 = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
|
||||||
pimalaya-process = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
|
||||||
pimalaya-secret = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
|
||||||
serde_json = "1.0"
|
|
||||||
shellexpand = "2.1"
|
|
||||||
termcolor = "1.1"
|
|
||||||
terminal_size = "0.1"
|
|
||||||
tokio = { version = "1.23", default-features = false, features = ["macros", "rt-multi-thread"] }
|
|
||||||
toml = "0.7.4"
|
|
||||||
toml_edit = "0.19.8"
|
|
||||||
unicode-width = "0.1"
|
|
||||||
url = "2.2"
|
|
||||||
uuid = { version = "0.8", features = ["v4"] }
|
|
||||||
|
|
||||||
[target.'cfg(target_env = "musl")'.dependencies]
|
[dev-dependencies.tempfile]
|
||||||
rusqlite = { version = "0.29", features = [] }
|
version = "3.3"
|
||||||
[target.'cfg(not(target_env = "musl"))'.dependencies]
|
|
||||||
rusqlite = { version = "0.29", features = ["bundled"] }
|
|
||||||
|
|
||||||
[target.'cfg(not(windows))'.dependencies]
|
[dependencies.anyhow]
|
||||||
coredump = "=0.1.2"
|
version = "1.0"
|
||||||
|
|
||||||
|
[dependencies.atty]
|
||||||
|
version = "0.2"
|
||||||
|
|
||||||
|
[dependencies.chrono]
|
||||||
|
version = "0.4.24"
|
||||||
|
|
||||||
|
[dependencies.clap]
|
||||||
|
version = "4.0"
|
||||||
|
|
||||||
|
[dependencies.clap_complete]
|
||||||
|
version = "4.0"
|
||||||
|
|
||||||
|
[dependencies.clap_mangen]
|
||||||
|
version = "0.2"
|
||||||
|
|
||||||
|
[dependencies.console]
|
||||||
|
version = "0.15.2"
|
||||||
|
|
||||||
|
[dependencies.dialoguer]
|
||||||
|
version = "0.10.2"
|
||||||
|
|
||||||
|
[dependencies.dirs]
|
||||||
|
version = "4.0.0"
|
||||||
|
|
||||||
|
[dependencies.email_address]
|
||||||
|
version = "0.2.4"
|
||||||
|
|
||||||
|
[dependencies.env_logger]
|
||||||
|
version = "0.8"
|
||||||
|
|
||||||
|
[dependencies.erased-serde]
|
||||||
|
version = "0.3"
|
||||||
|
|
||||||
|
[dependencies.indicatif]
|
||||||
|
version = "0.17"
|
||||||
|
|
||||||
|
[dependencies.log]
|
||||||
|
version = "0.4"
|
||||||
|
|
||||||
|
[dependencies.md5]
|
||||||
|
version = "0.7.0"
|
||||||
|
|
||||||
|
[dependencies.once_cell]
|
||||||
|
version = "1.16.0"
|
||||||
|
|
||||||
|
[dependencies.email-lib]
|
||||||
|
version = "=0.15.0"
|
||||||
|
default-features = false
|
||||||
|
|
||||||
|
[dependencies.keyring-lib]
|
||||||
|
version = "=0.1.0"
|
||||||
|
|
||||||
|
[dependencies.oauth-lib]
|
||||||
|
version = "=0.1.0"
|
||||||
|
|
||||||
|
[dependencies.process-lib]
|
||||||
|
version = "=0.1.0"
|
||||||
|
|
||||||
|
[dependencies.mml-lib]
|
||||||
|
version = "=0.2.1"
|
||||||
|
|
||||||
|
[dependencies.secret-lib]
|
||||||
|
version = "=0.1.0"
|
||||||
|
|
||||||
|
[dependencies.serde]
|
||||||
|
version = "1.0"
|
||||||
|
features = ["derive"]
|
||||||
|
|
||||||
|
[dependencies.serde_json]
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
[dependencies.shellexpand]
|
||||||
|
version = "2.1"
|
||||||
|
|
||||||
|
[dependencies.termcolor]
|
||||||
|
version = "1.1"
|
||||||
|
|
||||||
|
[dependencies.terminal_size]
|
||||||
|
version = "0.1"
|
||||||
|
|
||||||
|
[dependencies.tokio]
|
||||||
|
version = "1.23"
|
||||||
|
default-features = false
|
||||||
|
features = ["macros", "rt-multi-thread"]
|
||||||
|
|
||||||
|
[dependencies.toml]
|
||||||
|
version = "0.7.4"
|
||||||
|
|
||||||
|
[dependencies.toml_edit]
|
||||||
|
version = "0.19.8"
|
||||||
|
|
||||||
|
[dependencies.unicode-width]
|
||||||
|
version = "0.1"
|
||||||
|
|
||||||
|
[dependencies.url]
|
||||||
|
version = "2.2"
|
||||||
|
|
||||||
|
[dependencies.uuid]
|
||||||
|
version = "0.8"
|
||||||
|
features = ["v4"]
|
||||||
|
|
||||||
|
[target.'cfg(target_env = "musl")'.dependencies.rusqlite]
|
||||||
|
version = "0.29"
|
||||||
|
features = []
|
||||||
|
|
||||||
|
[target.'cfg(not(target_env = "musl"))'.dependencies.rusqlite]
|
||||||
|
version = "0.29"
|
||||||
|
features = ["bundled"]
|
||||||
|
|
||||||
|
[target.'cfg(not(windows))'.dependencies.coredump]
|
||||||
|
version = "=0.1.2"
|
||||||
|
|
21
README.md
21
README.md
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
https://pimalaya.org/himalaya/
|
https://pimalaya.org/himalaya/
|
||||||
|
|
||||||
CLI to manage your emails, based on the [pimalaya-email](https://sr.ht/~soywod/pimalaya/) library.
|
CLI to manage emails, based on [email-lib](https://sr.ht/~soywod/pimalaya/).
|
||||||
|
|
||||||
![image](https://user-images.githubusercontent.com/10437171/138774902-7b9de5a3-93eb-44b0-8cfb-6d2e11e3b1aa.png)
|
![image](https://user-images.githubusercontent.com/10437171/138774902-7b9de5a3-93eb-44b0-8cfb-6d2e11e3b1aa.png)
|
||||||
|
|
||||||
|
@ -99,16 +99,15 @@ If you want to **discuss** about the project, feel free to join the [Matrix](htt
|
||||||
|
|
||||||
Special thanks to the [nlnet](https://nlnet.nl/project/Himalaya/index.html) foundation that helped Himalaya to receive financial support from the [NGI Assure](https://www.ngi.eu/ngi-projects/ngi-assure/) program of the European Commission in September, 2022.
|
Special thanks to the [nlnet](https://nlnet.nl/project/Himalaya/index.html) foundation that helped Himalaya to receive financial support from the [NGI Assure](https://www.ngi.eu/ngi-projects/ngi-assure/) program of the European Commission in September, 2022.
|
||||||
|
|
||||||
* [himalaya-lib](https://git.sr.ht/~soywod/himalaya-lib)
|
- [IMAP RFC3501](https://tools.ietf.org/html/rfc3501)
|
||||||
* [IMAP RFC3501](https://tools.ietf.org/html/rfc3501)
|
- [Iris](https://github.com/soywod/iris.vim), the himalaya predecessor
|
||||||
* [Iris](https://github.com/soywod/iris.vim), the himalaya predecessor
|
- [isync](https://isync.sourceforge.io/), an email synchronizer for offline usage
|
||||||
* [isync](https://isync.sourceforge.io/), an email synchronizer for offline usage
|
- [NeoMutt](https://neomutt.org/), an email terminal user interface
|
||||||
* [NeoMutt](https://neomutt.org/), an email terminal user interface
|
- [Alpine](http://alpine.x10host.com/alpine/alpine-info/), an other email terminal user interface
|
||||||
* [Alpine](http://alpine.x10host.com/alpine/alpine-info/), an other email terminal user interface
|
- [mutt-wizard](https://github.com/LukeSmithxyz/mutt-wizard), a tool over NeoMutt and isync
|
||||||
* [mutt-wizard](https://github.com/LukeSmithxyz/mutt-wizard), a tool over NeoMutt and isync
|
- [rust-imap](https://github.com/jonhoo/rust-imap), a Rust IMAP library
|
||||||
* [rust-imap](https://github.com/jonhoo/rust-imap), a Rust IMAP library
|
- [lettre](https://github.com/lettre/lettre), a Rust mailer library
|
||||||
* [lettre](https://github.com/lettre/lettre), a Rust mailer library
|
- [mailparse](https://github.com/staktrace/mailparse), a Rust MIME email parser.
|
||||||
* [mailparse](https://github.com/staktrace/mailparse), a Rust MIME email parser.
|
|
||||||
|
|
||||||
## Sponsoring
|
## Sponsoring
|
||||||
|
|
||||||
|
|
32
flake.lock
32
flake.lock
|
@ -8,11 +8,11 @@
|
||||||
"rust-analyzer-src": "rust-analyzer-src"
|
"rust-analyzer-src": "rust-analyzer-src"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1686032467,
|
"lastModified": 1693117181,
|
||||||
"narHash": "sha256-KUCS237H0G1QGx5ehhEmh5yKtcDGCxvVXVtz8xEDAKE=",
|
"narHash": "sha256-LC4MUYim2zsYfuUOXcaSDIFHwzIcHbDmzDTBh5FXDBA=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "fenix",
|
"repo": "fenix",
|
||||||
"rev": "1a3e0f661119a7435099b118912d65bdbbf3bb11",
|
"rev": "8d8f72faedbf61b0f16b9d87c8f79076d7570202",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -42,11 +42,11 @@
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1685518550,
|
"lastModified": 1692799911,
|
||||||
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
|
"narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
|
"rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -82,11 +82,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1679567394,
|
"lastModified": 1692351612,
|
||||||
"narHash": "sha256-ZvLuzPeARDLiQUt6zSZFGOs+HZmE+3g4QURc8mkBsfM=",
|
"narHash": "sha256-KTGonidcdaLadRnv9KFgwSMh1ZbXoR/OBmPjeNMhFwU=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "naersk",
|
"repo": "naersk",
|
||||||
"rev": "88cd22380154a2c36799fe8098888f0f59861a15",
|
"rev": "78789c30d64dea2396c9da516bbcc8db3a475207",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -97,16 +97,16 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1685883127,
|
"lastModified": 1693087214,
|
||||||
"narHash": "sha256-zPDaPNrAtBnO24rNqjHLINHsqTdRbgWy1c/TL3EdwlM=",
|
"narHash": "sha256-Kn1SSqRfPpqcI1MDy82JXrPT1WI8c03TA2F0xu6kS+4=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "d4a9ff82fc18723219b60c66fb2ccb0734c460eb",
|
"rev": "f155f0cf4ea43c4e3c8918d2d327d44777b6cad4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"ref": "nixos-22.11",
|
"ref": "nixos-23.05",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
@ -124,11 +124,11 @@
|
||||||
"rust-analyzer-src": {
|
"rust-analyzer-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1685984106,
|
"lastModified": 1692775770,
|
||||||
"narHash": "sha256-dOEuU1AuASOWdXT/SbVpD8uX7JjiW3lCp08SbviHuww=",
|
"narHash": "sha256-LwoR5N1JHykSte2Ak+Pj/HjJ9fKy9zMJNEftfBJQkLs=",
|
||||||
"owner": "rust-lang",
|
"owner": "rust-lang",
|
||||||
"repo": "rust-analyzer",
|
"repo": "rust-analyzer",
|
||||||
"rev": "d42d55feaafa71e14521bbfe6e7011fbb41980f0",
|
"rev": "f5b7c60ff7a79bfb3e10f3e98c81b7bb4cb53c68",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
description = "CLI to manage your emails.";
|
description = "CLI to manage emails.";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-22.11";
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.05";
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
gitignore = {
|
gitignore = {
|
||||||
url = "github:hercules-ci/gitignore.nix";
|
url = "github:hercules-ci/gitignore.nix";
|
||||||
|
@ -48,6 +48,7 @@
|
||||||
notmuch
|
notmuch
|
||||||
|
|
||||||
# gpg
|
# gpg
|
||||||
|
gnupg
|
||||||
gpgme
|
gpgme
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
@ -95,8 +96,8 @@
|
||||||
SQLITE3_LIB_DIR = "${sqlite.out}/lib";
|
SQLITE3_LIB_DIR = "${sqlite.out}/lib";
|
||||||
hardeningDisable = [ "all" ];
|
hardeningDisable = [ "all" ];
|
||||||
});
|
});
|
||||||
# FIXME: package does not build, assembler messages: unknown
|
# FIXME: bzlip: fatal error: windows.h: No such file or directory
|
||||||
# pseudo-op…
|
# May be related to SQLite.
|
||||||
windows = mkPackageWithTarget "x86_64-pc-windows-gnu" {
|
windows = mkPackageWithTarget "x86_64-pc-windows-gnu" {
|
||||||
strictDeps = true;
|
strictDeps = true;
|
||||||
depsBuildBuild = with pkgs.pkgsCross.mingwW64; [
|
depsBuildBuild = with pkgs.pkgsCross.mingwW64; [
|
||||||
|
|
|
@ -2,7 +2,7 @@ fenix:
|
||||||
|
|
||||||
let
|
let
|
||||||
file = ./rust-toolchain.toml;
|
file = ./rust-toolchain.toml;
|
||||||
sha256 = "ks0nMEGGXKrHnfv4Fku+vhQ7gx76ruv6Ij4fKZR3l78=";
|
sha256 = "Q9UgzzvxLi4x9aWUJTn+/5EXekC98ODRU1TwhUs9RnY=";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
fromFile = { system }: fenix.packages.${system}.fromToolchainFile {
|
fromFile = { system }: fenix.packages.${system}.fromToolchainFile {
|
||||||
|
|
8
src/cache/id_mapper.rs
vendored
8
src/cache/id_mapper.rs
vendored
|
@ -1,13 +1,13 @@
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use log::{debug, trace};
|
|
||||||
#[cfg(feature = "imap-backend")]
|
#[cfg(feature = "imap-backend")]
|
||||||
use pimalaya_email::backend::ImapBackend;
|
use email::backend::ImapBackend;
|
||||||
#[cfg(feature = "notmuch-backend")]
|
#[cfg(feature = "notmuch-backend")]
|
||||||
use pimalaya_email::backend::NotmuchBackend;
|
use email::backend::NotmuchBackend;
|
||||||
use pimalaya_email::{
|
use email::{
|
||||||
account::AccountConfig,
|
account::AccountConfig,
|
||||||
backend::{Backend, MaildirBackend},
|
backend::{Backend, MaildirBackend},
|
||||||
};
|
};
|
||||||
|
use log::{debug, trace};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
const ID_MAPPER_DB_FILE_NAME: &str = ".id-mapper.sqlite";
|
const ID_MAPPER_DB_FILE_NAME: &str = ".id-mapper.sqlite";
|
||||||
|
|
|
@ -6,14 +6,14 @@
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use dialoguer::Confirm;
|
use dialoguer::Confirm;
|
||||||
use dirs::{config_dir, home_dir};
|
use dirs::{config_dir, home_dir};
|
||||||
use log::{debug, trace};
|
use email::{
|
||||||
use pimalaya_email::{
|
|
||||||
account::AccountConfig,
|
account::AccountConfig,
|
||||||
email::{EmailHooks, EmailTextPlainFormat},
|
email::{EmailHooks, EmailTextPlainFormat},
|
||||||
};
|
};
|
||||||
use pimalaya_process::Cmd;
|
use log::{debug, trace};
|
||||||
|
use process::Cmd;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashMap, fs, path::PathBuf, process};
|
use std::{collections::HashMap, fs, path::PathBuf, process::exit};
|
||||||
use toml;
|
use toml;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -101,7 +101,7 @@ impl DeserializedConfig {
|
||||||
.interact_opt()?
|
.interact_opt()?
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
{
|
{
|
||||||
process::exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
wizard::configure().await?
|
wizard::configure().await?
|
||||||
|
@ -160,19 +160,19 @@ impl DeserializedConfig {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use pimalaya_email::{
|
use email::{
|
||||||
account::PasswdConfig,
|
account::PasswdConfig,
|
||||||
backend::{BackendConfig, MaildirConfig},
|
backend::{BackendConfig, MaildirConfig},
|
||||||
sender::{SenderConfig, SendmailConfig},
|
sender::{SenderConfig, SendmailConfig},
|
||||||
};
|
};
|
||||||
use pimalaya_secret::Secret;
|
use secret::Secret;
|
||||||
|
|
||||||
#[cfg(feature = "notmuch-backend")]
|
#[cfg(feature = "notmuch-backend")]
|
||||||
use pimalaya_email::backend::NotmuchConfig;
|
use email::backend::NotmuchConfig;
|
||||||
#[cfg(feature = "imap-backend")]
|
#[cfg(feature = "imap-backend")]
|
||||||
use pimalaya_email::backend::{ImapAuthConfig, ImapConfig};
|
use email::backend::{ImapAuthConfig, ImapConfig};
|
||||||
#[cfg(feature = "smtp-sender")]
|
#[cfg(feature = "smtp-sender")]
|
||||||
use pimalaya_email::sender::{SmtpAuthConfig, SmtpConfig};
|
use email::sender::{SmtpAuthConfig, SmtpConfig};
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
|
@ -463,17 +463,28 @@ mod tests {
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(config
|
assert_eq!(
|
||||||
.unwrap_err()
|
config.unwrap(),
|
||||||
.root_cause()
|
DeserializedConfig {
|
||||||
.to_string()
|
accounts: HashMap::from_iter([(
|
||||||
.contains("missing field `sendmail-cmd`"));
|
"account".into(),
|
||||||
|
DeserializedAccountConfig {
|
||||||
|
email: "test@localhost".into(),
|
||||||
|
sender: SenderConfig::Sendmail(SendmailConfig {
|
||||||
|
cmd: "/usr/sbin/sendmail".into()
|
||||||
|
}),
|
||||||
|
..DeserializedAccountConfig::default()
|
||||||
|
}
|
||||||
|
)]),
|
||||||
|
..DeserializedConfig::default()
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "smtp-sender")]
|
#[cfg(feature = "smtp-sender")]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn account_smtp_sender_minimum_config() {
|
async fn account_smtp_sender_minimum_config() {
|
||||||
use pimalaya_email::sender::SenderConfig;
|
use email::sender::SenderConfig;
|
||||||
|
|
||||||
let config = make_config(
|
let config = make_config(
|
||||||
"[account]
|
"[account]
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
#[cfg(feature = "cmds-pgp")]
|
#[cfg(feature = "pgp-commands")]
|
||||||
use pimalaya_email::account::CmdsPgpConfig;
|
use email::account::CmdsPgpConfig;
|
||||||
#[cfg(feature = "gpg")]
|
#[cfg(feature = "pgp-gpg")]
|
||||||
use pimalaya_email::account::GpgConfig;
|
use email::account::GpgConfig;
|
||||||
#[cfg(feature = "native-pgp")]
|
#[cfg(feature = "pgp-native")]
|
||||||
use pimalaya_email::account::{NativePgpConfig, NativePgpSecretKey, SignedSecretKey};
|
use email::account::{NativePgpConfig, NativePgpSecretKey, SignedSecretKey};
|
||||||
#[cfg(feature = "notmuch-backend")]
|
#[cfg(feature = "notmuch-backend")]
|
||||||
use pimalaya_email::backend::NotmuchConfig;
|
use email::backend::NotmuchConfig;
|
||||||
#[cfg(feature = "imap-backend")]
|
#[cfg(feature = "imap-backend")]
|
||||||
use pimalaya_email::backend::{ImapAuthConfig, ImapConfig};
|
use email::backend::{ImapAuthConfig, ImapConfig};
|
||||||
#[cfg(feature = "smtp-sender")]
|
#[cfg(feature = "smtp-sender")]
|
||||||
use pimalaya_email::sender::{SmtpAuthConfig, SmtpConfig};
|
use email::sender::{SmtpAuthConfig, SmtpConfig};
|
||||||
use pimalaya_email::{
|
use email::{
|
||||||
account::{OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig, PgpConfig},
|
account::{OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig, PgpConfig},
|
||||||
backend::{BackendConfig, MaildirConfig},
|
backend::{BackendConfig, MaildirConfig},
|
||||||
email::{EmailHooks, EmailTextPlainFormat},
|
email::{EmailHooks, EmailTextPlainFormat},
|
||||||
folder::sync::FolderSyncStrategy,
|
folder::sync::FolderSyncStrategy,
|
||||||
sender::{SenderConfig, SendmailConfig},
|
sender::{SenderConfig, SendmailConfig},
|
||||||
};
|
};
|
||||||
use pimalaya_keyring::Entry;
|
use keyring::Entry;
|
||||||
use pimalaya_process::{Cmd, Pipeline, SingleCmd};
|
use process::{Cmd, Pipeline, SingleCmd};
|
||||||
use pimalaya_secret::Secret;
|
use secret::Secret;
|
||||||
use serde::{ser::SerializeSeq, Deserialize, Serialize, Serializer};
|
use serde::{ser::SerializeSeq, Deserialize, Serialize, Serializer};
|
||||||
use std::{collections::HashSet, ops::Deref, path::PathBuf};
|
use std::{collections::HashSet, ops::Deref, path::PathBuf};
|
||||||
|
|
||||||
|
@ -407,23 +407,23 @@ pub enum FolderSyncStrategyDef {
|
||||||
pub enum PgpConfigDef {
|
pub enum PgpConfigDef {
|
||||||
#[default]
|
#[default]
|
||||||
None,
|
None,
|
||||||
#[cfg(feature = "cmds-pgp")]
|
#[cfg(feature = "pgp-commands")]
|
||||||
#[serde(with = "CmdsPgpConfigDef", alias = "commands")]
|
#[serde(with = "CmdsPgpConfigDef", alias = "commands")]
|
||||||
Cmds(CmdsPgpConfig),
|
Cmds(CmdsPgpConfig),
|
||||||
#[cfg(feature = "gpg")]
|
#[cfg(feature = "pgp-gpg")]
|
||||||
#[serde(with = "GpgConfigDef")]
|
#[serde(with = "GpgConfigDef")]
|
||||||
Gpg(GpgConfig),
|
Gpg(GpgConfig),
|
||||||
#[cfg(feature = "native-pgp")]
|
#[cfg(feature = "pgp-native")]
|
||||||
#[serde(with = "NativePgpConfigDef")]
|
#[serde(with = "NativePgpConfigDef")]
|
||||||
Native(NativePgpConfig),
|
Native(NativePgpConfig),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gpg")]
|
#[cfg(feature = "pgp-gpg")]
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "GpgConfig", rename_all = "kebab-case")]
|
#[serde(remote = "GpgConfig", rename_all = "kebab-case")]
|
||||||
pub struct GpgConfigDef;
|
pub struct GpgConfigDef;
|
||||||
|
|
||||||
#[cfg(feature = "cmds-pgp")]
|
#[cfg(feature = "pgp-commands")]
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "CmdsPgpConfig", rename_all = "kebab-case")]
|
#[serde(remote = "CmdsPgpConfig", rename_all = "kebab-case")]
|
||||||
pub struct CmdsPgpConfigDef {
|
pub struct CmdsPgpConfigDef {
|
||||||
|
@ -441,7 +441,7 @@ pub struct CmdsPgpConfigDef {
|
||||||
verify_cmd: Option<Cmd>,
|
verify_cmd: Option<Cmd>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "native-pgp")]
|
#[cfg(feature = "pgp-native")]
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "NativePgpConfig", rename_all = "kebab-case")]
|
#[serde(remote = "NativePgpConfig", rename_all = "kebab-case")]
|
||||||
pub struct NativePgpConfigDef {
|
pub struct NativePgpConfigDef {
|
||||||
|
@ -455,7 +455,7 @@ pub struct NativePgpConfigDef {
|
||||||
key_servers: Vec<String>,
|
key_servers: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "native-pgp")]
|
#[cfg(feature = "pgp-native")]
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "NativePgpSecretKey", rename_all = "kebab-case")]
|
#[serde(remote = "NativePgpSecretKey", rename_all = "kebab-case")]
|
||||||
pub enum NativePgpSecretKeyDef {
|
pub enum NativePgpSecretKeyDef {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! accounts from the config file.
|
//! accounts from the config file.
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use pimalaya_email::backend::BackendConfig;
|
use email::backend::BackendConfig;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::{collections::hash_map::Iter, ops::Deref};
|
use std::{collections::hash_map::Iter, ops::Deref};
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||||
|
use email::folder::sync::FolderSyncStrategy;
|
||||||
use log::info;
|
use log::info;
|
||||||
use pimalaya_email::folder::sync::FolderSyncStrategy;
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::{folder, ui::table};
|
use crate::{folder, ui::table};
|
||||||
|
|
|
@ -4,17 +4,17 @@
|
||||||
//! account in the accounts section of the user configuration file.
|
//! account in the accounts section of the user configuration file.
|
||||||
|
|
||||||
#[cfg(feature = "imap-backend")]
|
#[cfg(feature = "imap-backend")]
|
||||||
use pimalaya_email::backend::ImapAuthConfig;
|
use email::backend::ImapAuthConfig;
|
||||||
#[cfg(feature = "smtp-sender")]
|
#[cfg(feature = "smtp-sender")]
|
||||||
use pimalaya_email::sender::SmtpAuthConfig;
|
use email::sender::SmtpAuthConfig;
|
||||||
use pimalaya_email::{
|
use email::{
|
||||||
account::{AccountConfig, PgpConfig},
|
account::{AccountConfig, PgpConfig},
|
||||||
backend::BackendConfig,
|
backend::BackendConfig,
|
||||||
email::{EmailHooks, EmailTextPlainFormat},
|
email::{EmailHooks, EmailTextPlainFormat},
|
||||||
folder::sync::FolderSyncStrategy,
|
folder::sync::FolderSyncStrategy,
|
||||||
sender::SenderConfig,
|
sender::SenderConfig,
|
||||||
};
|
};
|
||||||
use pimalaya_process::Cmd;
|
use process::Cmd;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashMap, path::PathBuf};
|
use std::{collections::HashMap, path::PathBuf};
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,11 @@
|
||||||
//! This module gathers all account actions triggered by the CLI.
|
//! This module gathers all account actions triggered by the CLI.
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use indicatif::{MultiProgress, ProgressBar, ProgressFinish, ProgressStyle};
|
|
||||||
use log::{info, trace, warn};
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
#[cfg(feature = "imap-backend")]
|
#[cfg(feature = "imap-backend")]
|
||||||
use pimalaya_email::backend::ImapAuthConfig;
|
use email::backend::ImapAuthConfig;
|
||||||
#[cfg(feature = "smtp-sender")]
|
#[cfg(feature = "smtp-sender")]
|
||||||
use pimalaya_email::sender::SmtpAuthConfig;
|
use email::sender::SmtpAuthConfig;
|
||||||
use pimalaya_email::{
|
use email::{
|
||||||
account::{
|
account::{
|
||||||
sync::{AccountSyncBuilder, AccountSyncProgressEvent},
|
sync::{AccountSyncBuilder, AccountSyncProgressEvent},
|
||||||
AccountConfig,
|
AccountConfig,
|
||||||
|
@ -18,6 +15,9 @@ use pimalaya_email::{
|
||||||
backend::BackendConfig,
|
backend::BackendConfig,
|
||||||
sender::SenderConfig,
|
sender::SenderConfig,
|
||||||
};
|
};
|
||||||
|
use indicatif::{MultiProgress, ProgressBar, ProgressFinish, ProgressStyle};
|
||||||
|
use log::{info, trace, warn};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
use std::{collections::HashMap, sync::Mutex};
|
use std::{collections::HashMap, sync::Mutex};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -294,7 +294,7 @@ pub async fn sync<P: Printer>(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use pimalaya_email::{account::AccountConfig, backend::ImapConfig};
|
use email::{account::AccountConfig, backend::ImapConfig};
|
||||||
use std::{collections::HashMap, fmt::Debug, io};
|
use std::{collections::HashMap, fmt::Debug, io};
|
||||||
use termcolor::ColorSpec;
|
use termcolor::ColorSpec;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
//! This module gathers all IMAP handlers triggered by the CLI.
|
//! This module gathers all IMAP handlers triggered by the CLI.
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use pimalaya_email::backend::ImapBackend;
|
use email::backend::ImapBackend;
|
||||||
|
|
||||||
pub async fn notify(imap: &mut ImapBackend, folder: &str, keepalive: u64) -> Result<()> {
|
pub async fn notify(imap: &mut ImapBackend, folder: &str, keepalive: u64) -> Result<()> {
|
||||||
imap.notify(keepalive, folder).await?;
|
imap.notify(keepalive, folder).await?;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use dialoguer::{Confirm, Input, Password, Select};
|
use dialoguer::{Confirm, Input, Password, Select};
|
||||||
use pimalaya_email::{
|
use email::{
|
||||||
account::{OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig},
|
account::{OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig},
|
||||||
backend::{BackendConfig, ImapAuthConfig, ImapConfig},
|
backend::{BackendConfig, ImapAuthConfig, ImapConfig},
|
||||||
};
|
};
|
||||||
use pimalaya_oauth2::{AuthorizationCodeGrant, Client};
|
use oauth::v2_0::{AuthorizationCodeGrant, Client};
|
||||||
use pimalaya_secret::Secret;
|
use secret::Secret;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::wizard::{prompt_passwd, THEME},
|
config::wizard::{prompt_passwd, THEME},
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use dialoguer::Input;
|
use dialoguer::Input;
|
||||||
use dirs::home_dir;
|
use dirs::home_dir;
|
||||||
use pimalaya_email::backend::{BackendConfig, MaildirConfig};
|
use email::backend::{BackendConfig, MaildirConfig};
|
||||||
|
|
||||||
use crate::config::wizard::THEME;
|
use crate::config::wizard::THEME;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use dialoguer::Input;
|
use dialoguer::Input;
|
||||||
use pimalaya_email::backend::{BackendConfig, NotmuchBackend, NotmuchConfig};
|
use email::backend::{BackendConfig, NotmuchBackend, NotmuchConfig};
|
||||||
|
|
||||||
use crate::config::wizard::THEME;
|
use crate::config::wizard::THEME;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use dialoguer::Select;
|
use dialoguer::Select;
|
||||||
use pimalaya_email::backend::BackendConfig;
|
use email::backend::BackendConfig;
|
||||||
|
|
||||||
use crate::config::wizard::THEME;
|
use crate::config::wizard::THEME;
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use atty::Stream;
|
use atty::Stream;
|
||||||
use log::{debug, trace};
|
use email::{
|
||||||
use pimalaya_email::{
|
|
||||||
account::AccountConfig,
|
account::AccountConfig,
|
||||||
backend::Backend,
|
backend::Backend,
|
||||||
email::{template::FilterParts, Flag, Flags, Message, MessageBuilder},
|
email::{template::FilterParts, Flag, Flags, Message, MessageBuilder},
|
||||||
sender::Sender,
|
sender::Sender,
|
||||||
};
|
};
|
||||||
|
use log::{debug, trace};
|
||||||
use std::{
|
use std::{
|
||||||
fs,
|
fs,
|
||||||
io::{self, BufRead},
|
io::{self, BufRead},
|
||||||
|
@ -127,7 +127,7 @@ pub async fn forward<P: Printer>(
|
||||||
.with_some_body(body)
|
.with_some_body(body)
|
||||||
.build()
|
.build()
|
||||||
.await?;
|
.await?;
|
||||||
trace!("initial template: {}", *tpl);
|
trace!("initial template: {tpl}");
|
||||||
editor::edit_tpl_with_editor(config, printer, backend, sender, tpl).await?;
|
editor::edit_tpl_with_editor(config, printer, backend, sender, tpl).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -276,7 +276,7 @@ pub async fn reply<P: Printer>(
|
||||||
.with_reply_all(all)
|
.with_reply_all(all)
|
||||||
.build()
|
.build()
|
||||||
.await?;
|
.await?;
|
||||||
trace!("initial template: {}", *tpl);
|
trace!("initial template: {tpl}");
|
||||||
editor::edit_tpl_with_editor(config, printer, backend, sender, tpl).await?;
|
editor::edit_tpl_with_editor(config, printer, backend, sender, tpl).await?;
|
||||||
backend
|
backend
|
||||||
.add_flags(&folder, vec![id], &Flags::from_iter([Flag::Answered]))
|
.add_flags(&folder, vec![id], &Flags::from_iter([Flag::Answered]))
|
||||||
|
@ -414,7 +414,7 @@ pub async fn write<P: Printer>(
|
||||||
.with_some_body(body)
|
.with_some_body(body)
|
||||||
.build()
|
.build()
|
||||||
.await?;
|
.await?;
|
||||||
trace!("initial template: {}", *tpl);
|
trace!("initial template: {tpl}");
|
||||||
editor::edit_tpl_with_editor(config, printer, backend, sender, tpl).await?;
|
editor::edit_tpl_with_editor(config, printer, backend, sender, tpl).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use pimalaya_email::account::AccountConfig;
|
use email::account::AccountConfig;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::ops;
|
use std::ops;
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ impl Envelopes {
|
||||||
pub fn from_backend(
|
pub fn from_backend(
|
||||||
config: &AccountConfig,
|
config: &AccountConfig,
|
||||||
id_mapper: &IdMapper,
|
id_mapper: &IdMapper,
|
||||||
envelopes: pimalaya_email::email::Envelopes,
|
envelopes: email::email::Envelopes,
|
||||||
) -> Result<Envelopes> {
|
) -> Result<Envelopes> {
|
||||||
let envelopes = envelopes
|
let envelopes = envelopes
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -59,7 +59,7 @@ impl PrintTable for Envelopes {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use chrono::DateTime;
|
use chrono::DateTime;
|
||||||
use pimalaya_email::account::AccountConfig;
|
use email::account::AccountConfig;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use crate::{Envelopes, IdMapper};
|
use crate::{Envelopes, IdMapper};
|
||||||
|
@ -69,11 +69,10 @@ mod tests {
|
||||||
let config = AccountConfig::default();
|
let config = AccountConfig::default();
|
||||||
let id_mapper = IdMapper::Dummy;
|
let id_mapper = IdMapper::Dummy;
|
||||||
|
|
||||||
let envelopes =
|
let envelopes = email::email::Envelopes::from_iter([email::email::Envelope {
|
||||||
pimalaya_email::email::Envelopes::from_iter([pimalaya_email::email::Envelope {
|
date: DateTime::parse_from_rfc3339("2023-06-15T09:42:00+04:00").unwrap(),
|
||||||
date: DateTime::parse_from_rfc3339("2023-06-15T09:42:00+04:00").unwrap(),
|
..Default::default()
|
||||||
..Default::default()
|
}]);
|
||||||
}]);
|
|
||||||
let envelopes = Envelopes::from_backend(&config, &id_mapper, envelopes).unwrap();
|
let envelopes = Envelopes::from_backend(&config, &id_mapper, envelopes).unwrap();
|
||||||
|
|
||||||
let expected_date = "2023-06-15 09:42+04:00";
|
let expected_date = "2023-06-15 09:42+04:00";
|
||||||
|
@ -90,11 +89,10 @@ mod tests {
|
||||||
..AccountConfig::default()
|
..AccountConfig::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let envelopes =
|
let envelopes = email::email::Envelopes::from_iter([email::email::Envelope {
|
||||||
pimalaya_email::email::Envelopes::from_iter([pimalaya_email::email::Envelope {
|
date: DateTime::parse_from_rfc3339("2023-06-15T09:42:00+04:00").unwrap(),
|
||||||
date: DateTime::parse_from_rfc3339("2023-06-15T09:42:00+04:00").unwrap(),
|
..Default::default()
|
||||||
..Default::default()
|
}]);
|
||||||
}]);
|
|
||||||
let envelopes = Envelopes::from_backend(&config, &id_mapper, envelopes).unwrap();
|
let envelopes = Envelopes::from_backend(&config, &id_mapper, envelopes).unwrap();
|
||||||
|
|
||||||
let expected_date = "15/06/2023 09h42";
|
let expected_date = "15/06/2023 09h42";
|
||||||
|
@ -114,11 +112,10 @@ mod tests {
|
||||||
..AccountConfig::default()
|
..AccountConfig::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let envelopes =
|
let envelopes = email::email::Envelopes::from_iter([email::email::Envelope {
|
||||||
pimalaya_email::email::Envelopes::from_iter([pimalaya_email::email::Envelope {
|
date: DateTime::parse_from_rfc3339("2023-06-15T09:42:00+04:00").unwrap(),
|
||||||
date: DateTime::parse_from_rfc3339("2023-06-15T09:42:00+04:00").unwrap(),
|
..Default::default()
|
||||||
..Default::default()
|
}]);
|
||||||
}]);
|
|
||||||
let envelopes = Envelopes::from_backend(&config, &id_mapper, envelopes).unwrap();
|
let envelopes = Envelopes::from_backend(&config, &id_mapper, envelopes).unwrap();
|
||||||
|
|
||||||
let expected_date = "15/06/2023 05h42";
|
let expected_date = "15/06/2023 05h42";
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
//! This module contains the command matcher, the subcommands and the
|
//! This module contains the command matcher, the subcommands and the
|
||||||
//! arguments related to the email flag domain.
|
//! arguments related to the email flag domain.
|
||||||
|
|
||||||
|
use ::email::email::{Flag, Flags};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::{Arg, ArgMatches, Command};
|
use clap::{Arg, ArgMatches, Command};
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use pimalaya_email::email::{Flag, Flags};
|
|
||||||
|
|
||||||
use crate::email;
|
use crate::email;
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,9 @@ pub enum Flag {
|
||||||
Custom(String),
|
Custom(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&pimalaya_email::email::Flag> for Flag {
|
impl From<&email::email::Flag> for Flag {
|
||||||
fn from(flag: &pimalaya_email::email::Flag) -> Self {
|
fn from(flag: &email::email::Flag) -> Self {
|
||||||
use pimalaya_email::email::Flag::*;
|
use email::email::Flag::*;
|
||||||
match flag {
|
match flag {
|
||||||
Seen => Flag::Seen,
|
Seen => Flag::Seen,
|
||||||
Answered => Flag::Answered,
|
Answered => Flag::Answered,
|
||||||
|
|
|
@ -14,8 +14,8 @@ impl ops::Deref for Flags {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<pimalaya_email::email::Flags> for Flags {
|
impl From<email::email::Flags> for Flags {
|
||||||
fn from(flags: pimalaya_email::email::Flags) -> Self {
|
fn from(flags: email::email::Flags) -> Self {
|
||||||
Flags(flags.iter().map(Flag::from).collect())
|
Flags(flags.iter().map(Flag::from).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use pimalaya_email::{backend::Backend, email::Flags};
|
use email::{backend::Backend, email::Flags};
|
||||||
|
|
||||||
use crate::{printer::Printer, IdMapper};
|
use crate::{printer::Printer, IdMapper};
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ pub struct Folder {
|
||||||
pub desc: String,
|
pub desc: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&pimalaya_email::folder::Folder> for Folder {
|
impl From<&email::folder::Folder> for Folder {
|
||||||
fn from(folder: &pimalaya_email::folder::Folder) -> Self {
|
fn from(folder: &email::folder::Folder) -> Self {
|
||||||
Folder {
|
Folder {
|
||||||
name: folder.name.clone(),
|
name: folder.name.clone(),
|
||||||
desc: folder.desc.clone(),
|
desc: folder.desc.clone(),
|
||||||
|
|
|
@ -19,8 +19,8 @@ impl ops::Deref for Folders {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<pimalaya_email::folder::Folders> for Folders {
|
impl From<email::folder::Folders> for Folders {
|
||||||
fn from(folders: pimalaya_email::folder::Folders) -> Self {
|
fn from(folders: email::folder::Folders) -> Self {
|
||||||
Folders(folders.iter().map(Folder::from).collect())
|
Folders(folders.iter().map(Folder::from).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use dialoguer::Confirm;
|
use dialoguer::Confirm;
|
||||||
use pimalaya_email::{account::AccountConfig, backend::Backend};
|
use email::{account::AccountConfig, backend::Backend};
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -68,7 +68,7 @@ pub async fn delete<P: Printer>(
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use pimalaya_email::{
|
use email::{
|
||||||
account::AccountConfig,
|
account::AccountConfig,
|
||||||
backend::Backend,
|
backend::Backend,
|
||||||
email::{Envelope, Envelopes, Flags, Messages},
|
email::{Envelope, Envelopes, Flags, Messages},
|
||||||
|
@ -152,10 +152,10 @@ mod tests {
|
||||||
fn name(&self) -> String {
|
fn name(&self) -> String {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
async fn add_folder(&mut self, _: &str) -> pimalaya_email::Result<()> {
|
async fn add_folder(&mut self, _: &str) -> email::Result<()> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
async fn list_folders(&mut self) -> pimalaya_email::Result<Folders> {
|
async fn list_folders(&mut self) -> email::Result<Folders> {
|
||||||
Ok(Folders::from_iter([
|
Ok(Folders::from_iter([
|
||||||
Folder {
|
Folder {
|
||||||
name: "INBOX".into(),
|
name: "INBOX".into(),
|
||||||
|
@ -167,16 +167,16 @@ mod tests {
|
||||||
},
|
},
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
async fn expunge_folder(&mut self, _: &str) -> pimalaya_email::Result<()> {
|
async fn expunge_folder(&mut self, _: &str) -> email::Result<()> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
async fn purge_folder(&mut self, _: &str) -> pimalaya_email::Result<()> {
|
async fn purge_folder(&mut self, _: &str) -> email::Result<()> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
async fn delete_folder(&mut self, _: &str) -> pimalaya_email::Result<()> {
|
async fn delete_folder(&mut self, _: &str) -> email::Result<()> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
async fn get_envelope(&mut self, _: &str, _: &str) -> pimalaya_email::Result<Envelope> {
|
async fn get_envelope(&mut self, _: &str, _: &str) -> email::Result<Envelope> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
async fn list_envelopes(
|
async fn list_envelopes(
|
||||||
|
@ -184,7 +184,7 @@ mod tests {
|
||||||
_: &str,
|
_: &str,
|
||||||
_: usize,
|
_: usize,
|
||||||
_: usize,
|
_: usize,
|
||||||
) -> pimalaya_email::Result<Envelopes> {
|
) -> email::Result<Envelopes> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
async fn search_envelopes(
|
async fn search_envelopes(
|
||||||
|
@ -194,64 +194,31 @@ mod tests {
|
||||||
_: &str,
|
_: &str,
|
||||||
_: usize,
|
_: usize,
|
||||||
_: usize,
|
_: usize,
|
||||||
) -> pimalaya_email::Result<Envelopes> {
|
) -> email::Result<Envelopes> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
async fn add_email(
|
async fn add_email(&mut self, _: &str, _: &[u8], _: &Flags) -> email::Result<String> {
|
||||||
&mut self,
|
|
||||||
_: &str,
|
|
||||||
_: &[u8],
|
|
||||||
_: &Flags,
|
|
||||||
) -> pimalaya_email::Result<String> {
|
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
async fn get_emails(
|
async fn get_emails(&mut self, _: &str, _: Vec<&str>) -> email::Result<Messages> {
|
||||||
&mut self,
|
|
||||||
_: &str,
|
|
||||||
_: Vec<&str>,
|
|
||||||
) -> pimalaya_email::Result<Messages> {
|
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
async fn preview_emails(
|
async fn preview_emails(&mut self, _: &str, _: Vec<&str>) -> email::Result<Messages> {
|
||||||
&mut self,
|
|
||||||
_: &str,
|
|
||||||
_: Vec<&str>,
|
|
||||||
) -> pimalaya_email::Result<Messages> {
|
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
async fn copy_emails(
|
async fn copy_emails(&mut self, _: &str, _: &str, _: Vec<&str>) -> email::Result<()> {
|
||||||
&mut self,
|
|
||||||
_: &str,
|
|
||||||
_: &str,
|
|
||||||
_: Vec<&str>,
|
|
||||||
) -> pimalaya_email::Result<()> {
|
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
async fn move_emails(
|
async fn move_emails(&mut self, _: &str, _: &str, _: Vec<&str>) -> email::Result<()> {
|
||||||
&mut self,
|
|
||||||
_: &str,
|
|
||||||
_: &str,
|
|
||||||
_: Vec<&str>,
|
|
||||||
) -> pimalaya_email::Result<()> {
|
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
async fn delete_emails(&mut self, _: &str, _: Vec<&str>) -> pimalaya_email::Result<()> {
|
async fn delete_emails(&mut self, _: &str, _: Vec<&str>) -> email::Result<()> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
async fn add_flags(
|
async fn add_flags(&mut self, _: &str, _: Vec<&str>, _: &Flags) -> email::Result<()> {
|
||||||
&mut self,
|
|
||||||
_: &str,
|
|
||||||
_: Vec<&str>,
|
|
||||||
_: &Flags,
|
|
||||||
) -> pimalaya_email::Result<()> {
|
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
async fn set_flags(
|
async fn set_flags(&mut self, _: &str, _: Vec<&str>, _: &Flags) -> email::Result<()> {
|
||||||
&mut self,
|
|
||||||
_: &str,
|
|
||||||
_: Vec<&str>,
|
|
||||||
_: &Flags,
|
|
||||||
) -> pimalaya_email::Result<()> {
|
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
async fn remove_flags(
|
async fn remove_flags(
|
||||||
|
@ -259,7 +226,7 @@ mod tests {
|
||||||
_: &str,
|
_: &str,
|
||||||
_: Vec<&str>,
|
_: Vec<&str>,
|
||||||
_: &Flags,
|
_: &Flags,
|
||||||
) -> pimalaya_email::Result<()> {
|
) -> email::Result<()> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use dialoguer::Input;
|
use dialoguer::Input;
|
||||||
use pimalaya_email::sender::{SenderConfig, SendmailConfig};
|
use email::sender::{SenderConfig, SendmailConfig};
|
||||||
|
|
||||||
use crate::config::wizard::THEME;
|
use crate::config::wizard::THEME;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use dialoguer::{Confirm, Input, Select};
|
use dialoguer::{Confirm, Input, Select};
|
||||||
use pimalaya_email::{
|
use email::{
|
||||||
account::{OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig},
|
account::{OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig},
|
||||||
sender::{SenderConfig, SmtpAuthConfig, SmtpConfig},
|
sender::{SenderConfig, SmtpAuthConfig, SmtpConfig},
|
||||||
};
|
};
|
||||||
use pimalaya_oauth2::{AuthorizationCodeGrant, Client};
|
use oauth::v2_0::{AuthorizationCodeGrant, Client};
|
||||||
use pimalaya_secret::Secret;
|
use secret::Secret;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::wizard::{prompt_passwd, THEME},
|
config::wizard::{prompt_passwd, THEME},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use dialoguer::Select;
|
use dialoguer::Select;
|
||||||
use pimalaya_email::sender::SenderConfig;
|
use email::sender::SenderConfig;
|
||||||
|
|
||||||
use crate::config::wizard::THEME;
|
use crate::config::wizard::THEME;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use atty::Stream;
|
use atty::Stream;
|
||||||
use pimalaya_email::{
|
use email::{
|
||||||
account::AccountConfig,
|
account::AccountConfig,
|
||||||
backend::Backend,
|
backend::Backend,
|
||||||
email::{Flag, Flags, Message, Tpl},
|
email::{Flag, Flags, Message},
|
||||||
sender::Sender,
|
sender::Sender,
|
||||||
};
|
};
|
||||||
|
use mml::MmlCompiler;
|
||||||
use std::io::{stdin, BufRead};
|
use std::io::{stdin, BufRead};
|
||||||
|
|
||||||
use crate::{printer::Printer, IdMapper};
|
use crate::{printer::Printer, IdMapper};
|
||||||
|
@ -76,7 +77,7 @@ pub async fn save<P: Printer>(
|
||||||
folder: &str,
|
folder: &str,
|
||||||
tpl: String,
|
tpl: String,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let email = Tpl::from(if atty::is(Stream::Stdin) || printer.is_json() {
|
let mml = if atty::is(Stream::Stdin) || printer.is_json() {
|
||||||
tpl.replace("\r", "")
|
tpl.replace("\r", "")
|
||||||
} else {
|
} else {
|
||||||
stdin()
|
stdin()
|
||||||
|
@ -85,11 +86,13 @@ pub async fn save<P: Printer>(
|
||||||
.filter_map(Result::ok)
|
.filter_map(Result::ok)
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join("\n")
|
.join("\n")
|
||||||
})
|
};
|
||||||
.with_pgp(config.pgp.clone())
|
|
||||||
.compile()
|
let email = MmlCompiler::new()
|
||||||
.await?
|
.with_pgp(config.pgp.clone())
|
||||||
.write_to_vec()?;
|
.compile(mml)
|
||||||
|
.await?
|
||||||
|
.write_to_vec()?;
|
||||||
|
|
||||||
let id = backend.add_email(folder, &email, &Flags::default()).await?;
|
let id = backend.add_email(folder, &email, &Flags::default()).await?;
|
||||||
id_mapper.create_alias(id)?;
|
id_mapper.create_alias(id)?;
|
||||||
|
@ -105,7 +108,8 @@ pub async fn send<P: Printer>(
|
||||||
tpl: String,
|
tpl: String,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let folder = config.sent_folder_alias()?;
|
let folder = config.sent_folder_alias()?;
|
||||||
let email = Tpl::from(if atty::is(Stream::Stdin) || printer.is_json() {
|
|
||||||
|
let mml = if atty::is(Stream::Stdin) || printer.is_json() {
|
||||||
tpl.replace("\r", "")
|
tpl.replace("\r", "")
|
||||||
} else {
|
} else {
|
||||||
stdin()
|
stdin()
|
||||||
|
@ -114,11 +118,13 @@ pub async fn send<P: Printer>(
|
||||||
.filter_map(Result::ok)
|
.filter_map(Result::ok)
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join("\n")
|
.join("\n")
|
||||||
})
|
};
|
||||||
.with_pgp(config.pgp.clone())
|
|
||||||
.compile()
|
let email = MmlCompiler::new()
|
||||||
.await?
|
.with_pgp(config.pgp.clone())
|
||||||
.write_to_vec()?;
|
.compile(mml)
|
||||||
|
.await?
|
||||||
|
.write_to_vec()?;
|
||||||
|
|
||||||
sender.send(&email).await?;
|
sender.send(&email).await?;
|
||||||
|
|
||||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -1,13 +1,13 @@
|
||||||
use anyhow::{anyhow, Context, Result};
|
|
||||||
use clap::Command;
|
|
||||||
use log::{debug, warn};
|
|
||||||
#[cfg(feature = "imap-backend")]
|
#[cfg(feature = "imap-backend")]
|
||||||
use pimalaya_email::backend::ImapBackend;
|
use ::email::backend::ImapBackend;
|
||||||
use pimalaya_email::{
|
use ::email::{
|
||||||
account::{sync::AccountSyncBuilder, DEFAULT_INBOX_FOLDER},
|
account::{sync::AccountSyncBuilder, DEFAULT_INBOX_FOLDER},
|
||||||
backend::{BackendBuilder, BackendConfig},
|
backend::{BackendBuilder, BackendConfig},
|
||||||
sender::SenderBuilder,
|
sender::SenderBuilder,
|
||||||
};
|
};
|
||||||
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
use clap::Command;
|
||||||
|
use log::{debug, warn};
|
||||||
use std::env;
|
use std::env;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use pimalaya_email::email::Tpl;
|
|
||||||
|
|
||||||
use crate::printer::WriteColor;
|
use crate::printer::WriteColor;
|
||||||
|
|
||||||
|
@ -20,10 +19,3 @@ impl Print for String {
|
||||||
Ok(writer.reset()?)
|
Ok(writer.reset()?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Print for Tpl {
|
|
||||||
fn print(&self, writer: &mut dyn WriteColor) -> Result<()> {
|
|
||||||
self.as_str().print(writer)?;
|
|
||||||
Ok(writer.reset()?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use pimalaya_email::email::EmailTextPlainFormat;
|
use email::email::EmailTextPlainFormat;
|
||||||
use std::io;
|
use std::io;
|
||||||
use termcolor::{self, StandardStream};
|
use termcolor::{self, StandardStream};
|
||||||
|
|
||||||
|
|
|
@ -1,42 +1,45 @@
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use log::debug;
|
use email::{
|
||||||
use pimalaya_email::{
|
|
||||||
account::AccountConfig,
|
account::AccountConfig,
|
||||||
backend::Backend,
|
backend::Backend,
|
||||||
email::{local_draft_path, remove_local_draft, Flag, Flags, Tpl},
|
email::{local_draft_path, remove_local_draft, Flag, Flags},
|
||||||
sender::Sender,
|
sender::Sender,
|
||||||
};
|
};
|
||||||
use std::{env, fs, process::Command};
|
use log::debug;
|
||||||
|
use mml::MmlCompiler;
|
||||||
|
use process::Cmd;
|
||||||
|
use std::{env, fs};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
printer::Printer,
|
printer::Printer,
|
||||||
ui::choice::{self, PostEditChoice, PreEditChoice},
|
ui::choice::{self, PostEditChoice, PreEditChoice},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn open_with_tpl(tpl: Tpl) -> Result<Tpl> {
|
pub async fn open_with_tpl(tpl: String) -> Result<String> {
|
||||||
let path = local_draft_path();
|
let path = local_draft_path();
|
||||||
|
|
||||||
debug!("create draft");
|
debug!("create draft");
|
||||||
fs::write(&path, tpl.as_bytes()).context(format!("cannot write local draft at {:?}", path))?;
|
fs::write(&path, tpl.as_bytes()).context(format!("cannot write local draft at {:?}", path))?;
|
||||||
|
|
||||||
debug!("open editor");
|
debug!("open editor");
|
||||||
Command::new(env::var("EDITOR").context(r#"cannot find "$EDITOR" env var"#)?)
|
let editor = env::var("EDITOR").context("cannot get editor from env var")?;
|
||||||
.arg(&path)
|
Cmd::from(format!("{editor} {}", &path.to_string_lossy()))
|
||||||
.status()
|
.run()
|
||||||
|
.await
|
||||||
.context("cannot launch editor")?;
|
.context("cannot launch editor")?;
|
||||||
|
|
||||||
debug!("read draft");
|
debug!("read draft");
|
||||||
let content =
|
let content =
|
||||||
fs::read_to_string(&path).context(format!("cannot read local draft at {:?}", path))?;
|
fs::read_to_string(&path).context(format!("cannot read local draft at {:?}", path))?;
|
||||||
|
|
||||||
Ok(Tpl::from(content))
|
Ok(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_with_local_draft() -> Result<Tpl> {
|
pub async fn open_with_local_draft() -> Result<String> {
|
||||||
let path = local_draft_path();
|
let path = local_draft_path();
|
||||||
let content =
|
let content =
|
||||||
fs::read_to_string(&path).context(format!("cannot read local draft at {:?}", path))?;
|
fs::read_to_string(&path).context(format!("cannot read local draft at {:?}", path))?;
|
||||||
open_with_tpl(Tpl::from(content))
|
open_with_tpl(content).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn edit_tpl_with_editor<P: Printer>(
|
pub async fn edit_tpl_with_editor<P: Printer>(
|
||||||
|
@ -44,7 +47,7 @@ pub async fn edit_tpl_with_editor<P: Printer>(
|
||||||
printer: &mut P,
|
printer: &mut P,
|
||||||
backend: &mut dyn Backend,
|
backend: &mut dyn Backend,
|
||||||
sender: &mut dyn Sender,
|
sender: &mut dyn Sender,
|
||||||
mut tpl: Tpl,
|
mut tpl: String,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let draft = local_draft_path();
|
let draft = local_draft_path();
|
||||||
if draft.exists() {
|
if draft.exists() {
|
||||||
|
@ -52,11 +55,11 @@ pub async fn edit_tpl_with_editor<P: Printer>(
|
||||||
match choice::pre_edit() {
|
match choice::pre_edit() {
|
||||||
Ok(choice) => match choice {
|
Ok(choice) => match choice {
|
||||||
PreEditChoice::Edit => {
|
PreEditChoice::Edit => {
|
||||||
tpl = open_with_local_draft()?;
|
tpl = open_with_local_draft().await?;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
PreEditChoice::Discard => {
|
PreEditChoice::Discard => {
|
||||||
tpl = open_with_tpl(tpl)?;
|
tpl = open_with_tpl(tpl).await?;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
PreEditChoice::Quit => return Ok(()),
|
PreEditChoice::Quit => return Ok(()),
|
||||||
|
@ -68,16 +71,16 @@ pub async fn edit_tpl_with_editor<P: Printer>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tpl = open_with_tpl(tpl)?;
|
tpl = open_with_tpl(tpl).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match choice::post_edit() {
|
match choice::post_edit() {
|
||||||
Ok(PostEditChoice::Send) => {
|
Ok(PostEditChoice::Send) => {
|
||||||
printer.print_log("Sending email…")?;
|
printer.print_log("Sending email…")?;
|
||||||
let email = tpl
|
let email = MmlCompiler::new()
|
||||||
.with_pgp(config.pgp.clone())
|
.with_pgp(config.pgp.clone())
|
||||||
.compile()
|
.compile(tpl)
|
||||||
.await?
|
.await?
|
||||||
.write_to_vec()?;
|
.write_to_vec()?;
|
||||||
sender.send(&email).await?;
|
sender.send(&email).await?;
|
||||||
|
@ -93,7 +96,7 @@ pub async fn edit_tpl_with_editor<P: Printer>(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ok(PostEditChoice::Edit) => {
|
Ok(PostEditChoice::Edit) => {
|
||||||
tpl = open_with_tpl(tpl)?;
|
tpl = open_with_tpl(tpl).await?;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Ok(PostEditChoice::LocalDraft) => {
|
Ok(PostEditChoice::LocalDraft) => {
|
||||||
|
@ -101,9 +104,9 @@ pub async fn edit_tpl_with_editor<P: Printer>(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ok(PostEditChoice::RemoteDraft) => {
|
Ok(PostEditChoice::RemoteDraft) => {
|
||||||
let email = tpl
|
let email = MmlCompiler::new()
|
||||||
.with_pgp(config.pgp.clone())
|
.with_pgp(config.pgp.clone())
|
||||||
.compile()
|
.compile(tpl)
|
||||||
.await?
|
.await?
|
||||||
.write_to_vec()?;
|
.write_to_vec()?;
|
||||||
backend
|
backend
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
//! [builder design pattern]: https://refactoring.guru/design-patterns/builder
|
//! [builder design pattern]: https://refactoring.guru/design-patterns/builder
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
use email::email::EmailTextPlainFormat;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use pimalaya_email::email::EmailTextPlainFormat;
|
|
||||||
use termcolor::{Color, ColorSpec};
|
use termcolor::{Color, ColorSpec};
|
||||||
use terminal_size::terminal_size;
|
use terminal_size::terminal_size;
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
@ -267,7 +267,7 @@ where
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use pimalaya_email::email::EmailTextPlainFormat;
|
use email::email::EmailTextPlainFormat;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
Loading…
Reference in a new issue