From 706d397ad59038392a7fa7b4a0912bcd42cbfb8d Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Mon, 15 Feb 2021 04:36:06 -0600 Subject: [PATCH] cargo clippy fixes + refactor --- Cargo.toml | 3 ++ imap/src/builders/command.rs | 1 - src/config.rs | 23 +++++++++++-- src/{mail.rs => mail/imap.rs} | 64 +++++------------------------------ src/mail/mod.rs | 57 +++++++++++++++++++++++++++++++ src/main.rs | 15 +++----- src/ui/mod.rs | 15 ++++---- src/ui/table.rs | 13 ++++--- 8 files changed, 108 insertions(+), 83 deletions(-) rename src/{mail.rs => mail/imap.rs} (82%) create mode 100644 src/mail/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 9c45c17..7860466 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,3 +34,6 @@ tokio-util = { version = "0.6.3", features = ["full"] } toml = "0.5.8" webpki-roots = "0.21.0" xdg = "2.2.0" + +[features] +clippy = [] diff --git a/imap/src/builders/command.rs b/imap/src/builders/command.rs index a2b1bb5..6a3504e 100644 --- a/imap/src/builders/command.rs +++ b/imap/src/builders/command.rs @@ -1,5 +1,4 @@ use std::borrow::Cow; -use std::fmt; use std::marker::PhantomData; use std::ops::{RangeFrom, RangeInclusive}; use std::str; diff --git a/src/config.rs b/src/config.rs index 5ecc5a5..6ea14b6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -29,14 +29,14 @@ pub struct Config { } /// Configuration for a single mail account -#[derive(Default, Serialize, Deserialize, Clone, Debug)] +#[derive(Serialize, Deserialize, Clone, Debug)] pub struct MailAccountConfig { /// Imap pub imap: ImapConfig, } /// Configuring an IMAP server -#[derive(Default, Serialize, Deserialize, Clone, Debug)] +#[derive(Serialize, Deserialize, Clone, Debug)] pub struct ImapConfig { /// Host of the IMAP server (needs to be hostname for TLS) pub server: String, @@ -49,6 +49,25 @@ pub struct ImapConfig { /// Password for authenticating to IMAP pub password: String, + + /// TLS + pub tls: TlsMethod, +} + +/// Describes when to perform the TLS handshake +#[derive(Serialize, Deserialize, Clone, Debug)] +pub enum TlsMethod { + /// Perform TLS handshake immediately upon connection + #[serde(rename = "on")] + On, + + /// Perform TLS handshake after issuing the STARTTLS command + #[serde(rename = "starttls")] + Starttls, + + /// Don't perform TLS handshake at all (unsecured) + #[serde(rename = "off")] + Off, } /// Spawns a notify::RecommendedWatcher to watch the XDG config directory. Whenever the config file diff --git a/src/mail.rs b/src/mail/imap.rs similarity index 82% rename from src/mail.rs rename to src/mail/imap.rs index f717b12..20ed62f 100644 --- a/src/mail.rs +++ b/src/mail/imap.rs @@ -1,5 +1,3 @@ -//! Mail - use std::collections::HashMap; use std::fmt::Display; use std::sync::Arc; @@ -16,62 +14,13 @@ use panorama_imap::{ parser::parse_response, types::{Capability, RequestId, Response, ResponseCode, State, Status}, }; -use tokio::{ - net::TcpStream, - sync::mpsc::{self, UnboundedReceiver}, - task::JoinHandle, -}; +use tokio::{net::TcpStream, sync::mpsc}; use tokio_rustls::{rustls::ClientConfig, webpki::DNSNameRef, TlsConnector}; -use tokio_stream::wrappers::WatchStream; use tokio_util::codec::{Decoder, LinesCodec, LinesCodecError}; -use crate::config::{Config, ConfigWatcher, ImapConfig}; +use crate::config::ImapConfig; -/// Command sent to the mail thread by something else (i.e. UI) -pub enum MailCommand { - /// Refresh the list - Refresh, - - /// Send a raw command - Raw(Command), -} - -/// Main entrypoint for the mail listener. -pub async fn run_mail( - config_watcher: ConfigWatcher, - cmd_in: UnboundedReceiver, -) -> Result<()> { - let mut curr_conn: Option> = None; - - let mut config_watcher = WatchStream::new(config_watcher); - loop { - debug!("listening for configs"); - let a = config_watcher.next().await; - debug!("got config {:?}", a); - let config: Config = match a { - Some(Some(v)) => v, - _ => break, - }; - - // TODO: gracefully shut down connection - // just gonna drop the connection for now - if let Some(mut curr_conn) = curr_conn.take() { - debug!("dropping connection..."); - curr_conn.abort(); - } - - let handle = tokio::spawn(async { - for acct in config.mail_accounts.into_iter() { - open_imap_connection(acct.imap); - } - }); - curr_conn = Some(handle); - } - - Ok(()) -} - -async fn open_imap_connection(config: ImapConfig) -> Result<()> { +pub async fn open_imap_connection(config: ImapConfig) -> Result<()> { debug!( "Opening imap connection to {}:{}", config.server, config.port @@ -165,6 +114,7 @@ where debug!("<<< {:?}", resp); match st { + State::Authenticated => {} State::NotAuthenticated => match resp { Response::Data { status: Status::Ok, @@ -194,7 +144,7 @@ where } } - Response::Capabilities(caps) => { + Response::Capabilities(_caps) => { if with_ssl { // send authentication information let cmd = Command { @@ -226,10 +176,12 @@ where Ok(LoopExit::Closed) } +type InFlightFunc = Box) + Send>; + /// A struct in charge of managing multiple in-flight commands. struct CommandManager { tag_idx: usize, - in_flight: HashMap) + Send>>, + in_flight: HashMap, sink: S, } diff --git a/src/mail/mod.rs b/src/mail/mod.rs new file mode 100644 index 0000000..6256134 --- /dev/null +++ b/src/mail/mod.rs @@ -0,0 +1,57 @@ +//! Mail + +mod imap; + +use anyhow::Result; +use futures::stream::StreamExt; +use panorama_imap::builders::command::Command as ImapCommand; +use tokio::{sync::mpsc::UnboundedReceiver, task::JoinHandle}; +use tokio_stream::wrappers::WatchStream; + +use crate::config::{Config, ConfigWatcher}; + +use self::imap::open_imap_connection; + +/// Command sent to the mail thread by something else (i.e. UI) +pub enum MailCommand { + /// Refresh the list + Refresh, + + /// Send a raw command + Raw(ImapCommand), +} + +/// Main entrypoint for the mail listener. +pub async fn run_mail( + config_watcher: ConfigWatcher, + _cmd_in: UnboundedReceiver, +) -> Result<()> { + let mut curr_conn: Option> = None; + + let mut config_watcher = WatchStream::new(config_watcher); + loop { + debug!("listening for configs"); + let a = config_watcher.next().await; + debug!("got config {:?}", a); + let config: Config = match a { + Some(Some(v)) => v, + _ => break, + }; + + // TODO: gracefully shut down connection + // just gonna drop the connection for now + if let Some(curr_conn) = curr_conn.take() { + debug!("dropping connection..."); + curr_conn.abort(); + } + + let handle = tokio::spawn(async { + for acct in config.mail_accounts.into_iter() { + open_imap_connection(acct.imap).await.unwrap(); + } + }); + curr_conn = Some(handle); + } + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 40a1a39..2148236 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,13 @@ #[macro_use] extern crate log; -use std::fs::File; -use std::io::Read; use std::path::PathBuf; use anyhow::Result; use futures::future::TryFutureExt; -use panorama::{ - config::{spawn_config_watcher, Config}, - mail, ui, -}; +use panorama::{config::spawn_config_watcher, mail, ui}; use structopt::StructOpt; -use tokio::sync::{mpsc, oneshot}; +use tokio::sync::mpsc; use xdg::BaseDirectories; #[derive(Debug, StructOpt)] @@ -35,14 +30,14 @@ async fn main() -> Result<()> { // print logs to file as directed by command line options setup_logger(&opt)?; - let xdg = BaseDirectories::new()?; - let (config_thread, config_update) = spawn_config_watcher()?; + let _xdg = BaseDirectories::new()?; + let (_config_thread, config_update) = spawn_config_watcher()?; // used to notify the runtime that the process should exit let (exit_tx, mut exit_rx) = mpsc::channel::<()>(1); // used to send commands to the mail service - let (mail_tx, mail_rx) = mpsc::unbounded_channel(); + let (_mail_tx, mail_rx) = mpsc::unbounded_channel(); tokio::spawn(mail::run_mail(config_update.clone(), mail_rx).unwrap_or_else(report_err)); diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 46e567b..17e4310 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -11,7 +11,7 @@ use crossterm::{ cursor, event::{self, Event, KeyCode, KeyEvent}, style::{self, Color}, - terminal::{self, ClearType}, + terminal, }; use tokio::time; @@ -58,12 +58,13 @@ pub async fn run_ui(mut w: impl Write, exit: ExitSender) -> Result<()> { if event::poll(FRAME)? { let event = event::read()?; table.update(&event); - match event { - Event::Key(KeyEvent { - code: KeyCode::Char('q'), - .. - }) => break, - _ => {} + + if let Event::Key(KeyEvent { + code: KeyCode::Char('q'), + .. + }) = event + { + break; } } } diff --git a/src/ui/table.rs b/src/ui/table.rs index 537de73..fce71a8 100644 --- a/src/ui/table.rs +++ b/src/ui/table.rs @@ -17,8 +17,8 @@ pub struct Table { impl Table { pub fn update(&mut self, event: &Event) { - match event { - Event::Key(KeyEvent { code, .. }) => match code { + if let Event::Key(KeyEvent { code, .. }) = event { + match code { KeyCode::Char('j') => { if let Some(selected_row) = &mut self.selected_row { *selected_row = (self.rows.len() as u16 - 1).min(*selected_row + 1); @@ -27,13 +27,12 @@ impl Table { KeyCode::Char('k') => { if let Some(selected_row) = &mut self.selected_row { if *selected_row > 0 { - *selected_row = *selected_row - 1; + *selected_row -= 1; } } } _ => {} - }, - _ => {} + } } } @@ -45,7 +44,7 @@ impl Table { let mut columns = Vec::new(); for row in self.rows.iter() { for (i, cell) in row.iter().enumerate() { - if columns.len() == 0 || columns.len() - 1 < i { + if columns.is_empty() || columns.len() - 1 < i { columns.push(0); } else { columns[i] = cell.len().max(columns[i]); @@ -105,7 +104,7 @@ impl Table { pub fn push_row(&mut self, row: Vec) { self.rows.push(row); - if let None = self.selected_row { + if self.selected_row.is_none() { self.selected_row = Some(0); } }