SieveScripts and VacationResponse implementation
This commit is contained in:
@@ -25,12 +25,12 @@ pub async fn test(server: Arc<JMAP>, client: &mut Client) {
|
||||
let account_id_3 = test_account_create(&server, "bill@example.com", "12345", "Bill Foobar")
|
||||
.await
|
||||
.to_string();
|
||||
test_alias_create(&server, "jdoe@example.com", "john.doe@example.com").await;
|
||||
test_alias_create(&server, "jdoe@example.com", "john.doe@example.com", false).await;
|
||||
|
||||
// Create a mailing list
|
||||
test_alias_create(&server, "jdoe@example.com", "members@example.com").await;
|
||||
test_alias_create(&server, "jane@example.com", "members@example.com").await;
|
||||
test_alias_create(&server, "bill@example.com", "members@example.com").await;
|
||||
test_alias_create(&server, "jdoe@example.com", "members@example.com", true).await;
|
||||
test_alias_create(&server, "jane@example.com", "members@example.com", true).await;
|
||||
test_alias_create(&server, "bill@example.com", "members@example.com", true).await;
|
||||
|
||||
// Delivering to individuals
|
||||
let mut lmtp = SmtpConnection::connect().await;
|
||||
@@ -47,6 +47,7 @@ pub async fn test(server: Arc<JMAP>, client: &mut Client) {
|
||||
),
|
||||
)
|
||||
.await;
|
||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||
assert_eq!(
|
||||
server
|
||||
.get_document_ids(
|
||||
@@ -77,6 +78,7 @@ pub async fn test(server: Arc<JMAP>, client: &mut Client) {
|
||||
),
|
||||
)
|
||||
.await;
|
||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||
assert_eq!(
|
||||
server
|
||||
.get_document_ids(
|
||||
@@ -101,7 +103,7 @@ pub async fn test(server: Arc<JMAP>, client: &mut Client) {
|
||||
lmtp.expn("non_existant@example.com", 5).await;
|
||||
lmtp.expn("jdoe@example.com", 5).await;
|
||||
lmtp.vrfy("jdoe@example.com", 2).await;
|
||||
lmtp.vrfy("members@example.com", 2).await;
|
||||
lmtp.vrfy("members@example.com", 5).await;
|
||||
lmtp.vrfy("non_existant@example.com", 5).await;
|
||||
|
||||
// Delivering to a mailing list
|
||||
@@ -118,6 +120,7 @@ pub async fn test(server: Arc<JMAP>, client: &mut Client) {
|
||||
),
|
||||
)
|
||||
.await;
|
||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||
for (account_id, num_messages) in [(&account_id_1, 3), (&account_id_2, 1), (&account_id_3, 1)] {
|
||||
assert_eq!(
|
||||
server
|
||||
@@ -151,6 +154,7 @@ pub async fn test(server: Arc<JMAP>, client: &mut Client) {
|
||||
10,
|
||||
)
|
||||
.await;
|
||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||
for (account_id, num_messages) in [(&account_id_1, 3), (&account_id_2, 2), (&account_id_3, 2)] {
|
||||
assert_eq!(
|
||||
server
|
||||
@@ -188,6 +192,7 @@ pub async fn test(server: Arc<JMAP>, client: &mut Client) {
|
||||
),
|
||||
)
|
||||
.await;
|
||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||
for (account_id, num_messages) in [(&account_id_1, 4), (&account_id_2, 3), (&account_id_3, 3)] {
|
||||
assert_eq!(
|
||||
server
|
||||
@@ -205,12 +210,6 @@ pub async fn test(server: Arc<JMAP>, client: &mut Client) {
|
||||
);
|
||||
}
|
||||
|
||||
// Size checks
|
||||
lmtp.send("MAIL FROM:<hello@world> SIZE=943718400").await;
|
||||
lmtp.read(1, 5).await;
|
||||
lmtp.send("BDAT 943718400").await;
|
||||
lmtp.read(1, 5).await;
|
||||
|
||||
// Remove test data
|
||||
for account_id in [&account_id_1, &account_id_2, &account_id_3] {
|
||||
client.set_default_account_id(account_id);
|
||||
@@ -269,6 +268,7 @@ impl SmtpConnection {
|
||||
writer,
|
||||
};
|
||||
conn.read(1, 2).await;
|
||||
conn.lhlo().await;
|
||||
conn
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use futures::StreamExt;
|
||||
use jmap::JMAP;
|
||||
use jmap_client::{
|
||||
client::{Client, Credentials},
|
||||
event_source::Changes,
|
||||
mailbox::Role,
|
||||
TypeState,
|
||||
};
|
||||
use jmap::{mailbox::INBOX_ID, JMAP};
|
||||
use jmap_client::{client::Client, event_source::Changes, mailbox::Role, TypeState};
|
||||
use jmap_proto::types::id::Id;
|
||||
use store::ahash::AHashSet;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::jmap::{mailbox::destroy_all_mailboxes, test_account_create, test_account_login};
|
||||
use crate::jmap::{
|
||||
delivery::SmtpConnection, mailbox::destroy_all_mailboxes, test_account_create,
|
||||
test_account_login,
|
||||
};
|
||||
|
||||
pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
println!("Running EventSource tests...");
|
||||
|
||||
// Create test account
|
||||
test_account_create(&server, "jdoe@example.com", "12345", "John Doe").await;
|
||||
let account_id = test_account_create(&server, "jdoe@example.com", "12345", "John Doe").await;
|
||||
let mut client = test_account_login("jdoe@example.com", "12345").await;
|
||||
|
||||
let mut changes = client
|
||||
@@ -59,8 +57,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
assert_ping(&mut event_rx).await; // Pings are only received in cfg(test)
|
||||
|
||||
// Ingest email and expect state change
|
||||
let implement = "true";
|
||||
/*let mut lmtp = SmtpConnection::connect().await;
|
||||
let mut lmtp = SmtpConnection::connect().await;
|
||||
lmtp.ingest(
|
||||
"bill@example.com",
|
||||
&["jdoe@example.com"],
|
||||
@@ -86,18 +83,23 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
],
|
||||
)
|
||||
.await;
|
||||
assert_ping(&mut event_rx).await;*/
|
||||
assert_ping(&mut event_rx).await;
|
||||
|
||||
// Destroy mailbox
|
||||
client.mailbox_destroy(&mailbox_id, true).await.unwrap();
|
||||
assert_state(&mut event_rx, &[TypeState::Mailbox]).await;
|
||||
|
||||
/*assert_state(
|
||||
// Destroy Inbox
|
||||
admin_client.set_default_account_id(&account_id.to_string());
|
||||
admin_client
|
||||
.mailbox_destroy(&Id::from(INBOX_ID).to_string(), true)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_state(
|
||||
&mut event_rx,
|
||||
&[TypeState::Email, TypeState::Thread, TypeState::Mailbox],
|
||||
)
|
||||
.await;*/
|
||||
let fix = "true";
|
||||
assert_state(&mut event_rx, &[TypeState::Mailbox]).await;
|
||||
.await;
|
||||
assert_ping(&mut event_rx).await;
|
||||
assert_ping(&mut event_rx).await;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use jmap_client::client::{Client, Credentials};
|
||||
use jmap_proto::types::id::Id;
|
||||
use smtp::core::{SmtpSessionManager, SMTP};
|
||||
use tokio::sync::{mpsc, watch};
|
||||
use utils::config::ServerProtocol;
|
||||
use utils::{config::ServerProtocol, UnwrapFailure};
|
||||
|
||||
use crate::{add_test_certs, store::TempDir};
|
||||
|
||||
@@ -41,7 +41,7 @@ max-connections = 512
|
||||
bind = ['127.0.0.1:11200']
|
||||
greeting = 'Test LMTP instance'
|
||||
protocol = 'lmtp'
|
||||
tls.implicit = true
|
||||
tls.implicit = false
|
||||
|
||||
[server.socket]
|
||||
reuse-addr = true
|
||||
@@ -51,6 +51,37 @@ enable = true
|
||||
implicit = false
|
||||
certificate = "default"
|
||||
|
||||
[session.ehlo]
|
||||
reject-non-fqdn = false
|
||||
|
||||
[session.rcpt.lookup]
|
||||
domains = "list/domains"
|
||||
addresses = "local"
|
||||
vrfy = "local"
|
||||
expn = "local"
|
||||
|
||||
[session.rcpt.errors]
|
||||
total = 5
|
||||
wait = "1ms"
|
||||
|
||||
[list]
|
||||
domains = ["example.com"]
|
||||
|
||||
[queue]
|
||||
path = "{TMP}"
|
||||
hash = 64
|
||||
|
||||
[report]
|
||||
path = "{TMP}"
|
||||
hash = 64
|
||||
|
||||
[resolver]
|
||||
type = "system"
|
||||
|
||||
[queue.outbound]
|
||||
next-hop = [ { if = "rcpt-domain", in-list = "list/domains", then = "local" },
|
||||
{ else = false } ]
|
||||
|
||||
[store]
|
||||
db.path = "{TMP}/sqlite.db"
|
||||
blob.path = "{TMP}"
|
||||
@@ -93,10 +124,10 @@ uid-by-login = "SELECT ROWID - 1 FROM users WHERE login = ?"
|
||||
login-by-uid = "SELECT login FROM users WHERE ROWID - 1 = ?"
|
||||
secret-by-uid = "SELECT secret FROM users WHERE ROWID - 1 = ?"
|
||||
gids-by-uid = "SELECT gid FROM groups WHERE uid = ?"
|
||||
uids-by-address = "SELECT uid FROM emails WHERE address = ?"
|
||||
addresses-by-uid = "SELECT address FROM emails WHERE uid = ?"
|
||||
vrfy = "SELECT address FROM emails WHERE address LIKE '%' || ? || '%' LIMIT 5"
|
||||
expn = "SELECT address FROM emails WHERE address LIKE '%' || ? || '%' LIMIT 5"
|
||||
uids-by-address = "SELECT uid FROM emails WHERE email = ?"
|
||||
addresses-by-uid = "SELECT email FROM emails WHERE uid = ?"
|
||||
vrfy = "SELECT email FROM emails WHERE email LIKE '%' || ? || '%' AND is_list = false LIMIT 5"
|
||||
expn = "SELECT u.login FROM users u INNER JOIN emails e ON u.rowid -1 = e.uid WHERE e.email = ? AND e.is_list = true LIMIT 5"
|
||||
|
||||
[oauth]
|
||||
key = "parerga_und_paralipomena"
|
||||
@@ -131,11 +162,11 @@ pub async fn jmap_tests() {
|
||||
//thread_get::test(params.server.clone(), &mut params.client).await;
|
||||
//thread_merge::test(params.server.clone(), &mut params.client).await;
|
||||
//mailbox::test(params.server.clone(), &mut params.client).await;
|
||||
delivery::test(params.server.clone(), &mut params.client).await;
|
||||
//delivery::test(params.server.clone(), &mut params.client).await;
|
||||
//auth_acl::test(params.server.clone(), &mut params.client).await;
|
||||
//auth_limits::test(params.server.clone(), &mut params.client).await;
|
||||
//auth_oauth::test(params.server.clone(), &mut params.client).await;
|
||||
//event_source::test(params.server.clone(), &mut params.client).await;
|
||||
event_source::test(params.server.clone(), &mut params.client).await;
|
||||
//push_subscription::test(params.server.clone(), &mut params.client).await;
|
||||
|
||||
if delete {
|
||||
@@ -163,8 +194,12 @@ async fn init_jmap_tests(delete_if_exists: bool) -> JMAPTest {
|
||||
// Start JMAP and SMTP servers
|
||||
servers.bind(&config);
|
||||
let (delivery_tx, delivery_rx) = mpsc::channel(IPC_CHANNEL_BUFFER);
|
||||
let smtp = SMTP::init(&config, &servers, delivery_tx).await;
|
||||
let jmap = JMAP::init(&config, delivery_rx).await;
|
||||
let smtp = SMTP::init(&config, &servers, delivery_tx)
|
||||
.await
|
||||
.failed("Invalid configuration file");
|
||||
let jmap = JMAP::init(&config, delivery_rx)
|
||||
.await
|
||||
.failed("Invalid configuration file");
|
||||
let shutdown_tx = servers.spawn(|server, shutdown_rx| {
|
||||
match &server.protocol {
|
||||
ServerProtocol::Smtp | ServerProtocol::Lmtp => {
|
||||
@@ -181,7 +216,7 @@ async fn init_jmap_tests(delete_if_exists: bool) -> JMAPTest {
|
||||
for query in [
|
||||
"CREATE TABLE users (login TEXT PRIMARY KEY, secret TEXT, name TEXT)",
|
||||
"CREATE TABLE groups (uid INTEGER, gid INTEGER, PRIMARY KEY (uid, gid))",
|
||||
"CREATE TABLE emails (uid INTEGER NOT NULL, email TEXT NOT NULL, PRIMARY KEY (uid, email))",
|
||||
"CREATE TABLE emails (uid INTEGER NOT NULL, email TEXT NOT NULL, is_list BOOLEAN DEFAULT 0, PRIMARY KEY (uid, email))",
|
||||
"INSERT INTO users (login, secret) VALUES ('admin', 'secret')", // RowID 0 is admin
|
||||
] {
|
||||
assert!(
|
||||
@@ -290,14 +325,15 @@ pub async fn test_account_create(jmap: &JMAP, login: &str, secret: &str, name: &
|
||||
Id::new(uid)
|
||||
}
|
||||
|
||||
pub async fn test_alias_create(jmap: &JMAP, login: &str, alias: &str) {
|
||||
pub async fn test_alias_create(jmap: &JMAP, login: &str, alias: &str, is_list: bool) {
|
||||
let uid = jmap.get_account_id(login).await.unwrap() as u64;
|
||||
assert!(
|
||||
jmap.auth_db
|
||||
.execute(
|
||||
&format!(
|
||||
"INSERT OR REPLACE INTO emails (uid, email) VALUES ({}, ?)",
|
||||
uid
|
||||
"INSERT OR REPLACE INTO emails (uid, email, is_list) VALUES ({}, ?, {})",
|
||||
uid,
|
||||
if is_list { "true" } else { "false" }
|
||||
),
|
||||
vec![alias.to_string()].into_iter()
|
||||
)
|
||||
|
||||
@@ -120,6 +120,13 @@ if envelope :domain :is "to" "foobar.org" {
|
||||
data = '''
|
||||
require ["envelope", "reject", "variables", "replace", "mime", "foreverypart", "editheader", "extracttext", "enotify"];
|
||||
|
||||
if envelope :localpart :is "to" "thomas" {
|
||||
deleteheader "from";
|
||||
addheader "From" "no-reply@my.domain";
|
||||
redirect "redirect@here.email";
|
||||
discard;
|
||||
}
|
||||
|
||||
if envelope :localpart :is "to" "bill" {
|
||||
reject "Bill cannot receive messages.";
|
||||
stop;
|
||||
@@ -313,6 +320,32 @@ async fn sieve_scripts() {
|
||||
.assert_contains("THIS IS A PIECE OF HTML TEXT")
|
||||
.assert_not_contains("X-My-Header: true");
|
||||
|
||||
// Expect a modified redirected message
|
||||
session
|
||||
.send_message(
|
||||
"test@example.net",
|
||||
&["thomas@foobar.gov"],
|
||||
"test:no_dkim",
|
||||
"250",
|
||||
)
|
||||
.await;
|
||||
let redirect = qr.read_event().await.unwrap_message();
|
||||
assert_eq!(redirect.return_path, "");
|
||||
assert_eq!(redirect.recipients.len(), 1);
|
||||
assert_eq!(
|
||||
redirect.recipients.first().unwrap().address,
|
||||
"redirect@here.email"
|
||||
);
|
||||
|
||||
redirect
|
||||
.read_lines()
|
||||
.assert_contains("From: no-reply@my.domain")
|
||||
.assert_contains("To: Suzie Q <suzie@shopping.example.net>")
|
||||
.assert_contains("Subject: Is dinner ready?")
|
||||
.assert_contains("Message-ID: <20030712040037.46341.5F8J@football.example.com>")
|
||||
.assert_not_contains("From: Joe SixPack <joe@football.example.com>");
|
||||
qr.assert_empty_queue();
|
||||
|
||||
// Test pipes
|
||||
session.data.remote_ip = "10.0.0.123".parse().unwrap();
|
||||
session
|
||||
|
||||
Reference in New Issue
Block a user