extern crate dirs;
extern crate tempfile;
extern crate notmuch;
extern crate gethostname;
extern crate maildir;
extern crate lettre;
extern crate lettre_email;
use std::ffi::OsStr;
use std::io::{Result, Write};
use std::fs::{self, File};
use std::path::PathBuf;
use tempfile::{tempdir, TempDir};
use std::process::Command;
use maildir::Maildir;
use lettre_email::{EmailBuilder, Header};
use lettre::SendableEmail;
pub struct MailBox {
root_dir: TempDir,
maildir: Maildir
}
impl MailBox {
pub fn new() -> Self {
let root_dir = tempdir().unwrap();
let root_path = root_dir.path().to_path_buf();
let tmp_path = root_path.join("tmp");
fs::create_dir(&tmp_path).unwrap();
let cfg_fname = root_path.join("notmuch-config");
let mut cfg_file = File::create(cfg_fname).unwrap();
write!(
cfg_file,
r#"
[database]
path={tmppath}
hook_dir={tmppath}/hooks
[user]
name=Some Hacker
primary_email=dst@example.com
[new]
tags=unread;inbox;
ignore=
[search]
exclude_tags=deleted;spam;
[maildir]
synchronize_flags=true
[crypto]
gpg_path=gpg
"#,
tmppath = root_path.to_string_lossy()
)
.unwrap();
let maildir = Maildir::from(root_path.to_path_buf());
maildir.create_dirs().unwrap();
std::fs::create_dir(root_path.join("hooks")).unwrap();
Self { root_dir, maildir }
}
pub fn path(&self) -> PathBuf {
self.root_dir.path().into()
}
pub fn deliver(&self,
subject: Option<String>,
body: Option<String>,
to: Option<String>,
from: Option<String>,
headers: Vec<(String, String)>,
is_new: bool, _keywords: Option<Vec<String>>, seen: bool, replied: bool, flagged: bool) -> Result<(String, PathBuf)>
{
let mut builder = EmailBuilder::new()
.subject(subject.unwrap_or_else(|| "Test mail".to_string()));
if let Some(val) = body {
builder = builder.text(val);
}
builder = builder.to(to.unwrap_or_else(|| "to@example.com".to_string()))
.from(from.unwrap_or_else(|| "src@example.com".to_string()));
for h in headers.into_iter(){
let hdr: Header = h.into();
builder = builder.header(hdr);
}
let msg:SendableEmail = builder.build().unwrap().into();
let msg_id = msg.message_id().to_string() + ".lettre@localhost";
let id = if is_new {
self.maildir.store_new(&msg.message_to_string().unwrap().as_bytes()).unwrap()
}else{
let mut flags = String::from("");
if flagged {
flags += "F";
}
if replied {
flags += "R";
}
if seen {
flags += "S";
}
println!("flags: {:?}", flags);
let mid = self.maildir.store_cur_with_flags(&msg.message_to_string().unwrap().as_bytes(), flags.as_str()).unwrap();
format!("{}:2,{}", mid, flags)
};
let mut msgpath = self.path();
msgpath = if is_new {
msgpath.join("new")
} else {
msgpath.join("cur")
};
msgpath = msgpath.join(&id);
Ok((msg_id, msgpath))
}
}
impl Drop for MailBox {
fn drop(&mut self) {
}
}
#[derive(Clone, Debug)]
pub struct NotmuchCommand {
maildir_path: PathBuf
}
impl NotmuchCommand {
pub fn new(maildir_path: &PathBuf) -> Self {
Self {
maildir_path: maildir_path.clone()
}
}
pub fn run<I, S>(&self, args: I) -> Result<()>
where
I: IntoIterator<Item=S>,
S: AsRef<OsStr>
{
let cfg_fname = self.maildir_path.join("notmuch-config");
Command::new("notmuch")
.env("NOTMUCH_CONFIG", &cfg_fname)
.env_remove("NOTMUCH_DATABASE")
.env_remove("NOTMUCH_PROFILE")
.env_remove("MAILDIR")
.args(args)
.status()?;
Ok(())
}
}