/* * 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::PathBuf; use std::sync::Mutex; use std::sync::atomic::{AtomicU32, Ordering}; use std::thread; use std::time::Duration; use encodify::base64::STANDARD; use inbuxa_migrate::db; use inbuxa_migrate::imap::client::{ConnectMode, ImapClient}; use inbuxa_migrate::imap::error::ImapError; use inbuxa_migrate::imap::transport::Connector; use inbuxa_migrate::logging::Logger; use inbuxa_migrate::sync::CommonConfig; use inbuxa_migrate::sync::import_imap::{ImapAuth, ImapImportConfig, run}; use rusqlite::Connection; type Script = Box std::io::Result<()> + Send + 'static>; struct MockImap { addr: String, port: u16, _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_command(&mut self) -> std::io::Result<(String, String)> { 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", )); } let trimmed = line.trim_end_matches(['\r', '\n']); let (tag, rest) = trimmed .split_once(' ') .map(|(t, r)| (t.to_owned(), r.to_owned())) .unwrap_or_else(|| (trimmed.to_owned(), String::new())); Ok((tag, rest)) } } impl MockImap { fn start(handler: H) -> MockImap where H: FnOnce(&mut MockConn) -> std::io::Result<()> + Send + 'static, { Self::start_scripts(vec![Box::new(handler)]) } fn start_scripts(scripts: Vec