Rename testing crate to tools, and add README
parent
a37faf0bec
commit
6302d9d618
|
@ -70,7 +70,7 @@ opt-level = "z"
|
||||||
debug = false
|
debug = false
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["melib", "testing", ]
|
members = ["melib", "tools", ]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["sqlite3", "notmuch", "regexp", "smtp"]
|
default = ["sqlite3", "notmuch", "regexp", "smtp"]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "testing"
|
name = "tools"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
authors = ["Manos Pitsidianakis <el13635@mail.ntua.gr>"]
|
authors = ["Manos Pitsidianakis <el13635@mail.ntua.gr>"]
|
||||||
workspace = ".."
|
workspace = ".."
|
||||||
|
@ -14,8 +14,12 @@ name = "mboxparse"
|
||||||
path = "src/mboxparse.rs"
|
path = "src/mboxparse.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "imapconn"
|
name = "imapshell"
|
||||||
path = "src/imap_conn.rs"
|
path = "src/imapshell.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "smtp_conn"
|
||||||
|
path = "src/smtp_conn.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
melib = { path = "../melib", version = "*", features = ["debug-tracing", "unicode_algorithms"] }
|
melib = { path = "../melib", version = "*", features = ["debug-tracing", "unicode_algorithms"] }
|
|
@ -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).
|
||||||
|
```
|
|
@ -0,0 +1,7 @@
|
||||||
|
extern crate ui;
|
||||||
|
use ui::terminal::embed::create_pty;
|
||||||
|
|
||||||
|
fn main() -> std::io::Result<()> {
|
||||||
|
create_pty().unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ use melib::{AccountSettings, BackendEventConsumer};
|
||||||
///
|
///
|
||||||
/// # Example invocation:
|
/// # Example invocation:
|
||||||
/// ```sh
|
/// ```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.
|
/// `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<()> {
|
fn main() -> Result<()> {
|
||||||
let mut args = std::env::args().skip(1).collect::<Vec<String>>();
|
let mut args = std::env::args().skip(1).collect::<Vec<String>>();
|
||||||
if args.len() != 4 {
|
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);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<usize>, offsets: &Vec<usize>) -> 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<usize>,
|
||||||
|
columns: &mut StackVec<usize>,
|
||||||
|
minima: &mut Vec<usize>,
|
||||||
|
breaks: &mut Vec<usize>,
|
||||||
|
width: usize,
|
||||||
|
offsets: &Vec<usize>,
|
||||||
|
) {
|
||||||
|
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<String> {
|
||||||
|
let mut words = text.split_whitespace().collect::<Vec<&str>>();
|
||||||
|
let breaks = LineBreakCandidateIter::new(text).collect::<Vec<(usize, LineBreakCandidate)>>();
|
||||||
|
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::<Vec<&str>>();
|
||||||
|
for _ in 0..(width - 1) {
|
||||||
|
print!(" ");
|
||||||
|
}
|
||||||
|
println!("|");
|
||||||
|
for l in linear(&text, width) {
|
||||||
|
println!("{}", l);
|
||||||
|
}
|
||||||
|
for _ in 0..(width - 1) {
|
||||||
|
print!(" ");
|
||||||
|
}
|
||||||
|
println!("|");
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -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 <el13635@mail.ntua.gr>
|
||||||
|
Message-Id: <E1hSjnr-0003fN-RL2@postretch>
|
||||||
|
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(())
|
||||||
|
}
|
Loading…
Reference in New Issue