/* * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC * SPDX-FileCopyrightText: 2026 John Coffey * * SPDX-License-Identifier: Apache-2.0 OR MIT */ use std::io::{BufRead, BufReader, Write}; use std::net::{TcpListener, TcpStream}; use std::path::{Path, PathBuf}; use std::sync::Mutex; use std::sync::atomic::{AtomicU32, Ordering}; use std::thread; use std::time::Duration; use inbuxa_migrate::logging::Logger; use inbuxa_migrate::sync::CommonConfig; use inbuxa_migrate::sync::import_managesieve::{ManageSieveAuth, ManageSieveImportConfig, run}; use rusqlite::Connection; type Script = Box std::io::Result<()> + Send + 'static>; struct MockSieveServer { addr: String, _thread: thread::JoinHandle<()>, } struct MockConn { reader: BufReader, writer: TcpStream, } impl MockConn { fn write_line(&mut self, s: &str) -> std::io::Result<()> { self.writer.write_all(s.as_bytes())?; self.writer.write_all(b"\r\n")?; self.writer.flush() } fn write_raw(&mut self, bytes: &[u8]) -> std::io::Result<()> { self.writer.write_all(bytes)?; self.writer.flush() } fn read_line(&mut self) -> std::io::Result { let mut line = String::new(); let n = self.reader.read_line(&mut line)?; if n == 0 { return Err(std::io::Error::new( std::io::ErrorKind::UnexpectedEof, "client closed", )); } Ok(line.trim_end_matches(['\r', '\n']).to_owned()) } fn write_capability(&mut self, sasl: &str, starttls: bool) -> std::io::Result<()> { self.write_line("\"IMPLEMENTATION\" \"Mock ManageSieve\"")?; self.write_line("\"VERSION\" \"1.0\"")?; if starttls { self.write_line("\"STARTTLS\"")?; } self.write_line(&format!("\"SASL\" \"{sasl}\""))?; self.write_line("\"SIEVE\" \"fileinto vacation\"")?; Ok(()) } } impl MockSieveServer { fn start(handler: H) -> MockSieveServer where H: FnOnce(&mut MockConn) -> std::io::Result<()> + Send + 'static, { Self::start_scripts(vec![Box::new(handler)]) } fn start_scripts(scripts: Vec