Move format_flowed to a separate crate

This makes it possible to fuzz test the functions
without exposing the module interface in the deltachat core
interface.

Also ensure that format_flowed will not grow a dependency
on deltachat core types.
This commit is contained in:
link2xt
2022-12-26 13:34:38 +00:00
parent 6dc790f447
commit 89b7ce4c4e
9 changed files with 70 additions and 54 deletions

View File

@@ -5,6 +5,7 @@
### Changes
- Validate signatures in try_decrypt() even if the message isn't encrypted #3859
- Don't parse the message again after detached signatures validation #3862
- Move format=flowed support to a separate crate #3869
### API-Changes

5
Cargo.lock generated
View File

@@ -887,6 +887,7 @@ dependencies = [
"encoded-words",
"escaper",
"fast-socks5",
"format-flowed",
"futures",
"futures-lite",
"hex",
@@ -1445,6 +1446,10 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "format-flowed"
version = "1.0.0"
[[package]]
name = "futures"
version = "0.3.25"

View File

@@ -19,6 +19,7 @@ panic = 'abort'
[dependencies]
deltachat_derive = { path = "./deltachat_derive" }
format-flowed = { path = "./format-flowed" }
ansi_term = { version = "0.12.1", optional = true }
anyhow = "1"
@@ -99,7 +100,8 @@ members = [
"deltachat-ffi",
"deltachat_derive",
"deltachat-jsonrpc",
"deltachat-rpc-server"
"deltachat-rpc-server",
"format-flowed",
]
[[example]]

11
format-flowed/Cargo.toml Normal file
View File

@@ -0,0 +1,11 @@
[package]
name = "format-flowed"
version = "1.0.0"
description = "format=flowed support"
edition = "2021"
license = "MPL-2.0"
keywords = ["email"]
categories = ["email"]
[dependencies]

View File

@@ -62,7 +62,7 @@ fn format_line_flowed(line: &str, prefix: &str) -> String {
///
/// RFC 2646 technique is used to insert soft line breaks, so DelSp
/// SHOULD be set to "no" when sending.
pub(crate) fn format_flowed(text: &str) -> String {
pub fn format_flowed(text: &str) -> String {
let mut result = String::new();
for line in text.split('\n') {
@@ -147,8 +147,6 @@ pub fn unformat_flowed(text: &str, delsp: bool) -> String {
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::TestContext;
use anyhow::Result;
#[test]
fn test_format_flowed() {
@@ -220,51 +218,4 @@ mod tests {
> unwrapped on the receiver";
assert_eq!(format_flowed_quote(quote), expected);
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_send_quotes() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
let chat = alice.create_chat(&bob).await;
let sent = alice.send_text(chat.id, "> First quote").await;
let received = bob.recv_msg(&sent).await;
assert_eq!(received.text.as_deref(), Some("> First quote"));
assert!(received.quoted_text().is_none());
assert!(received.quoted_message(&bob).await?.is_none());
let sent = alice.send_text(chat.id, "> Second quote").await;
let received = bob.recv_msg(&sent).await;
assert_eq!(received.text.as_deref(), Some("> Second quote"));
assert!(received.quoted_text().is_none());
assert!(received.quoted_message(&bob).await?.is_none());
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_format_flowed_round_trip() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
let chat = alice.create_chat(&bob).await;
let text = " Foo bar";
let sent = alice.send_text(chat.id, text).await;
let received = bob.recv_msg(&sent).await;
assert_eq!(received.text.as_deref(), Some(text));
let text = "Foo bar baz";
let sent = alice.send_text(chat.id, text).await;
let received = bob.recv_msg(&sent).await;
assert_eq!(received.text.as_deref(), Some(text));
let python_program = "\
def hello():
return 'Hello, world!'";
let sent = alice.send_text(chat.id, python_program).await;
let received = bob.recv_msg(&sent).await;
assert_eq!(received.text.as_deref(), Some(python_program));
Ok(())
}
}

View File

@@ -74,7 +74,6 @@ pub mod imex;
mod scheduler;
#[macro_use]
mod job;
mod format_flowed;
pub mod key;
mod keyring;
pub mod location;

View File

@@ -2340,4 +2340,51 @@ mod tests {
);
assert_eq!(Viewtype::Webxdc, Viewtype::from_i32(80).unwrap());
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_send_quotes() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
let chat = alice.create_chat(&bob).await;
let sent = alice.send_text(chat.id, "> First quote").await;
let received = bob.recv_msg(&sent).await;
assert_eq!(received.text.as_deref(), Some("> First quote"));
assert!(received.quoted_text().is_none());
assert!(received.quoted_message(&bob).await?.is_none());
let sent = alice.send_text(chat.id, "> Second quote").await;
let received = bob.recv_msg(&sent).await;
assert_eq!(received.text.as_deref(), Some("> Second quote"));
assert!(received.quoted_text().is_none());
assert!(received.quoted_message(&bob).await?.is_none());
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_format_flowed_round_trip() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
let chat = alice.create_chat(&bob).await;
let text = " Foo bar";
let sent = alice.send_text(chat.id, text).await;
let received = bob.recv_msg(&sent).await;
assert_eq!(received.text.as_deref(), Some(text));
let text = "Foo bar baz";
let sent = alice.send_text(chat.id, text).await;
let received = bob.recv_msg(&sent).await;
assert_eq!(received.text.as_deref(), Some(text));
let python_program = "\
def hello():
return 'Hello, world!'";
let sent = alice.send_text(chat.id, python_program).await;
let received = bob.recv_msg(&sent).await;
assert_eq!(received.text.as_deref(), Some(python_program));
Ok(())
}
}

View File

@@ -4,6 +4,7 @@ use std::convert::TryInto;
use anyhow::{bail, ensure, Context as _, Result};
use chrono::TimeZone;
use format_flowed::{format_flowed, format_flowed_quote};
use lettre_email::{mime, Address, Header, MimeMultipartType, PartBuilder};
use tokio::fs;
@@ -15,7 +16,6 @@ use crate::contact::Contact;
use crate::context::{get_version_str, Context};
use crate::e2ee::EncryptHelper;
use crate::ephemeral::Timer as EphemeralTimer;
use crate::format_flowed::{format_flowed, format_flowed_quote};
use crate::html::new_html_mimepart;
use crate::location;
use crate::message::{self, Message, MsgId, Viewtype};

View File

@@ -9,6 +9,7 @@ use std::str;
use anyhow::{bail, Context as _, Result};
use deltachat_derive::{FromSql, ToSql};
use format_flowed::unformat_flowed;
use lettre_email::mime::{self, Mime};
use mailparse::{addrparse_header, DispositionType, MailHeader, MailHeaderMap, SingleInfo};
use once_cell::sync::Lazy;
@@ -24,7 +25,6 @@ use crate::decrypt::{
};
use crate::dehtml::dehtml;
use crate::events::EventType;
use crate::format_flowed::unformat_flowed;
use crate::headerdef::{HeaderDef, HeaderDefMap};
use crate::key::{DcKey, Fingerprint, SignedPublicKey, SignedSecretKey};
use crate::keyring::Keyring;