Re-enable proto
This commit is contained in:
parent
1edf0b15ec
commit
11462f80c4
32 changed files with 992 additions and 132 deletions
929
Cargo.lock
generated
929
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||||
|
|
|
@ -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!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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?;
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
||||||
|
|
|
@ -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
35
aero-proto/Cargo.toml
Normal 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
|
|
@ -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!();
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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");
|
|
@ -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
|
|
@ -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>,
|
|
@ -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 {
|
|
@ -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>>,
|
|
@ -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;
|
|
@ -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;
|
|
@ -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>> {
|
|
@ -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
|
|
@ -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,
|
|
@ -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
6
aero-proto/src/lib.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#![feature(async_closure)]
|
||||||
|
|
||||||
|
pub mod dav;
|
||||||
|
pub mod imap;
|
||||||
|
pub mod lmtp;
|
||||||
|
pub mod sasl;
|
|
@ -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(())
|
|
@ -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");
|
||||||
}
|
}
|
|
@ -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: {
|
||||||
|
|
Loading…
Reference in a new issue