mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-21 18:40:19 +00:00
implement add attachement to msg feature
This commit is contained in:
parent
cd48879dc3
commit
2850ae01fd
5 changed files with 294 additions and 88 deletions
|
@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Move feature [#31]
|
||||
- Delete feature [#36]
|
||||
- Signature support [#33]
|
||||
- Add attachment(s) to a message [#37]
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -92,6 +93,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
[#33]: https://github.com/soywod/himalaya/issues/33
|
||||
[#34]: https://github.com/soywod/himalaya/issues/34
|
||||
[#35]: https://github.com/soywod/himalaya/issues/35
|
||||
[#37]: https://github.com/soywod/himalaya/issues/37
|
||||
[#38]: https://github.com/soywod/himalaya/issues/38
|
||||
[#39]: https://github.com/soywod/himalaya/issues/39
|
||||
[#40]: https://github.com/soywod/himalaya/issues/40
|
||||
|
|
199
Cargo.lock
generated
199
Cargo.lock
generated
|
@ -21,7 +21,7 @@ version = "0.7.15"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"memchr 2.3.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -183,6 +183,15 @@ dependencies = [
|
|||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.1"
|
||||
|
@ -218,6 +227,12 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
|
@ -256,12 +271,29 @@ dependencies = [
|
|||
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.17"
|
||||
|
@ -286,6 +318,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"terminal_size",
|
||||
"toml",
|
||||
"tree_magic",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
|
@ -377,6 +410,16 @@ dependencies = [
|
|||
"nom 5.1.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.9"
|
||||
|
@ -406,9 +449,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "lettre"
|
||||
version = "0.10.0-alpha.4"
|
||||
version = "0.10.0-beta.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc8c2fc7873920aca23647e5e86d44ff3f40bbc5a5efaab445c9eb0e001c9f71"
|
||||
checksum = "897171ed0e63da84c988b157106ad8b6532d7499aeeec906ce46b05415cc79d3"
|
||||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"hostname",
|
||||
|
@ -420,10 +463,8 @@ dependencies = [
|
|||
"once_cell",
|
||||
"quoted_printable",
|
||||
"r2d2",
|
||||
"rand",
|
||||
"rand 0.8.3",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
|
@ -446,6 +487,15 @@ version = "0.2.88"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.2"
|
||||
|
@ -487,6 +537,15 @@ version = "0.1.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.4"
|
||||
|
@ -527,6 +586,15 @@ dependencies = [
|
|||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "3.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b"
|
||||
dependencies = [
|
||||
"memchr 1.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "5.1.2"
|
||||
|
@ -534,7 +602,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
|
||||
dependencies = [
|
||||
"lexical-core",
|
||||
"memchr",
|
||||
"memchr 2.3.4",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
|
@ -545,7 +613,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "88034cfd6b4a0d54dd14f4a507eceee36c0b70e5a02236c4e4df571102be17f0"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"memchr",
|
||||
"memchr 2.3.4",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
|
@ -613,6 +681,16 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e"
|
||||
dependencies = [
|
||||
"lock_api 0.3.4",
|
||||
"parking_lot_core 0.7.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.1"
|
||||
|
@ -620,8 +698,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
"lock_api 0.4.2",
|
||||
"parking_lot_core 0.8.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"cloudabi",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -644,6 +736,16 @@ version = "2.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.19"
|
||||
|
@ -687,7 +789,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "545c5bc2b880973c9c10e4067418407a0ccaa3091781d1671d46eb35107cb26f"
|
||||
dependencies = [
|
||||
"log",
|
||||
"parking_lot",
|
||||
"parking_lot 0.11.1",
|
||||
"scheduled-thread-pool",
|
||||
]
|
||||
|
||||
|
@ -703,11 +805,23 @@ version = "0.7.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.1.15",
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
"rand_chacha 0.2.2",
|
||||
"rand_core 0.5.1",
|
||||
"rand_hc 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha 0.3.0",
|
||||
"rand_core 0.6.2",
|
||||
"rand_hc 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -717,7 +831,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.6.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -726,7 +850,16 @@ version = "0.5.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.1.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
|
||||
dependencies = [
|
||||
"getrandom 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -735,7 +868,16 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
|
||||
dependencies = [
|
||||
"rand_core 0.6.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -751,7 +893,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"memchr 2.3.4",
|
||||
"regex-syntax",
|
||||
"thread_local",
|
||||
]
|
||||
|
@ -810,7 +952,7 @@ version = "0.2.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc6f74fd1204073fa02d5d5d68bec8021be4c38690b61264b2fdb48083d0e7d7"
|
||||
dependencies = [
|
||||
"parking_lot",
|
||||
"parking_lot 0.11.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -916,7 +1058,7 @@ checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
|||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"libc",
|
||||
"rand",
|
||||
"rand 0.7.3",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
|
@ -985,6 +1127,19 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree_magic"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1d99367ce3e553a84738f73bd626ccca541ef90ae757fdcdc4cbe728e6cb629"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"lazy_static",
|
||||
"nom 3.2.1",
|
||||
"parking_lot 0.10.2",
|
||||
"petgraph",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
|
@ -1030,7 +1185,7 @@ version = "0.8.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11"
|
||||
dependencies = [
|
||||
"rand",
|
||||
"rand 0.7.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -9,7 +9,7 @@ edition = "2018"
|
|||
clap = "2.33.3"
|
||||
error-chain = "0.12.4"
|
||||
imap = "2.4.0"
|
||||
lettre = "0.10.0-alpha.4"
|
||||
lettre = "0.10.0-beta.3"
|
||||
mailparse = "0.13.1"
|
||||
native-tls = "0.2"
|
||||
rfc2047-decoder = "0.1.2"
|
||||
|
@ -17,4 +17,5 @@ serde = { version = "1.0.118", features = ["derive"] }
|
|||
serde_json = "1.0.61"
|
||||
terminal_size = "0.1.15"
|
||||
toml = "0.5.8"
|
||||
tree_magic = "0.2.3"
|
||||
uuid = { version = "0.8", features = ["v4"] }
|
||||
|
|
|
@ -56,6 +56,16 @@ fn page_arg<'a>() -> Arg<'a, 'a> {
|
|||
.default_value("0")
|
||||
}
|
||||
|
||||
fn attachment_arg<'a>() -> Arg<'a, 'a> {
|
||||
Arg::with_name("attachments")
|
||||
.help("Adds attachment to the message")
|
||||
.short("a")
|
||||
.long("attachment")
|
||||
.value_name("PATH")
|
||||
.multiple(true)
|
||||
.takes_value(true)
|
||||
}
|
||||
|
||||
pub fn msg_subcmds<'a>() -> Vec<App<'a, 'a>> {
|
||||
vec![
|
||||
SubCommand::with_name("list")
|
||||
|
@ -75,7 +85,9 @@ pub fn msg_subcmds<'a>() -> Vec<App<'a, 'a>> {
|
|||
.multiple(true)
|
||||
.required(true),
|
||||
),
|
||||
SubCommand::with_name("write").about("Writes a new message"),
|
||||
SubCommand::with_name("write")
|
||||
.about("Writes a new message")
|
||||
.arg(attachment_arg()),
|
||||
SubCommand::with_name("send")
|
||||
.about("Sends a raw message")
|
||||
.arg(Arg::with_name("message").raw(true)),
|
||||
|
@ -247,10 +259,16 @@ pub fn msg_matches(matches: &ArgMatches) -> Result<()> {
|
|||
break;
|
||||
}
|
||||
|
||||
if let Some(_) = matches.subcommand_matches("write") {
|
||||
if let Some(matches) = matches.subcommand_matches("write") {
|
||||
let attachments = matches
|
||||
.values_of("attachments")
|
||||
.unwrap_or_default()
|
||||
.map(String::from)
|
||||
.collect::<Vec<_>>();
|
||||
let tpl = Msg::build_new_tpl(&config, &account)?;
|
||||
let content = input::open_editor_with_tpl(tpl.to_string().as_bytes())?;
|
||||
let mut msg = Msg::from(content);
|
||||
msg.attachments = attachments;
|
||||
|
||||
loop {
|
||||
match input::post_edit_choice() {
|
||||
|
@ -317,6 +335,11 @@ pub fn msg_matches(matches: &ArgMatches) -> Result<()> {
|
|||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("reply") {
|
||||
let attachments = matches
|
||||
.values_of("attachments")
|
||||
.unwrap_or_default()
|
||||
.map(String::from)
|
||||
.collect::<Vec<_>>();
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
|
||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
||||
|
@ -328,6 +351,7 @@ pub fn msg_matches(matches: &ArgMatches) -> Result<()> {
|
|||
|
||||
let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?;
|
||||
let mut msg = Msg::from(content);
|
||||
msg.attachments = attachments;
|
||||
|
||||
loop {
|
||||
match input::post_edit_choice() {
|
||||
|
@ -360,12 +384,18 @@ pub fn msg_matches(matches: &ArgMatches) -> Result<()> {
|
|||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("forward") {
|
||||
let attachments = matches
|
||||
.values_of("attachments")
|
||||
.unwrap_or_default()
|
||||
.map(String::from)
|
||||
.collect::<Vec<_>>();
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
|
||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
||||
let tpl = msg.build_forward_tpl(&config, &account)?;
|
||||
let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?;
|
||||
let mut msg = Msg::from(content);
|
||||
msg.attachments = attachments;
|
||||
|
||||
loop {
|
||||
match input::post_edit_choice() {
|
||||
|
|
144
src/msg/model.rs
144
src/msg/model.rs
|
@ -6,7 +6,8 @@ use serde::{
|
|||
ser::{self, SerializeStruct},
|
||||
Serialize,
|
||||
};
|
||||
use std::{fmt, result};
|
||||
use std::{borrow::Cow, fmt, fs, path::PathBuf, result};
|
||||
use tree_magic;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::config::model::{Account, Config};
|
||||
|
@ -171,25 +172,6 @@ impl<'a> ReadableMsg {
|
|||
|
||||
// Message
|
||||
|
||||
// #[derive(Debug, Serialize, PartialEq)]
|
||||
// #[serde(rename_all = "lowercase")]
|
||||
// pub enum Flag {
|
||||
// Seen,
|
||||
// Answered,
|
||||
// Flagged,
|
||||
// }
|
||||
|
||||
// impl Flag {
|
||||
// fn from_imap_flag(flag: &imap::types::Flag<'_>) -> Option<Self> {
|
||||
// match flag {
|
||||
// imap::types::Flag::Seen => Some(Self::Seen),
|
||||
// imap::types::Flag::Answered => Some(Self::Answered),
|
||||
// imap::types::Flag::Flagged => Some(Self::Flagged),
|
||||
// _ => None,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Msg<'m> {
|
||||
pub uid: u32,
|
||||
|
@ -197,7 +179,8 @@ pub struct Msg<'m> {
|
|||
pub subject: String,
|
||||
pub sender: String,
|
||||
pub date: String,
|
||||
|
||||
#[serde(skip_serializing)]
|
||||
pub attachments: Vec<String>,
|
||||
#[serde(skip_serializing)]
|
||||
raw: Vec<u8>,
|
||||
}
|
||||
|
@ -210,6 +193,7 @@ impl<'m> From<Vec<u8>> for Msg<'m> {
|
|||
subject: String::from(""),
|
||||
sender: String::from(""),
|
||||
date: String::from(""),
|
||||
attachments: vec![],
|
||||
raw,
|
||||
}
|
||||
}
|
||||
|
@ -242,6 +226,7 @@ impl<'m> From<&'m imap::types::Fetch> for Msg<'m> {
|
|||
.internal_date()
|
||||
.map(|date| date.naive_local().to_string())
|
||||
.unwrap_or_default(),
|
||||
attachments: vec![],
|
||||
raw: fetch.body().unwrap_or_default().to_vec(),
|
||||
},
|
||||
}
|
||||
|
@ -263,52 +248,85 @@ impl<'m> Msg<'m> {
|
|||
}
|
||||
|
||||
pub fn to_sendable_msg(&self) -> Result<lettre::Message> {
|
||||
use lettre::message::header::{ContentTransferEncoding, ContentType};
|
||||
use lettre::message::{Message, SinglePart};
|
||||
use lettre::message::{
|
||||
header::*,
|
||||
{Body, Message, MultiPart, SinglePart},
|
||||
};
|
||||
|
||||
let parsed = self.parse()?;
|
||||
let msg = parsed
|
||||
.headers
|
||||
.iter()
|
||||
.fold(Message::builder(), |msg, h| {
|
||||
let value = String::from_utf8(h.get_value_raw().to_vec())
|
||||
.unwrap()
|
||||
.replace("\r", "");
|
||||
let msg_builder = parsed.headers.iter().fold(Message::builder(), |msg, h| {
|
||||
let value = String::from_utf8(h.get_value_raw().to_vec())
|
||||
.unwrap()
|
||||
.replace("\r", "");
|
||||
|
||||
match h.get_key().to_lowercase().as_str() {
|
||||
"in-reply-to" => msg.in_reply_to(value.parse().unwrap()),
|
||||
"from" => match value.parse() {
|
||||
Ok(addr) => msg.from(addr),
|
||||
match h.get_key().to_lowercase().as_str() {
|
||||
"in-reply-to" => msg.in_reply_to(value.parse().unwrap()),
|
||||
"from" => match value.parse() {
|
||||
Ok(addr) => msg.from(addr),
|
||||
Err(_) => msg,
|
||||
},
|
||||
"to" => value
|
||||
.split(",")
|
||||
.fold(msg, |msg, addr| match addr.trim().parse() {
|
||||
Ok(addr) => msg.to(addr),
|
||||
Err(_) => msg,
|
||||
},
|
||||
"to" => value
|
||||
.split(",")
|
||||
.fold(msg, |msg, addr| match addr.trim().parse() {
|
||||
Ok(addr) => msg.to(addr),
|
||||
Err(_) => msg,
|
||||
}),
|
||||
"cc" => value
|
||||
.split(",")
|
||||
.fold(msg, |msg, addr| match addr.trim().parse() {
|
||||
Ok(addr) => msg.cc(addr),
|
||||
Err(_) => msg,
|
||||
}),
|
||||
"bcc" => value
|
||||
.split(",")
|
||||
.fold(msg, |msg, addr| match addr.trim().parse() {
|
||||
Ok(addr) => msg.bcc(addr),
|
||||
Err(_) => msg,
|
||||
}),
|
||||
"subject" => msg.subject(value),
|
||||
_ => msg,
|
||||
}
|
||||
})
|
||||
.singlepart(
|
||||
SinglePart::builder()
|
||||
.header(ContentType("text/plain; charset=utf-8".parse().unwrap()))
|
||||
.header(ContentTransferEncoding::Base64)
|
||||
.body(parsed.get_body_raw()?),
|
||||
)?;
|
||||
}),
|
||||
"cc" => value
|
||||
.split(",")
|
||||
.fold(msg, |msg, addr| match addr.trim().parse() {
|
||||
Ok(addr) => msg.cc(addr),
|
||||
Err(_) => msg,
|
||||
}),
|
||||
"bcc" => value
|
||||
.split(",")
|
||||
.fold(msg, |msg, addr| match addr.trim().parse() {
|
||||
Ok(addr) => msg.bcc(addr),
|
||||
Err(_) => msg,
|
||||
}),
|
||||
"subject" => msg.subject(value),
|
||||
_ => msg,
|
||||
}
|
||||
});
|
||||
|
||||
let text_part = SinglePart::builder()
|
||||
.header(ContentType("text/plain; charset=utf-8".parse().unwrap()))
|
||||
.header(ContentTransferEncoding::Base64)
|
||||
.body(parsed.get_body_raw()?);
|
||||
|
||||
let msg = if self.attachments.is_empty() {
|
||||
msg_builder.singlepart(text_part)
|
||||
} else {
|
||||
let mut parts = MultiPart::mixed().singlepart(text_part);
|
||||
|
||||
for attachment in &self.attachments {
|
||||
let attachment_name = PathBuf::from(attachment);
|
||||
let attachment_name = attachment_name
|
||||
.file_name()
|
||||
.map(|fname| fname.to_string_lossy())
|
||||
.unwrap_or(Cow::from(Uuid::new_v4().to_string()));
|
||||
let attachment_content = fs::read(attachment)
|
||||
.chain_err(|| format!("Cannot read attachment `{}`", attachment))?;
|
||||
let attachment_ctype = tree_magic::from_u8(&attachment_content);
|
||||
|
||||
parts = parts.singlepart(
|
||||
SinglePart::builder()
|
||||
.header(ContentType(attachment_ctype.parse().chain_err(|| {
|
||||
format!("Could not parse content type `{}`", attachment_ctype)
|
||||
})?))
|
||||
.header(ContentDisposition {
|
||||
disposition: DispositionType::Attachment,
|
||||
parameters: vec![DispositionParam::Filename(
|
||||
Charset::Ext("utf-8".into()),
|
||||
None,
|
||||
attachment_name.as_bytes().into(),
|
||||
)],
|
||||
})
|
||||
.body(Body::new(attachment_content)),
|
||||
);
|
||||
}
|
||||
|
||||
msg_builder.multipart(parts)
|
||||
}?;
|
||||
|
||||
Ok(msg)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue