1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
mod error;
mod stream;
pub use self::{error::*, stream::*};
use crate::{Envelope, SyncFuture, Transport};
use async_std::{
fs::{create_dir_all, rename, File},
io::prelude::WriteExt,
path::Path,
};
use std::path::PathBuf;
#[derive(Debug)]
#[cfg_attr(
feature = "serde-impls",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub struct FileTransport {
path: PathBuf,
}
impl FileTransport {
pub fn new<P: AsRef<Path>>(path: P) -> FileTransport {
FileTransport {
path: PathBuf::from(path.as_ref()),
}
}
}
impl Transport for FileTransport {
type DataStream = MailFile;
fn send_stream<'s, 'a>(&'s self, envelope: Envelope) -> SyncFuture<'a, Result<MailFile, Error>>
where
's: 'a,
{
let id = envelope.message_id().to_owned();
let dir = self.path.clone();
let mut headers = String::new();
if let Some(sender) = envelope.from() {
headers += format!("X-Samotop-From: {}\r\n", sender).as_str();
}
for rcpt in envelope.to() {
headers += format!("X-Samotop-To: {}\r\n", rcpt).as_str();
}
let target_dir = dir.join("new");
let tmp_dir = dir.join("tmp");
let target_file = target_dir.join(id.as_str());
let tmp_file = tmp_dir.join(id.as_str());
let target = Box::pin(rename(tmp_file.clone(), target_file));
Box::pin(async move {
ensure_dir(tmp_dir).await?;
ensure_dir(target_dir).await?;
let mut file = File::create(tmp_file).await?;
file.write_all(headers.as_bytes()).await?;
Ok(MailFile::new(id, file, target))
})
}
}
async fn ensure_dir<P: AsRef<Path>>(dir: P) -> std::io::Result<()> {
if !dir.as_ref().exists().await {
create_dir_all(dir).await
} else {
Ok(())
}
}