From 6302d9d61820279f11fdf8e358d68f2de51111d2 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Thu, 27 Aug 2020 17:18:58 +0300 Subject: [PATCH] Rename testing crate to tools, and add README --- Cargo.toml | 2 +- {testing => tools}/Cargo.toml | 10 +- tools/README.md | 46 ++++++ {testing => tools}/src/email_parse.rs | 0 tools/src/embed.rs | 7 + .../imap_conn.rs => tools/src/imapshell.rs | 4 +- {testing => tools}/src/linebreak.rs | 0 tools/src/linebreak1.rs | 150 ++++++++++++++++++ {testing => tools}/src/mboxparse.rs | 0 tools/src/smtp_conn.rs | 50 ++++++ 10 files changed, 263 insertions(+), 6 deletions(-) rename {testing => tools}/Cargo.toml (79%) create mode 100644 tools/README.md rename {testing => tools}/src/email_parse.rs (100%) create mode 100644 tools/src/embed.rs rename testing/src/imap_conn.rs => tools/src/imapshell.rs (92%) rename {testing => tools}/src/linebreak.rs (100%) create mode 100644 tools/src/linebreak1.rs rename {testing => tools}/src/mboxparse.rs (100%) create mode 100644 tools/src/smtp_conn.rs diff --git a/Cargo.toml b/Cargo.toml index f3864d7fb..f3187e204 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,7 @@ opt-level = "z" debug = false [workspace] -members = ["melib", "testing", ] +members = ["melib", "tools", ] [features] default = ["sqlite3", "notmuch", "regexp", "smtp"] diff --git a/testing/Cargo.toml b/tools/Cargo.toml similarity index 79% rename from testing/Cargo.toml rename to tools/Cargo.toml index 3ad49874b..e855132f4 100644 --- a/testing/Cargo.toml +++ b/tools/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "testing" +name = "tools" version = "0.4.1" authors = ["Manos Pitsidianakis "] workspace = ".." @@ -14,8 +14,12 @@ name = "mboxparse" path = "src/mboxparse.rs" [[bin]] -name = "imapconn" -path = "src/imap_conn.rs" +name = "imapshell" +path = "src/imapshell.rs" + +[[bin]] +name = "smtp_conn" +path = "src/smtp_conn.rs" [dependencies] melib = { path = "../melib", version = "*", features = ["debug-tracing", "unicode_algorithms"] } diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 000000000..de3e1b5ff --- /dev/null +++ b/tools/README.md @@ -0,0 +1,46 @@ +# meli tools + +This crate holds a collection of small binaries used for meli development. Of note is `imapshell` which opens a shell to an IMAP server for the user to play with. + +## imapshell + +```shell +cd tools/ +cargo build --bin imapshell +# Usage: imap_conn server_hostname server_username server_password server_port +rlwrap ./target/debug/imapshell "mail.domain.tld" "epilys@domain.tld" "hunter2" 143 +``` + +Example session: + +First, the IMAP connections performs its own non-interactive setup: + +```text +[2020-08-27 17:11:33]["main"] melib/src/backends/imap/connection.rs:459_25: sent: M1 CAPABILITY +[2020-08-27 17:11:33]["main"] melib/src/backends/imap/connection.rs:408_33: &ret[last_line_idx..] = "M1 OK Pre-login capabilities listed, post-login capabilities have more.\r\n" +[2020-08-27 17:11:33]["main"] melib/src/backends/imap/connection.rs:459_25: sent: M2 LOGIN "epilys@domain.tld" "hunter2" +[2020-08-27 17:11:34]["main"] melib/src/backends/imap/connection.rs:459_25: sent: M3 CAPABILITY +[2020-08-27 17:11:34]["main"] melib/src/backends/imap/connection.rs:408_33: &ret[last_line_idx..] = "M3 OK Capability completed (0.000 + 0.120 + 0.119 secs).\r\n" +[2020-08-27 17:11:34]["main"] melib/src/backends/imap/connection.rs:459_25: sent: M4 ENABLE CONDSTORE +[2020-08-27 17:11:34]["main"] melib/src/backends/imap/connection.rs:408_33: &ret[last_line_idx..] = "M4 OK Enabled (0.000 + 0.120 + 0.119 secs).\r\n" +[2020-08-27 17:11:34]["main"] melib/src/backends/imap/protocol_parser.rs:261_9: &val = "M4 OK Enabled (0.000 + 0.120 + 0.119 secs).\r\n" +[2020-08-27 17:11:34]["main"] melib/src/backends/imap/connection.rs:459_25: sent: M5 COMPRESS DEFLATE +[2020-08-27 17:11:34]["main"] melib/src/backends/imap/connection.rs:408_33: &ret[last_line_idx..] = "M5 OK Begin compression (0.000 + 0.127 + 0.126 secs).\r\n" +[2020-08-27 17:11:34]["main"] melib/src/backends/imap/protocol_parser.rs:261_9: &val = "M5 OK Begin compression (0.000 + 0.127 + 0.126 secs).\r\n" +[2020-08-27 17:11:34]["main"] melib/src/backends/imap/protocol_parser.rs:261_9: &val = "M5 OK Begin compression (0.000 + 0.127 + 0.126 secs).\r\n" +[2020-08-27 17:11:34]["main"] melib/src/backends/imap/connection.rs:459_25: sent: M6 NOOP +[2020-08-27 17:11:34]["main"] melib/src/backends/imap/connection.rs:408_33: &ret[last_line_idx..] = "M6 OK NOOP completed (0.000 + 0.000 secs).\r\n" +[2020-08-27 17:11:34]["main"] melib/src/backends/imap/protocol_parser.rs:261_9: &val = "M6 OK NOOP completed (0.000 + 0.000 secs).\r\n" +``` + +Then, input is read line by line and sent to the server. You don't have to prefix the commands with a unique ID, that is taken care of by the tool. Example command and reply: + +```text +LIST "" "INBOX" +[2020-08-27 17:14:53]["main"] melib/src/backends/imap/connection.rs:717_9: send_command +[2020-08-27 17:14:53]["main"] melib/src/backends/imap/connection.rs:437_9: stream send_command() +[2020-08-27 17:14:53]["main"] melib/src/backends/imap/connection.rs:459_25: sent: M8 LIST "" "INBOX" +[2020-08-27 17:14:53]["main"] melib/src/backends/imap/connection.rs:729_13: send_command ok +[2020-08-27 17:14:53]["main"] melib/src/backends/imap.rs:1241_21: out: * LIST (\HasChildren) "." INBOX +M8 OK List completed (0.000 + 0.000 secs). +``` diff --git a/testing/src/email_parse.rs b/tools/src/email_parse.rs similarity index 100% rename from testing/src/email_parse.rs rename to tools/src/email_parse.rs diff --git a/tools/src/embed.rs b/tools/src/embed.rs new file mode 100644 index 000000000..e91830236 --- /dev/null +++ b/tools/src/embed.rs @@ -0,0 +1,7 @@ +extern crate ui; +use ui::terminal::embed::create_pty; + +fn main() -> std::io::Result<()> { + create_pty().unwrap(); + Ok(()) +} diff --git a/testing/src/imap_conn.rs b/tools/src/imapshell.rs similarity index 92% rename from testing/src/imap_conn.rs rename to tools/src/imapshell.rs index 00fa93ae6..4a10a9dbf 100644 --- a/testing/src/imap_conn.rs +++ b/tools/src/imapshell.rs @@ -8,7 +8,7 @@ use melib::{AccountSettings, BackendEventConsumer}; /// /// # Example invocation: /// ```sh -/// ./imap_conn server_hostname server_username server_password server_port"); +/// ./imapshell server_hostname server_username server_password server_port"); /// ``` /// /// `danger_accept_invalid_certs` is turned on by default, so no certificate validation is performed. @@ -16,7 +16,7 @@ use melib::{AccountSettings, BackendEventConsumer}; fn main() -> Result<()> { let mut args = std::env::args().skip(1).collect::>(); if args.len() != 4 { - eprintln!("Usage: imap_conn server_hostname server_username server_password server_port"); + eprintln!("Usage: imapshell server_hostname server_username server_password server_port"); std::process::exit(1); } diff --git a/testing/src/linebreak.rs b/tools/src/linebreak.rs similarity index 100% rename from testing/src/linebreak.rs rename to tools/src/linebreak.rs diff --git a/tools/src/linebreak1.rs b/tools/src/linebreak1.rs new file mode 100644 index 000000000..f5abceaad --- /dev/null +++ b/tools/src/linebreak1.rs @@ -0,0 +1,150 @@ +extern crate melib; +use melib::Result; +use melib::StackVec; +use std::str::FromStr; + +extern crate text_processing; +use text_processing::line_break::*; +use text_processing::Graphemes; + +fn cost(i: usize, j: usize, width: usize, minima: &Vec, offsets: &Vec) -> usize { + let w = offsets[j] + j - offsets[i] - i - 1; + if w > width { + return 65536 * (w - width); + } + minima[i] + (width - w) * (width - w) +} + +fn smawk( + rows: &mut StackVec, + columns: &mut StackVec, + minima: &mut Vec, + breaks: &mut Vec, + width: usize, + offsets: &Vec, +) { + let mut stack = StackVec::new(); + let mut i = 0; + while i < rows.len() { + if stack.len() > 0 { + let c = columns[stack.len() - 1]; + if cost(*stack.iter().last().unwrap(), c, width, minima, offsets) + < cost(rows[i], c, width, minima, offsets) + { + if stack.len() < columns.len() { + stack.push(rows[i]); + } + i += 1; + } else { + stack.pop(); + } + } else { + stack.push(rows[i]); + i += 1; + } + } + let rows = &mut stack; + if columns.len() > 1 { + let mut odd_columns = columns.iter().skip(1).step_by(2).cloned().collect(); + smawk(rows, &mut odd_columns, minima, breaks, width, offsets); + for (i, o) in odd_columns.into_iter().enumerate() { + columns.set(2 * i + 1, o); + } + } + let mut i = 0; + let mut j = 0; + while j < columns.len() { + let end = if j + 1 < columns.len() { + breaks[columns[j + 1]] + } else { + *rows.iter().last().unwrap() + }; + let c = cost(rows[i], columns[j], width, minima, offsets); + if c < minima[columns[j]] { + minima[columns[j]] = c; + breaks[columns[j]] = rows[i]; + } + if rows[i] < end { + i += 1; + } else { + j += 2; + } + } +} + +fn linear(text: &str, width: usize) -> Vec { + let mut words = text.split_whitespace().collect::>(); + let breaks = LineBreakCandidateIter::new(text).collect::>(); + let count = words.len(); + let mut minima = vec![std::usize::MAX - 1; count + 1]; + minima[0] = 0; + let mut offsets = Vec::with_capacity(words.len()); + offsets.push(0); + for w in words.iter() { + offsets.push(offsets.iter().last().unwrap() + w.grapheme_len()); + } + + let mut breaks = vec![0; count + 1]; + + let mut n = count + 1; + let mut i = 1; + let mut offset = 0; + loop { + let r = std::cmp::min(n, 2 * i); + let edge = i + offset; + smawk( + &mut (offset..edge).collect(), + &mut (edge..(r + offset)).collect(), + &mut minima, + &mut breaks, + width, + &offsets, + ); + let x = minima[r - 1 + offset]; + let mut for_was_broken = false; + for j in i..(r - 1) { + let y = cost(j + offset, r - 1 + offset, width, &minima, &offsets); + if y <= x { + n -= j; + i = 1; + offset += j; + for_was_broken = true; + break; + } + } + + if !for_was_broken { + if r == n { + break; + } + i *= 2; + } + } + let mut lines = Vec::new(); + let mut j = count; + while j > 0 { + let mut line = words[breaks[j]..j].join(" "); + lines.push(line); + j = breaks[j]; + } + lines.reverse(); + lines +} + +fn main() -> Result<()> { + let text = std::fs::read_to_string(std::env::args().nth(1).unwrap())?; + let width = usize::from_str(&std::env::args().nth(2).unwrap()).unwrap(); + //let paragraphs = text.split("\n\n").collect::>(); + for _ in 0..(width - 1) { + print!(" "); + } + println!("|"); + for l in linear(&text, width) { + println!("{}", l); + } + for _ in 0..(width - 1) { + print!(" "); + } + println!("|"); + Ok(()) +} diff --git a/testing/src/mboxparse.rs b/tools/src/mboxparse.rs similarity index 100% rename from testing/src/mboxparse.rs rename to tools/src/mboxparse.rs diff --git a/tools/src/smtp_conn.rs b/tools/src/smtp_conn.rs new file mode 100644 index 000000000..d71953728 --- /dev/null +++ b/tools/src/smtp_conn.rs @@ -0,0 +1,50 @@ +extern crate melib; + +use melib::futures; +use melib::smol; +use melib::smtp::*; +use melib::Result; + +/// Opens an interactive shell on an IMAP server. Suggested use is with rlwrap(1) +/// +/// # Example invocation: +/// ```sh +/// ./imap_conn server_hostname server_username server_password server_port"); +/// ``` +/// +/// `danger_accept_invalid_certs` is turned on by default, so no certificate validation is performed. + +fn main() -> Result<()> { + let conf = SmtpServerConf { + hostname: "smtp1.ntua.gr".into(), + port: 587, + security: SmtpSecurity::StartTLS { + danger_accept_invalid_certs: false, + }, + extensions: SmtpExtensionSupport::default(), + auth: SmtpAuth::Auto { + username: "el13635".into(), + password: Password::CommandEval( + "gpg2 --no-tty -q -d ~/.passwords/msmtp/ntua.gpg".into(), + ), + require_auth: true, + }, + envelope_from: String::new(), + }; + for _ in 0..1 { + std::thread::spawn(|| smol::run(futures::future::pending::<()>())); + } + + let mut conn = futures::executor::block_on(SmtpConnection::new_connection(conf)).unwrap(); + futures::executor::block_on(conn.mail_transaction( + r##"To: pr.birch@gmail.com +Auto-Submitted: auto-generated +Subject: Fwd: *** SMTP TEST #2 information *** +From: Manos +Message-Id: +Date: Mon, 13 Jul 2020 15:02:15 +0300 + +postretch : May 20 18:02:00 : epilys : user NOT in sudoers ; TTY=pts/13 ; PWD=/tmp/db-project ; USER=postgres ; COMMAND=/usr/bin/dropdb Prescriptions-R-X"##, + )).unwrap(); + Ok(()) +}