Re-enable proto

This commit is contained in:
Quentin 2024-03-08 09:55:33 +01:00
parent 1edf0b15ec
commit 11462f80c4
Signed by: quentin
GPG key ID: E9602264D639FF68
32 changed files with 992 additions and 132 deletions

929
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,7 @@ members = [
"aero-dav", "aero-dav",
"aero-dav/fuzz", "aero-dav/fuzz",
"aero-collections", "aero-collections",
# "aero-proto", "aero-proto",
# "aerogramme", # "aerogramme",
] ]
@ -20,7 +20,7 @@ aero-bayou = { version = "0.3.0", path = "aero-bayou" }
aero-sasl = { version = "0.3.0", path = "aero-sasl" } aero-sasl = { version = "0.3.0", path = "aero-sasl" }
aero-dav = { version = "0.3.0", path = "aero-dav" } aero-dav = { version = "0.3.0", path = "aero-dav" }
aero-collections = { version = "0.3.0", path = "aero-collections" } aero-collections = { version = "0.3.0", path = "aero-collections" }
#aero-proto = { version = "0.3.0", path = "aero-proto" } aero-proto = { version = "0.3.0", path = "aero-proto" }
#aerogramme = { version = "0.3.0", path = "aerogramme" } #aerogramme = { version = "0.3.0", path = "aerogramme" }
# async runtime # async runtime

View file

