review flag command, remove lib + dead code

This commit is contained in:
Clément DOUIN 2021-09-19 14:24:00 +02:00
parent 71818e04b4
commit 65664d5405
No known key found for this signature in database
GPG key ID: 69C9B9CFFDEE2DEF
14 changed files with 168 additions and 412 deletions

View file

@ -77,96 +77,6 @@ impl Config {
Ok(path)
}
/// Returns the account by the given name.
/// If `name` is `None`, then the default account is returned.
pub fn find_account_by_name(&self, name: Option<&str>) -> Result<&ConfigAccountEntry> {
match name {
Some("") | None => self
.accounts
.iter()
.find(|(_, account)| account.default.unwrap_or(false))
.map(|(_, account)| account)
.ok_or_else(|| anyhow!("cannot find default account")),
Some(name) => self
.accounts
.get(name)
.ok_or_else(|| anyhow!("cannot find account `{}`", name)),
}
}
/// Returns the path to the given filename in the download directory.
/// You can imagine this as:
/// ```skip
/// Account-specifique-download-dir-path + Attachment-Filename
/// ```
pub fn downloads_filepath(&self, account: &ConfigAccountEntry, filename: &str) -> PathBuf {
account
.downloads_dir
.as_ref()
.and_then(|dir| dir.to_str())
.and_then(|dir| shellexpand::full(dir).ok())
.map(|dir| PathBuf::from(dir.to_string()))
.unwrap_or(
self.downloads_dir
.as_ref()
.and_then(|dir| dir.to_str())
.and_then(|dir| shellexpand::full(dir).ok())
.map(|dir| PathBuf::from(dir.to_string()))
.unwrap_or(env::temp_dir()),
)
.join(filename)
}
/// This is a little helper-function like which uses the the name and email
/// of the account to create a valid address for the header of the headers
/// of a msg.
///
/// # Hint
/// If the name includes some special characters like a whitespace, comma or semicolon, then
/// the name will be automatically wrapped between two `"`.
///
/// # Exapmle
/// ```
/// use himalaya::config::model::{Account, Config};
///
/// fn main() {
/// let config = Config::default();
///
/// let normal_account = Account::new(Some("Acc1"), "acc1@mail.com");
/// // notice the semicolon in the name!
/// let special_account = Account::new(Some("TL;DR"), "acc2@mail.com");
///
/// // -- Expeced outputs --
/// let expected_normal = Account {
/// name: Some("Acc1".to_string()),
/// email: "acc1@mail.com".to_string(),
/// .. Account::default()
/// };
///
/// let expected_special = Account {
/// name: Some("\"TL;DR\"".to_string()),
/// email: "acc2@mail.com".to_string(),
/// .. Account::default()
/// };
///
/// assert_eq!(config.address(&normal_account), "Acc1 <acc1@mail.com>");
/// assert_eq!(config.address(&special_account), "\"TL;DR\" <acc2@mail.com>");
/// }
/// ```
pub fn address(&self, account: &ConfigAccountEntry) -> String {
let name = account.name.as_ref().unwrap_or(&self.name);
let has_special_chars = "()<>[]:;@.,".contains(|special_char| name.contains(special_char));
if name.is_empty() {
format!("{}", account.email)
} else if has_special_chars {
// so the name has special characters => Wrap it with '"'
format!("\"{}\" <{}>", name, account.email)
} else {
format!("{} <{}>", name, account.email)
}
}
pub fn run_notify_cmd<S: AsRef<str>>(&self, subject: S, sender: S) -> Result<()> {
let subject = subject.as_ref();
let sender = sender.as_ref();
@ -183,7 +93,7 @@ impl Config {
Ok(())
}
pub fn exec_watch_cmds(&self, account: &ConfigAccountEntry) -> Result<()> {
pub fn _exec_watch_cmds(&self, account: &ConfigAccountEntry) -> Result<()> {
let cmds = account
.watch_cmds
.as_ref()
@ -323,28 +233,6 @@ impl Account {
format!("{} <{}>", name, self.email)
}
}
/// Returns the imap-host address + the port usage of the account
///
/// # Example
/// ```rust
/// use himalaya::config::model::Account;
/// fn main () {
/// let account = Account {
/// imap_host: String::from("hostExample"),
/// imap_port: 42,
/// .. Account::default()
/// };
///
/// let expected_output = ("hostExample", 42);
///
/// assert_eq!(account.imap_addr(), expected_output);
/// }
/// ```
pub fn imap_addr(&self) -> (&str, u16) {
debug!("host: {}", self.imap_host);
debug!("port: {}", self.imap_port);
(&self.imap_host, self.imap_port)
}
/// Runs the given command in your password string and returns it.
pub fn imap_passwd(&self) -> Result<String> {
@ -364,83 +252,6 @@ impl Account {
Ok(SmtpCredentials::new(self.smtp_login.to_owned(), passwd))
}
/// Creates a new account with the given values and returns it. All other attributes of the
/// account are gonna be empty/None.
///
/// # Example
/// ```rust
/// use himalaya::config::model::Account;
///
/// fn main() {
/// let account1 = Account::new(Some("Name1"), "email@address.com");
/// let account2 = Account::new(None, "email@address.com");
///
/// let expected1 = Account {
/// name: Some("Name1".to_string()),
/// email: "email@address.com".to_string(),
/// .. Account::default()
/// };
///
/// let expected2 = Account {
/// email: "email@address.com".to_string(),
/// .. Account::default()
/// };
///
/// assert_eq!(account1, expected1);
/// assert_eq!(account2, expected2);
/// }
/// ```
pub fn new<S: ToString + Default>(name: Option<S>, email_addr: S) -> Self {
Self {
name: name.unwrap_or_default().to_string(),
email: email_addr.to_string(),
..Self::default()
}
}
/// Creates a new account with a custom signature. Passing `None` to `signature` sets the
/// signature to `Account Signature`.
///
/// # Examples
/// ```rust
/// use himalaya::config::model::Account;
///
/// fn main() {
///
/// // the testing accounts
/// let account_with_custom_signature = Account::new_with_signature(
/// Some("Email name"), "some@mail.com", Some("Custom signature! :)"));
/// let account_with_default_signature = Account::new_with_signature(
/// Some("Email name"), "some@mail.com", None);
///
/// // How they should look like
/// let account_cmp1 = Account {
/// name: Some("Email name".to_string()),
/// email: "some@mail.com".to_string(),
/// signature: Some("Custom signature! :)".to_string()),
/// .. Account::default()
/// };
///
/// let account_cmp2 = Account {
/// name: Some("Email name".to_string()),
/// email: "some@mail.com".to_string(),
/// .. Account::default()
/// };
///
/// assert_eq!(account_with_custom_signature, account_cmp1);
/// assert_eq!(account_with_default_signature, account_cmp2);
/// }
/// ```
pub fn new_with_signature<S: AsRef<str> + ToString + Default>(
name: Option<S>,
email_addr: S,
signature: Option<S>,
) -> Self {
let mut account = Account::new(name, email_addr);
account.signature = signature.unwrap_or_default().to_string();
account
}
}
impl<'a> TryFrom<(&'a Config, Option<&str>)> for Account {

View file

@ -33,9 +33,15 @@ pub trait ImapServiceInterface {
) -> Result<Option<ImapMsgs>>;
fn get_msg(&mut self, uid: &str) -> Result<Msg>;
fn append_msg(&mut self, mbox: &Mbox, msg: &mut Msg) -> Result<()>;
fn add_flags(&mut self, uid_seq: &str, flags: Flags) -> Result<()>;
fn set_flags(&mut self, uid_seq: &str, flags: Flags) -> Result<()>;
fn remove_flags(&mut self, uid_seq: &str, flags: Flags) -> Result<()>;
/// Add flags to the given message UID sequence.
///
/// ```ignore
/// let flags = Flags::from(vec![Flag::Seen, Flag::Deleted]);
/// add_flags("5:10", flags)
/// ```
fn add_flags(&mut self, uid_seq: &str, flags: &Flags) -> Result<()>;
fn set_flags(&mut self, uid_seq: &str, flags: &Flags) -> Result<()>;
fn remove_flags(&mut self, uid_seq: &str, flags: &Flags) -> Result<()>;
fn expunge(&mut self) -> Result<()>;
fn logout(&mut self) -> Result<()>;
}
@ -204,14 +210,7 @@ impl<'a> ImapServiceInterface for ImapService<'a> {
Ok(())
}
/// Add flags to the given message UID sequence.
///
/// ```ignore
///
/// let flags = Flags::from(vec![Flag::Seen, Flag::Deleted]);
/// imap.add_flags("5:10", flags)
/// ```
fn add_flags(&mut self, uid_seq: &str, flags: Flags) -> Result<()> {
fn add_flags(&mut self, uid_seq: &str, flags: &Flags) -> Result<()> {
let mbox = self.mbox.to_owned();
let flags: String = flags.to_string();
self.sess()?
@ -244,9 +243,8 @@ impl<'a> ImapServiceInterface for ImapService<'a> {
/// imap_conn.logout();
/// }
/// ```
fn set_flags(&mut self, uid_seq: &str, flags: Flags) -> Result<()> {
fn set_flags(&mut self, uid_seq: &str, flags: &Flags) -> Result<()> {
let mbox = self.mbox.to_owned();
let flags: String = flags.to_string();
self.sess()?
.select(&mbox.name)
.context(format!("cannot select mailbox `{}`", self.mbox.name))?;
@ -258,7 +256,7 @@ impl<'a> ImapServiceInterface for ImapService<'a> {
/// Remove the flags to the message by the given information. Take a look on the example above.
/// It's pretty similar.
fn remove_flags(&mut self, uid_seq: &str, flags: Flags) -> Result<()> {
fn remove_flags(&mut self, uid_seq: &str, flags: &Flags) -> Result<()> {
let mbox = self.mbox.to_owned();
let flags = flags.to_string();
self.sess()?

View file

@ -101,15 +101,6 @@ pub struct Mbox {
pub attributes: Attributes,
}
impl Mbox {
pub fn new<S: AsRef<str>>(name: S) -> Self {
Self {
name: name.as_ref().to_owned(),
..Self::default()
}
}
}
impl Default for Mbox {
fn default() -> Self {
Self {

View file

@ -183,7 +183,7 @@ pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Command<'a>>> {
return Ok(Some(Command::Tpl(msg::tpl::arg::matches(&m)?)));
}
if let Some(m) = m.subcommand_matches("flags") {
if let Some(m) = m.subcommand_matches("flag") {
return Ok(Some(Command::Flag(msg::flag::arg::matches(&m)?)));
}

View file

@ -20,31 +20,6 @@ pub struct Attachment {
}
impl Attachment {
/// Creates a new attachment.
///
/// # Example
/// ```
/// # use himalaya::msg::attachment::Attachment;
/// let attachment = Attachment::new(
/// "VIP Text",
/// "text/plain",
/// "Some very important text".as_bytes().to_vec());
///
/// ```
pub fn new(filename: &str, content_type: &str, body_raw: Vec<u8>) -> Self {
// Use the mime type `text/plain` per default
let content_type: ContentType = match content_type.parse() {
Ok(lettre_type) => lettre_type,
Err(_) => ContentType::TEXT_PLAIN,
};
Self {
filename: filename.to_string(),
content_type,
body_raw,
}
}
/// This from function extracts one attachment of a parsed msg.
/// If it couldn't create an attachment with the given parsed msg, than it will
/// return `None`.

View file

@ -65,54 +65,6 @@ impl Body {
html: None,
}
}
/// Returns a new instance of `Body` with `html` set.
///
/// # Example
/// ```rust
/// use himalaya::msg::body::Body;
///
/// fn main() {
/// let body = Body::new_with_html("Html body");
///
/// let expected_body = Body {
/// text: None,
/// html: Some("Html body".to_string()),
/// };
///
/// assert_eq!(body, expected_body);
/// }
/// ```
pub fn new_with_html<S: ToString>(html: S) -> Self {
Self {
plain: None,
html: Some(html.to_string()),
}
}
/// Returns a new isntance of `Body` with `text` and `html` set.
///
/// # Example
/// ```rust
/// use himalaya::msg::body::Body;
///
/// fn main() {
/// let body = Body::new_with_both("Text body", "Html body");
///
/// let expected_body = Body {
/// text: Some("Text body".to_string()),
/// html: Some("Html body".to_string()),
/// };
///
/// assert_eq!(body, expected_body);
/// }
/// ```
pub fn new_with_both<S: ToString>(text: S, html: S) -> Self {
Self {
plain: Some(text.to_string()),
html: Some(html.to_string()),
}
}
}
// == Traits ==

View file

@ -1,7 +1,15 @@
use anyhow::{anyhow, Context, Error, Result};
use imap::types::{Fetch, Flag, ZeroCopy};
use lettre::message::{
header::ContentType, Attachment as lettre_Attachment, Mailbox, Message, MultiPart, SinglePart,
};
use log::debug;
use mailparse;
use serde::Serialize;
use std::{
convert::{From, TryFrom},
fmt,
};
use crate::{
config::entity::Account,
@ -9,21 +17,10 @@ use crate::{
attachment::entity::Attachment, body::entity::Body, flag::entity::Flags,
header::entity::Headers,
},
ui::table::{Cell, Row, Table},
};
#[cfg(not(test))]
use crate::ui::editor;
use serde::Serialize;
use lettre::message::{
header::ContentType, Attachment as lettre_Attachment, Mailbox, Message, MultiPart, SinglePart,
};
use std::{
convert::{From, TryFrom},
fmt,
ui::{
editor,
table::{Cell, Row, Table},
},
};
/// Represents the msg in a serializeable form with additional values.
@ -425,7 +422,6 @@ impl Msg {
// We don't let this line compile, if we're doing
// tests, because we just need to look, if the headers are set
// correctly
#[cfg(not(test))]
let msg = editor::open_editor_with_tpl(msg.as_bytes())?;
// refresh the state of the msg
@ -716,14 +712,6 @@ impl Msg {
self.uid
}
/// It returns the raw version of the Message. In general it's the structure
/// how you get it if you get the data from the fetch. It's the output if
/// you read a message with the `--raw` flag like this: `himalaya read
/// --raw <UID>`.
pub fn get_raw(&self) -> Vec<u8> {
self.raw.clone()
}
/// Returns the raw mail as a string instead of a Vector of bytes.
pub fn get_raw_as_string(&self) -> Result<String> {
let raw_message = String::from_utf8(self.raw.clone())

View file

@ -9,7 +9,7 @@ use log::debug;
use crate::domain::msg;
type Uid<'a> = &'a str;
type Flags<'a> = &'a str;
type Flags<'a> = Vec<&'a str>;
/// Message flag commands.
pub enum Command<'a> {
@ -24,8 +24,8 @@ pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Command<'a>>> {
debug!("set command matched");
let uid = m.value_of("uid").unwrap();
debug!("uid: {}", uid);
let flags = m.value_of("flags").unwrap();
debug!("flags: {}", flags);
let flags: Vec<&str> = m.values_of("flags").unwrap_or_default().collect();
debug!("flags: `{:?}`", flags);
return Ok(Some(Command::Set(uid, flags)));
}
@ -33,8 +33,8 @@ pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Command<'a>>> {
debug!("add command matched");
let uid = m.value_of("uid").unwrap();
debug!("uid: {}", uid);
let flags = m.value_of("flags").unwrap();
debug!("flags: {}", flags);
let flags: Vec<&str> = m.values_of("flags").unwrap_or_default().collect();
debug!("flags: `{:?}`", flags);
return Ok(Some(Command::Add(uid, flags)));
}
@ -42,8 +42,8 @@ pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Command<'a>>> {
debug!("remove command matched");
let uid = m.value_of("uid").unwrap();
debug!("uid: {}", uid);
let flags = m.value_of("flags").unwrap();
debug!("flags: {}", flags);
let flags: Vec<&str> = m.values_of("flags").unwrap_or_default().collect();
debug!("flags: `{:?}`", flags);
return Ok(Some(Command::Remove(uid, flags)));
}
@ -53,7 +53,9 @@ pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Command<'a>>> {
/// Message flag flags argument.
fn flags_arg<'a>() -> Arg<'a, 'a> {
Arg::with_name("flags")
.help("IMAP flags (see https://tools.ietf.org/html/rfc3501#page-11). Just write the flag name without the backslash. Example: --flags \"Seen Answered\"")
.help(
"IMAP flags (they do not need to be prefixed with `\\` and they are case-insensitive)",
)
.value_name("FLAGS…")
.multiple(true)
.required(true)
@ -61,7 +63,8 @@ fn flags_arg<'a>() -> Arg<'a, 'a> {
/// Message flag subcommands.
pub fn subcmds<'a>() -> Vec<App<'a, 'a>> {
vec![SubCommand::with_name("flags")
vec![SubCommand::with_name("flag")
.aliases(&["flags", "flg"])
.about("Handles flags")
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(
@ -72,7 +75,7 @@ pub fn subcmds<'a>() -> Vec<App<'a, 'a>> {
)
.subcommand(
SubCommand::with_name("add")
.about("Appends flags to a message")
.about("Adds flags to a message")
.arg(msg::arg::uid_arg())
.arg(flags_arg()),
)

View file

@ -3,6 +3,7 @@ use serde::ser::{Serialize, SerializeSeq, Serializer};
use std::borrow::Cow;
use std::collections::HashSet;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::convert::From;
@ -70,27 +71,25 @@ impl Flags {
}
}
impl ToString for Flags {
fn to_string(&self) -> String {
let mut flags = String::new();
impl fmt::Display for Flags {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut glue = "";
for flag in &self.0 {
write!(f, "{}", glue)?;
match flag {
Flag::Seen => flags.push_str("\\Seen "),
Flag::Answered => flags.push_str("\\Answered "),
Flag::Flagged => flags.push_str("\\Flagged "),
Flag::Deleted => flags.push_str("\\Deleted "),
Flag::Draft => flags.push_str("\\Draft "),
Flag::Recent => flags.push_str("\\Recent "),
Flag::MayCreate => flags.push_str("\\MayCreate "),
Flag::Custom(cow) => flags.push_str(&format!("\\{} ", cow)),
_ => panic!("Unknown flag!"),
Flag::Seen => write!(f, "\\Seen")?,
Flag::Answered => write!(f, "\\Answered")?,
Flag::Flagged => write!(f, "\\Flagged")?,
Flag::Deleted => write!(f, "\\Deleted")?,
Flag::Draft => write!(f, "\\Draft")?,
Flag::Recent => write!(f, "\\Recent")?,
Flag::MayCreate => write!(f, "\\MayCreate")?,
Flag::Custom(cow) => write!(f, "{}", cow)?,
_ => (),
}
glue = " ";
}
// remove the trailing whitespaces
flags = flags.trim_end_matches(' ').to_string();
flags
Ok(())
}
}
@ -143,13 +142,14 @@ impl From<&str> for Flags {
for flag in flags.split_ascii_whitespace() {
match flag {
"Seen" => content.insert(Flag::Seen),
"Answered" => content.insert(Flag::Answered),
"Deleted" => content.insert(Flag::Flagged),
"Deleted" => content.insert(Flag::Deleted),
"Draft" => content.insert(Flag::Draft),
"Recent" => content.insert(Flag::Recent),
"Flagged" => content.insert(Flag::Flagged),
"MayCreate" => content.insert(Flag::MayCreate),
_other => content.insert(Flag::Custom(Cow::Owned(_other.to_string()))),
"Recent" => content.insert(Flag::Recent),
"Seen" => content.insert(Flag::Seen),
custom => content.insert(Flag::Custom(Cow::Owned(custom.to_string()))),
};
}
@ -157,6 +157,29 @@ impl From<&str> for Flags {
}
}
impl<'a> From<Vec<&'a str>> for Flags {
fn from(flags: Vec<&'a str>) -> Self {
let mut map: HashSet<Flag<'static>> = HashSet::new();
for f in flags {
match f {
"Answered" | _ if f.eq_ignore_ascii_case("answered") => map.insert(Flag::Answered),
"Deleted" | _ if f.eq_ignore_ascii_case("deleted") => map.insert(Flag::Deleted),
"Draft" | _ if f.eq_ignore_ascii_case("draft") => map.insert(Flag::Draft),
"Flagged" | _ if f.eq_ignore_ascii_case("flagged") => map.insert(Flag::Flagged),
"MayCreate" | _ if f.eq_ignore_ascii_case("maycreate") => {
map.insert(Flag::MayCreate)
}
"Recent" | _ if f.eq_ignore_ascii_case("recent") => map.insert(Flag::Recent),
"Seen" | _ if f.eq_ignore_ascii_case("seen") => map.insert(Flag::Seen),
custom => map.insert(Flag::Custom(Cow::Owned(custom.into()))),
};
}
Self(map)
}
}
impl Deref for Flags {
type Target = HashSet<Flag<'static>>;

View file

@ -1,36 +1,82 @@
//! Module related to message flag handling.
//!
//! This module gathers all message flag commands.
use anyhow::Result;
use crate::domain::{imap::service::ImapServiceInterface, msg::flag::entity::Flags};
use crate::{
domain::{imap::service::ImapServiceInterface, msg::flag::entity::Flags},
output::service::OutputServiceInterface,
};
pub fn set<ImapService: ImapServiceInterface>(
uid: &str,
flags: &str,
imap: &mut ImapService,
/// Add flags from the given message UID sequence.
/// Flags do not need to be prefixed with `\` and they are not case-sensitive.
///
/// ```ignore
/// add("21", "\\Seen", &output, &mut imap)?;
/// add("42", "recent", &output, &mut imap)?;
/// add("1:10", "Answered custom", &output, &mut imap)?;
/// ```
pub fn add<'a, OutputService: OutputServiceInterface, ImapService: ImapServiceInterface>(
uid: &'a str,
flags: Vec<&'a str>,
output: &'a OutputService,
imap: &'a mut ImapService,
) -> Result<()> {
let flags = Flags::from(flags);
imap.set_flags(uid, flags)?;
imap.add_flags(uid, &flags)?;
output.print(format!(
r#"Flag(s) "{}" successfully added to message {}"#,
flags, uid
))?;
imap.logout()?;
Ok(())
}
pub fn add<ImapService: ImapServiceInterface>(
uid: &str,
flags: &str,
imap: &mut ImapService,
/// Remove flags from the given message UID sequence.
/// Flags do not need to be prefixed with `\` and they are not case-sensitive.
///
/// ```ignore
/// remove("21", "\\Seen", &output, &mut imap)?;
/// remove("42", "recent", &output, &mut imap)?;
/// remove("1:10", "Answered custom", &output, &mut imap)?;
/// ```
pub fn remove<'a, OutputService: OutputServiceInterface, ImapService: ImapServiceInterface>(
uid: &'a str,
flags: Vec<&'a str>,
output: &'a OutputService,
imap: &'a mut ImapService,
) -> Result<()> {
let flags = Flags::from(flags);
imap.add_flags(uid, flags)?;
imap.remove_flags(uid, &flags)?;
output.print(format!(
r#"Flag(s) "{}" successfully removed from message {}"#,
flags, uid
))?;
imap.logout()?;
Ok(())
}
pub fn remove<ImapService: ImapServiceInterface>(
uid: &str,
flags: &str,
imap: &mut ImapService,
/// Replace flags from the given message UID sequence.
/// Flags do not need to be prefixed with `\` and they are not case-sensitive.
///
/// ```ignore
/// set("21", "\\Seen", &output, &mut imap)?;
/// set("42", "recent", &output, &mut imap)?;
/// set("1:10", "Answered custom", &output, &mut imap)?;
/// ```
pub fn set<'a, OutputService: OutputServiceInterface, ImapService: ImapServiceInterface>(
uid: &'a str,
flags: Vec<&'a str>,
output: &'a OutputService,
imap: &'a mut ImapService,
) -> Result<()> {
let flags = Flags::from(flags);
imap.remove_flags(uid, flags)?;
imap.set_flags(uid, &flags)?;
output.print(format!(
r#"Flag(s) "{}" successfully set for message {}"#,
flags, uid
))?;
imap.logout()?;
Ok(())
}

View file

@ -1,3 +1,7 @@
//! Module related to message handling.
//!
//! This module gathers all message commands.
use anyhow::{Context, Result};
use atty::Stream;
use imap::types::Flag;
@ -175,7 +179,7 @@ pub fn delete<OutputService: OutputServiceInterface, ImapService: ImapServiceInt
imap: &mut ImapService,
) -> Result<()> {
let flags = Flags::from(vec![Flag::Seen, Flag::Deleted]);
imap.add_flags(uid, flags)?;
imap.add_flags(uid, &flags)?;
imap.expunge()?;
output.print(format!("Message(s) {} successfully deleted", uid))?;
imap.logout()?;
@ -288,8 +292,8 @@ pub fn move_<ImapService: ImapServiceInterface>(
uid, target
))?;
// delete the msg in the old mailbox
let flags = vec![Flag::Seen, Flag::Deleted];
imap.add_flags(uid, Flags::from(flags))?;
let flags = Flags::from(vec![Flag::Seen, Flag::Deleted]);
imap.add_flags(uid, &flags)?;
imap.expunge()?;
imap.logout()?;
Ok(())

View file

@ -1,24 +0,0 @@
//! # Welcome to Himalaya!
//! Here's a little summary of how to read the code of himalaya:
//! Each module includes three "main" files:
//! - `model.rs`: **The "main" file** of each module which includes the main implementation of the given
//! module.
//! - `cli.rs`: Includes the subcommands and arguments which are related to the module.
//!
//! For example the `read` subcommand is in the `msg/cli.rs` file because it's related to the
//! msg you want to read.
//!
//! - `mod.rs`: Includes all other files in the module. Click [here] for more information.
//!
//! [here]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html
pub mod compl;
/// Everything which is related to the config files. For example the structure of your config file.
pub mod config;
/// Handles the output. For example the JSON and HTML output.
pub mod output;
pub mod domain;
pub mod ui;

View file

@ -4,20 +4,20 @@ use env_logger;
use std::{convert::TryFrom, env};
use url::Url;
use himalaya::{
compl,
config::{
self,
entity::{Account, Config},
},
domain::{
imap::{self, service::ImapService},
mbox::{self, entity::Mbox},
msg,
smtp::service::SmtpService,
},
output::{self, service::OutputService},
mod compl;
mod config;
mod domain;
mod output;
mod ui;
use config::entity::{Account, Config};
use domain::{
imap::{self, service::ImapService},
mbox::{self, entity::Mbox},
msg,
smtp::service::SmtpService,
};
use output::service::OutputService;
fn create_app<'a>() -> clap::App<'a, 'a> {
clap::App::new(env!("CARGO_PKG_NAME"))
@ -132,13 +132,13 @@ fn main() -> Result<()> {
Some(msg::arg::Command::Flag(m)) => match m {
Some(msg::flag::arg::Command::Set(uid, flags)) => {
return msg::flag::handler::set(uid, flags, &mut imap);
return msg::flag::handler::set(uid, flags, &output, &mut imap);
}
Some(msg::flag::arg::Command::Add(uid, flags)) => {
return msg::flag::handler::add(uid, flags, &mut imap);
return msg::flag::handler::add(uid, flags, &output, &mut imap);
}
Some(msg::flag::arg::Command::Remove(uid, flags)) => {
return msg::flag::handler::remove(uid, flags, &mut imap);
return msg::flag::handler::remove(uid, flags, &output, &mut imap);
}
_ => (),
},

View file

@ -67,17 +67,6 @@ pub struct OutputService {
}
impl OutputService {
/// Create a new output-handler by setting the given formatting style.
pub fn new(slice: &str) -> Result<Self> {
let fmt = OutputFmt::try_from(Some(slice))?;
Ok(Self { fmt })
}
/// Returns true, if the formatting should be plaintext.
pub fn is_plain(&self) -> bool {
self.fmt == OutputFmt::Plain
}
/// Returns true, if the formatting should be json.
pub fn is_json(&self) -> bool {
self.fmt == OutputFmt::Json