@ -1,4 +1,4 @@
use super::types as dav; //use super::types as dav;
use super::caltypes::*; use super::caltypes::*;
use super::xml; use super::xml;
use super::error; use super::error;
@ -7,25 +7,25 @@ use super::error;
// ---- EXTENSIONS --- // ---- EXTENSIONS ---
impl xml::QRead<Violation> for Violation { impl xml::QRead<Violation> for Violation {
async fn qread(xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> { async fn qread(_xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> {
unreachable!(); unreachable!();
} }
} }
impl xml::QRead<Property> for Property { impl xml::QRead<Property> for Property {
async fn qread(xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> { async fn qread(_xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> {
unreachable!(); unreachable!();
} }
} }
impl xml::QRead<PropertyRequest> for PropertyRequest { impl xml::QRead<PropertyRequest> for PropertyRequest {
async fn qread(xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> { async fn qread(_xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> {
unreachable!(); unreachable!();
} }
} }
impl xml::QRead<ResourceType> for ResourceType { impl xml::QRead<ResourceType> for ResourceType {
async fn qread(xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> { async fn qread(_xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> {
unreachable!(); unreachable!();
} }
} }

View file

@ -1,7 +1,5 @@
use quick_xml::Error as QError; use quick_xml::Error as QError;
use quick_xml::events::{Event, BytesEnd, BytesStart, BytesText}; use quick_xml::events::{Event, BytesText};
use quick_xml::name::PrefixDeclaration;
use tokio::io::AsyncWrite;
use super::caltypes::*; use super::caltypes::*;
use super::xml::{Node, QWrite, IWrite, Writer}; use super::xml::{Node, QWrite, IWrite, Writer};
@ -627,7 +625,7 @@ impl QWrite for ParamFilterMatch {
impl QWrite for TimeZone { impl QWrite for TimeZone {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let mut start = xml.create_cal_element("timezone"); let start = xml.create_cal_element("timezone");
let end = start.to_end(); let end = start.to_end();
xml.q.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;
@ -638,7 +636,7 @@ impl QWrite for TimeZone {
impl QWrite for Filter { impl QWrite for Filter {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> { async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
let mut start = xml.create_cal_element("filter"); let start = xml.create_cal_element("filter");
let end = start.to_end(); let end = start.to_end();
xml.q.write_event_async(Event::Start(start.clone())).await?; xml.q.write_event_async(Event::Start(start.clone())).await?;

View file

@ -1,14 +1,9 @@
use std::future::Future;
use quick_xml::events::Event; use quick_xml::events::Event;
use quick_xml::events::attributes::AttrError; use chrono::DateTime;
use quick_xml::name::{Namespace, QName, PrefixDeclaration, ResolveResult, ResolveResult::*};
use quick_xml::reader::NsReader;
use tokio::io::AsyncBufRead;
use super::types::*; use super::types::*;
use super::error::ParsingError; use super::error::ParsingError;
use super::xml::{Node, QRead, Reader, IRead, DAV_URN, CAL_URN}; use super::xml::{Node, QRead, Reader, IRead, DAV_URN};
//@TODO (1) Rewrite all objects as Href, //@TODO (1) Rewrite all objects as Href,
// where we return Ok(None) instead of trying to find the object at any cost. // where we return Ok(None) instead of trying to find the object at any cost.
@ -119,7 +114,7 @@ impl QRead<LockInfo> for LockInfo {
impl<E: Extension> QRead<PropValue<E>> for PropValue<E> { impl<E: Extension> QRead<PropValue<E>> for PropValue<E> {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> { async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
xml.open(DAV_URN, "prop").await?; xml.open(DAV_URN, "prop").await?;
let mut acc = xml.collect::<Property<E>>().await?; let acc = xml.collect::<Property<E>>().await?;
xml.close().await?; xml.close().await?;
Ok(PropValue(acc)) Ok(PropValue(acc))
} }
@ -352,8 +347,6 @@ impl<E: Extension> QRead<PropertyRequest<E>> for PropertyRequest<E> {
impl<E: Extension> QRead<Property<E>> for Property<E> { impl<E: Extension> QRead<Property<E>> for Property<E> {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> { async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
use chrono::{DateTime, FixedOffset, TimeZone};
// Core WebDAV properties // Core WebDAV properties
if xml.maybe_open(DAV_URN, "creationdate").await?.is_some() { if xml.maybe_open(DAV_URN, "creationdate").await?.is_some() {
let datestr = xml.tag_string().await?; let datestr = xml.tag_string().await?;
@ -592,7 +585,7 @@ impl QRead<LockType> for LockType {
impl QRead<Href> for Href { impl QRead<Href> for Href {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> { async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
xml.open(DAV_URN, "href").await?; xml.open(DAV_URN, "href").await?;
let mut url = xml.tag_string().await?; let url = xml.tag_string().await?;
xml.close().await?; xml.close().await?;
Ok(Href(url)) Ok(Href(url))
} }

View file

@ -1,5 +1,4 @@
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![feature(async_fn_in_trait)]
#![feature(async_closure)] #![feature(async_closure)]
#![feature(trait_alias)] #![feature(trait_alias)]

View file

@ -6,12 +6,12 @@ use super::error;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Disabled(()); pub struct Disabled(());
impl xml::QRead<Disabled> for Disabled { impl xml::QRead<Disabled> for Disabled {
async fn qread(xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> { async fn qread(_xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> {
Err(error::ParsingError::Recoverable) Err(error::ParsingError::Recoverable)
} }
} }
impl xml::QWrite for Disabled { impl xml::QWrite for Disabled {
async fn qwrite(&self, xml: &mut xml::Writer<impl xml::IWrite>) -> Result<(), quick_xml::Error> { async fn qwrite(&self, _xml: &mut xml::Writer<impl xml::IWrite>) -> Result<(), quick_xml::Error> {
unreachable!(); unreachable!();
} }
} }

35
aero-proto/Cargo.toml Normal file
View file

@ -0,0 +1,35 @@
[package]
name = "aero-proto"
version = "0.3.0"
authors = ["Alex Auvolat <alex@adnab.me>", "Quentin Dufour <quentin@dufour.io>"]
edition = "2021"
license = "EUPL-1.2"
description = "Binding between Aerogramme's internal components and well-known protocols"
[dependencies]
aero-sasl.workspace = true
aero-dav.workspace = true
aero-user.workspace = true
aero-collections.workspace = true
async-trait.workspace = true
anyhow.workspace = true
hyper.workspace = true
base64.workspace = true
hyper-util.workspace = true
http-body-util.workspace = true
futures.workspace = true
tokio.workspace = true
tokio-util.workspace = true
tokio-rustls.workspace = true
rustls.workspace = true
rustls-pemfile.workspace = true
imap-codec.workspace = true
imap-flow.workspace = true
chrono.workspace = true
eml-codec.workspace = true
thiserror.workspace = true
duplexify.workspace = true
smtp-message.workspace = true
smtp-server.workspace = true
tracing.workspace = true

View file

@ -11,9 +11,9 @@ use futures::stream::{FuturesUnordered, StreamExt};
use tokio::net::TcpListener; use tokio::net::TcpListener;
use tokio::sync::watch; use tokio::sync::watch;
use crate::config::DavUnsecureConfig; use aero_user::config::DavUnsecureConfig;
use crate::login::ArcLoginProvider; use aero_user::login::ArcLoginProvider;
use crate::user::User; use aero_collections::user::User;
pub struct Server { pub struct Server {
bind_addr: SocketAddr, bind_addr: SocketAddr,
@ -110,7 +110,7 @@ async fn auth(
// Call login provider // Call login provider
let creds = match login.login(username, password).await { let creds = match login.login(username, password).await {
Ok(c) => c, Ok(c) => c,
Err(e) => return Ok(Response::builder() Err(_) => return Ok(Response::builder()
.status(401) .status(401)
.body(Full::new(Bytes::from("Wrong credentials")))?), .body(Full::new(Bytes::from("Wrong credentials")))?),
}; };
@ -140,6 +140,7 @@ async fn router(user: std::sync::Arc<User>, req: Request<impl hyper::body::Body>
Ok(Response::new(Full::new(Bytes::from("Hello World!")))) Ok(Response::new(Full::new(Bytes::from("Hello World!"))))
} }
async fn collections(user: std::sync::Arc<User>, req: Request<impl hyper::body::Body>) -> Result<Response<Full<Bytes>>> { #[allow(dead_code)]
async fn collections(_user: std::sync::Arc<User>, _req: Request<impl hyper::body::Body>) -> Result<Response<Full<Bytes>>> {
unimplemented!(); unimplemented!();
} }

View file

@ -4,12 +4,13 @@ use imap_codec::imap_types::core::AString;
use imap_codec::imap_types::response::Code; use imap_codec::imap_types::response::Code;
use imap_codec::imap_types::secret::Secret; use imap_codec::imap_types::secret::Secret;
use aero_user::login::ArcLoginProvider;
use aero_collections::user::User;
use crate::imap::capability::ServerCapability; use crate::imap::capability::ServerCapability;
use crate::imap::command::anystate; use crate::imap::command::anystate;
use crate::imap::flow; use crate::imap::flow;
use crate::imap::response::Response; use crate::imap::response::Response;
use crate::login::ArcLoginProvider;
use crate::user::User;
//--- dispatching //--- dispatching

View file

@ -14,17 +14,16 @@ use imap_codec::imap_types::mailbox::{ListMailbox, Mailbox as MailboxCodec};
use imap_codec::imap_types::response::{Code, CodeOther, Data}; use imap_codec::imap_types::response::{Code, CodeOther, Data};
use imap_codec::imap_types::status::{StatusDataItem, StatusDataItemName}; use imap_codec::imap_types::status::{StatusDataItem, StatusDataItemName};
use aero_collections::mail::uidindex::*;
use aero_collections::user::User;
use aero_collections::mail::IMF;
use aero_collections::mail::namespace::MAILBOX_HIERARCHY_DELIMITER as MBX_HIER_DELIM_RAW;
use crate::imap::capability::{ClientCapability, ServerCapability}; use crate::imap::capability::{ClientCapability, ServerCapability};
use crate::imap::command::{anystate, MailboxName}; use crate::imap::command::{anystate, MailboxName};
use crate::imap::flow; use crate::imap::flow;
use crate::imap::mailbox_view::{MailboxView, UpdateParameters}; use crate::imap::mailbox_view::MailboxView;
use crate::imap::response::Response; use crate::imap::response::Response;
use crate::imap::Body;
use crate::mail::uidindex::*;
use crate::user::User;
use crate::mail::IMF;
use crate::mail::namespace::MAILBOX_HIERARCHY_DELIMITER as MBX_HIER_DELIM_RAW;
pub struct AuthenticatedContext<'a> { pub struct AuthenticatedContext<'a> {
pub req: &'a Command<'static>, pub req: &'a Command<'static>,
@ -611,7 +610,7 @@ impl<'a> AuthenticatedContext<'a> {
Some(mb) => mb, Some(mb) => mb,
None => bail!("Mailbox does not exist"), None => bail!("Mailbox does not exist"),
}; };
let mut view = MailboxView::new(mb, self.client_capabilities.condstore.is_enabled()).await; let view = MailboxView::new(mb, self.client_capabilities.condstore.is_enabled()).await;
if date.is_some() { if date.is_some() {
tracing::warn!("Cannot set date when appending message"); tracing::warn!("Cannot set date when appending message");

View file

@ -3,7 +3,7 @@ pub mod anystate;
pub mod authenticated; pub mod authenticated;
pub mod selected; pub mod selected;
use crate::mail::namespace::INBOX; use aero_collections::mail::namespace::INBOX;
use imap_codec::imap_types::mailbox::Mailbox as MailboxCodec; use imap_codec::imap_types::mailbox::Mailbox as MailboxCodec;
/// Convert an IMAP mailbox name/identifier representation /// Convert an IMAP mailbox name/identifier representation

View file

@ -3,7 +3,7 @@ use std::sync::Arc;
use anyhow::Result; use anyhow::Result;
use imap_codec::imap_types::command::{Command, CommandBody, FetchModifier, StoreModifier}; use imap_codec::imap_types::command::{Command, CommandBody, FetchModifier, StoreModifier};
use imap_codec::imap_types::core::{Charset, Vec1}; use imap_codec::imap_types::core::Charset;
use imap_codec::imap_types::fetch::MacroOrMessageDataItemNames; use imap_codec::imap_types::fetch::MacroOrMessageDataItemNames;
use imap_codec::imap_types::flag::{Flag, StoreResponse, StoreType}; use imap_codec::imap_types::flag::{Flag, StoreResponse, StoreType};
use imap_codec::imap_types::mailbox::Mailbox as MailboxCodec; use imap_codec::imap_types::mailbox::Mailbox as MailboxCodec;
@ -11,13 +11,14 @@ use imap_codec::imap_types::response::{Code, CodeOther};
use imap_codec::imap_types::search::SearchKey; use imap_codec::imap_types::search::SearchKey;
use imap_codec::imap_types::sequence::SequenceSet; use imap_codec::imap_types::sequence::SequenceSet;
use aero_collections::user::User;
use crate::imap::attributes::AttributesProxy; use crate::imap::attributes::AttributesProxy;
use crate::imap::capability::{ClientCapability, ServerCapability}; use crate::imap::capability::{ClientCapability, ServerCapability};
use crate::imap::command::{anystate, authenticated, MailboxName}; use crate::imap::command::{anystate, authenticated, MailboxName};
use crate::imap::flow; use crate::imap::flow;
use crate::imap::mailbox_view::{MailboxView, UpdateParameters}; use crate::imap::mailbox_view::{MailboxView, UpdateParameters};
use crate::imap::response::Response; use crate::imap::response::Response;
use crate::user::User;
pub struct SelectedContext<'a> { pub struct SelectedContext<'a> {
pub req: &'a Command<'static>, pub req: &'a Command<'static>,

View file

@ -5,8 +5,9 @@ use std::sync::Arc;
use imap_codec::imap_types::core::Tag; use imap_codec::imap_types::core::Tag;
use tokio::sync::Notify; use tokio::sync::Notify;
use aero_collections::user::User;
use crate::imap::mailbox_view::MailboxView; use crate::imap::mailbox_view::MailboxView;
use crate::user::User;
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {

View file

@ -3,8 +3,8 @@ use std::num::{NonZeroU32, NonZeroU64};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use imap_codec::imap_types::sequence::{SeqOrUid, Sequence, SequenceSet}; use imap_codec::imap_types::sequence::{SeqOrUid, Sequence, SequenceSet};
use crate::mail::uidindex::{ImapUid, ModSeq, UidIndex}; use aero_collections::mail::uidindex::{ImapUid, ModSeq, UidIndex};
use crate::mail::unique_ident::UniqueIdent; use aero_collections::mail::unique_ident::UniqueIdent;
pub struct Index<'a> { pub struct Index<'a> {
pub imap_index: Vec<MailIndex<'a>>, pub imap_index: Vec<MailIndex<'a>>,

View file

@ -16,7 +16,7 @@ use eml_codec::{
part::{composite::Message, AnyPart}, part::{composite::Message, AnyPart},
}; };
use crate::mail::query::QueryResult; use aero_collections::mail::query::QueryResult;
use crate::imap::attributes::AttributesProxy; use crate::imap::attributes::AttributesProxy;
use crate::imap::flags; use crate::imap::flags;

View file

@ -6,18 +6,18 @@ use anyhow::{anyhow, Error, Result};
use futures::stream::{StreamExt, TryStreamExt}; use futures::stream::{StreamExt, TryStreamExt};
use imap_codec::imap_types::core::{Charset, Vec1}; use imap_codec::imap_types::core::Charset;
use imap_codec::imap_types::fetch::MessageDataItem; use imap_codec::imap_types::fetch::MessageDataItem;
use imap_codec::imap_types::flag::{Flag, FlagFetch, FlagPerm, StoreResponse, StoreType}; use imap_codec::imap_types::flag::{Flag, FlagFetch, FlagPerm, StoreResponse, StoreType};
use imap_codec::imap_types::response::{Code, CodeOther, Data, Status}; use imap_codec::imap_types::response::{Code, CodeOther, Data, Status};
use imap_codec::imap_types::search::SearchKey; use imap_codec::imap_types::search::SearchKey;
use imap_codec::imap_types::sequence::SequenceSet; use imap_codec::imap_types::sequence::SequenceSet;
use crate::mail::mailbox::Mailbox; use aero_collections::mail::mailbox::Mailbox;
use crate::mail::query::QueryScope; use aero_collections::mail::query::QueryScope;
use crate::mail::snapshot::FrozenMailbox; use aero_collections::mail::snapshot::FrozenMailbox;
use crate::mail::uidindex::{ImapUid, ImapUidvalidity, ModSeq}; use aero_collections::mail::uidindex::{ImapUid, ImapUidvalidity, ModSeq};
use crate::mail::unique_ident::UniqueIdent; use aero_collections::mail::unique_ident::UniqueIdent;
use crate::imap::attributes::AttributesProxy; use crate::imap::attributes::AttributesProxy;
use crate::imap::flags; use crate::imap::flags;

View file

@ -384,6 +384,8 @@ impl<'a> NodeMsg<'a> {
}) })
} }
} }
#[allow(dead_code)]
struct NodeMult<'a>(&'a NodeMime<'a>, &'a composite::Multipart<'a>); struct NodeMult<'a>(&'a NodeMime<'a>, &'a composite::Multipart<'a>);
impl<'a> NodeMult<'a> { impl<'a> NodeMult<'a> {
fn structure(&self, is_ext: bool) -> Result<BodyStructure<'static>> { fn structure(&self, is_ext: bool) -> Result<BodyStructure<'static>> {

View file

@ -15,13 +15,11 @@ mod session;
use std::net::SocketAddr; use std::net::SocketAddr;
use anyhow::{anyhow, bail, Context, Result}; use anyhow::{anyhow, bail, Result};
use futures::stream::{FuturesUnordered, StreamExt}; use futures::stream::{FuturesUnordered, StreamExt};
use tokio::net::TcpListener; use tokio::net::TcpListener;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio::sync::watch; use tokio::sync::watch;
use imap_codec::imap_types::response::{Code, CommandContinuationRequest, Response, Status}; use imap_codec::imap_types::response::{Code, CommandContinuationRequest, Response, Status};
use imap_codec::imap_types::{core::Text, response::Greeting}; use imap_codec::imap_types::{core::Text, response::Greeting};
use imap_flow::server::{ServerFlow, ServerFlowEvent, ServerFlowOptions}; use imap_flow::server::{ServerFlow, ServerFlowEvent, ServerFlowOptions};
@ -29,12 +27,13 @@ use imap_flow::stream::AnyStream;
use rustls_pemfile::{certs, private_key}; use rustls_pemfile::{certs, private_key};
use tokio_rustls::TlsAcceptor; use tokio_rustls::TlsAcceptor;
use crate::config::{ImapConfig, ImapUnsecureConfig}; use aero_user::config::{ImapConfig, ImapUnsecureConfig};
use aero_user::login::ArcLoginProvider;
use crate::imap::capability::ServerCapability; use crate::imap::capability::ServerCapability;
use crate::imap::request::Request; use crate::imap::request::Request;
use crate::imap::response::{Body, ResponseOrIdle}; use crate::imap::response::{Body, ResponseOrIdle};
use crate::imap::session::Instance; use crate::imap::session::Instance;
use crate::login::ArcLoginProvider;
/// Server is a thin wrapper to register our Services in BàL /// Server is a thin wrapper to register our Services in BàL
pub struct Server { pub struct Server {
@ -140,7 +139,6 @@ impl Server {
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::mpsc::*; use tokio::sync::mpsc::*;
use tokio::sync::Notify; use tokio::sync::Notify;
use tokio_util::bytes::BytesMut;
const PIPELINABLE_COMMANDS: usize = 64; const PIPELINABLE_COMMANDS: usize = 64;
@ -325,8 +323,6 @@ impl NetLoop {
self.server.enqueue_status(Status::bye(None, "Internal session exited").unwrap()); self.server.enqueue_status(Status::bye(None, "Internal session exited").unwrap());
tracing::error!("session task exited for {:?}, quitting", self.ctx.addr); tracing::error!("session task exited for {:?}, quitting", self.ctx.addr);
}, },
Some(_) => unreachable!(),
}, },
// When receiving a CTRL+C // When receiving a CTRL+C

View file

@ -4,9 +4,10 @@ use imap_codec::imap_types::core::Vec1;
use imap_codec::imap_types::search::{MetadataItemSearch, SearchKey}; use imap_codec::imap_types::search::{MetadataItemSearch, SearchKey};
use imap_codec::imap_types::sequence::{SeqOrUid, Sequence, SequenceSet}; use imap_codec::imap_types::sequence::{SeqOrUid, Sequence, SequenceSet};
use aero_collections::mail::query::QueryScope;
use crate::imap::index::MailIndex; use crate::imap::index::MailIndex;
use crate::imap::mail_view::MailView; use crate::imap::mail_view::MailView;
use crate::mail::query::QueryScope;
pub enum SeqType { pub enum SeqType {
Undefined, Undefined,

View file

@ -1,11 +1,13 @@
use anyhow::{anyhow, bail, Context, Result};
use imap_codec::imap_types::{command::Command, core::Tag};
use aero_user::login::ArcLoginProvider;
use crate::imap::capability::{ClientCapability, ServerCapability}; use crate::imap::capability::{ClientCapability, ServerCapability};
use crate::imap::command::{anonymous, authenticated, selected}; use crate::imap::command::{anonymous, authenticated, selected};
use crate::imap::flow; use crate::imap::flow;
use crate::imap::request::Request; use crate::imap::request::Request;
use crate::imap::response::{Response, ResponseOrIdle}; use crate::imap::response::{Response, ResponseOrIdle};
use crate::login::ArcLoginProvider;
use anyhow::{anyhow, bail, Context, Result};
use imap_codec::imap_types::{command::Command, core::Tag};
//----- //-----
pub struct Instance { pub struct Instance {

6
aero-proto/src/lib.rs Normal file
View file

@ -0,0 +1,6 @@
#![feature(async_closure)]
pub mod dav;
pub mod imap;
pub mod lmtp;
pub mod sasl;

View file

@ -10,18 +10,16 @@ use futures::{
stream::{FuturesOrdered, FuturesUnordered}, stream::{FuturesOrdered, FuturesUnordered},
StreamExt, StreamExt,
}; };
use log::*;
use tokio::net::TcpListener; use tokio::net::TcpListener;
use tokio::select; use tokio::select;
use tokio::sync::watch; use tokio::sync::watch;
use tokio_util::compat::*; use tokio_util::compat::*;
use smtp_message::{DataUnescaper, Email, EscapedDataReader, Reply, ReplyCode}; use smtp_message::{DataUnescaper, Email, EscapedDataReader, Reply, ReplyCode};
use smtp_server::{reply, Config, ConnectionMetadata, Decision, MailMetadata}; use smtp_server::{reply, Config, ConnectionMetadata, Decision, MailMetadata};
use crate::config::*; use aero_user::config::*;
use crate::login::*; use aero_user::login::*;
use crate::mail::incoming::EncryptedMessage; use aero_collections::mail::incoming::EncryptedMessage;
pub struct LmtpServer { pub struct LmtpServer {
bind_addr: SocketAddr, bind_addr: SocketAddr,
@ -43,7 +41,7 @@ impl LmtpServer {
pub async fn run(self: &Arc<Self>, mut must_exit: watch::Receiver<bool>) -> Result<()> { pub async fn run(self: &Arc<Self>, mut must_exit: watch::Receiver<bool>) -> Result<()> {
let tcp = TcpListener::bind(self.bind_addr).await?; let tcp = TcpListener::bind(self.bind_addr).await?;
info!("LMTP server listening on {:#}", self.bind_addr); tracing::info!("LMTP server listening on {:#}", self.bind_addr);
let mut connections = FuturesUnordered::new(); let mut connections = FuturesUnordered::new();
@ -60,7 +58,7 @@ impl LmtpServer {
_ = wait_conn_finished => continue, _ = wait_conn_finished => continue,
_ = must_exit.changed() => continue, _ = must_exit.changed() => continue,
}; };
info!("LMTP: accepted connection from {}", remote_addr); tracing::info!("LMTP: accepted connection from {}", remote_addr);
let conn = tokio::spawn(smtp_server::interact( let conn = tokio::spawn(smtp_server::interact(
socket.compat(), socket.compat(),
@ -73,7 +71,7 @@ impl LmtpServer {
} }
drop(tcp); drop(tcp);
info!("LMTP server shutting down, draining remaining connections..."); tracing::info!("LMTP server shutting down, draining remaining connections...");
while connections.next().await.is_some() {} while connections.next().await.is_some() {}
Ok(()) Ok(())

View file

@ -6,10 +6,11 @@ use tokio::io::BufStream;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt}; use tokio::io::{AsyncBufReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream}; use tokio::net::{TcpListener, TcpStream};
use tokio::sync::watch; use tokio::sync::watch;
use tokio_util::bytes::BytesMut;
use aero_user::config::AuthConfig; use aero_user::config::AuthConfig;
use aero_user::login::ArcLoginProvider; use aero_user::login::ArcLoginProvider;
use aero_sasl::{flow::State, decode::client_command, encode::Encode};
pub struct AuthServer { pub struct AuthServer {
login_provider: ArcLoginProvider, login_provider: ArcLoginProvider,
@ -108,7 +109,8 @@ impl NetLoop {
tracing::trace!(cmd=?cmd, "Received command"); tracing::trace!(cmd=?cmd, "Received command");
// Make some progress in our local state // Make some progress in our local state
self.state.progress(cmd, &self.login).await; let login = async |user: String, pass: String| self.login.login(user.as_str(), pass.as_str()).await.is_ok();
self.state.progress(cmd, login).await;
if matches!(self.state, State::Error) { if matches!(self.state, State::Error) {
bail!("Internal state is in error, previous logs explain what went wrong"); bail!("Internal state is in error, previous logs explain what went wrong");
} }

View file

@ -28,9 +28,9 @@ impl State {
Self::Init Self::Init
} }
async fn try_auth_plain<'a, X, F>(&self, data: &'a [u8], login: X) -> AuthRes async fn try_auth_plain<X, F>(&self, data: &[u8], login: X) -> AuthRes
where where
X: FnOnce(&'a str, &'a str) -> F, X: FnOnce(String, String) -> F,
F: Future<Output=bool>, F: Future<Output=bool>,
{ {
// Check that we can extract user's login+pass // Check that we can extract user's login+pass
@ -56,7 +56,7 @@ impl State {
}; };
// Try to connect user // Try to connect user
match login(user, password).await { match login(user.to_string(), password.to_string()).await {
true => AuthRes::Success(user.to_string()), true => AuthRes::Success(user.to_string()),
false => { false => {
tracing::warn!("login failed"); tracing::warn!("login failed");
@ -67,7 +67,7 @@ impl State {
pub async fn progress<F,X>(&mut self, cmd: ClientCommand, login: X) pub async fn progress<F,X>(&mut self, cmd: ClientCommand, login: X)
where where
X: FnOnce(&str, &str) -> F, X: FnOnce(String, String) -> F,
F: Future<Output=bool>, F: Future<Output=bool>,
{ {
let new_state = 'state: { let new_state = 'state: {