use std::{error, fmt, num::ParseIntError, result};
#[cfg(feature = "pop")]
use async_pop::error::Error as PopError;
#[cfg(feature = "imap")]
use async_imap::error::Error as ImapError;
#[cfg(feature = "smtp")]
use async_smtp::error::Error as SmtpError;
use async_native_tls::Error as TlsError;
use chrono::ParseError as ParseTimeError;
use email::results::ParsingError as AddressParseError;
use mailparse::MailParseError;
#[cfg(feature = "runtime-tokio")]
use tokio::io::Error as IoError;
#[cfg(feature = "runtime-async-std")]
use async_std::io::Error as IoError;
macro_rules! impl_from_error {
($error_type:ty, $error_kind:expr, $error_msg:expr) => {
impl From<$error_type> for Error {
fn from(err: $error_type) -> Self {
Error::new($error_kind(err), $error_msg)
}
}
};
}
macro_rules! err {
($kind:expr, $($arg:tt)*) => {{
use crate::error::Error;
let kind = $kind;
let message = format!($($arg)*);
return Err(Error::new( kind, message ));
}};
}
#[derive(Debug)]
pub enum ErrorKind {
MessageNotFound,
UnexpectedBehavior,
Unsupported,
Io(IoError),
#[cfg(feature = "imap")]
Imap(ImapError),
#[cfg(feature = "pop")]
Pop(PopError),
#[cfg(feature = "smtp")]
Smtp(SmtpError),
Tls(TlsError),
#[cfg(feature = "maildir")]
Maildir(maildir::MaildirError),
#[cfg(feature = "maildir")]
MailEntry(maildir::MailEntryError),
#[cfg(feature = "maildir")]
Db(sled::Error),
ParseTime(ParseTimeError),
ParseInt(ParseIntError),
ParseAddress,
InvalidLoginConfig,
ParseMessage(MailParseError),
InvalidMessage,
MailServer,
SerializeJSON,
ConfigNotFound,
ParseEmailAddress(AddressParseError),
MailBoxNotFound,
NoClientAvailable,
}
#[derive(Debug)]
pub struct Error {
message: String,
kind: ErrorKind,
}
impl Error {
pub fn new<S: Into<String>>(kind: ErrorKind, msg: S) -> Self {
Self {
message: msg.into(),
kind,
}
}
pub fn kind(&self) -> &ErrorKind {
&self.kind
}
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self.kind() {
#[cfg(feature = "pop")]
ErrorKind::Pop(e) => e.source(),
#[cfg(feature = "imap")]
ErrorKind::Imap(e) => e.source(),
ErrorKind::Io(e) => e.source(),
ErrorKind::Tls(e) => e.source(),
ErrorKind::ParseMessage(e) => e.source(),
_ => None,
}
}
}
#[cfg(feature = "pop")]
impl_from_error!(PopError, |err| ErrorKind::Pop(err), "Error from pop server");
#[cfg(feature = "imap")]
impl_from_error!(
ImapError,
|err| ErrorKind::Imap(err),
"Error from imap server"
);
#[cfg(feature = "smtp")]
impl_from_error!(
SmtpError,
|err| ErrorKind::Smtp(err),
"Error from smtp server"
);
impl_from_error!(
TlsError,
|err| ErrorKind::Tls(err),
"Error creating a secure connection"
);
impl_from_error!(IoError, |err| ErrorKind::Io(err), "Io operation failed");
impl_from_error!(
ParseTimeError,
|err| ErrorKind::ParseTime(err),
"Failed to parse date time"
);
impl_from_error!(
MailParseError,
|err| ErrorKind::ParseMessage(err),
"Failed to parse mail message"
);
impl_from_error!(
AddressParseError,
|err| ErrorKind::ParseEmailAddress(err),
"Failed to parse email address"
);
impl_from_error!(
ParseIntError,
|err| ErrorKind::ParseInt(err),
"Failed to parse integer value from string"
);
#[cfg(feature = "maildir")]
impl_from_error!(
maildir::MaildirError,
|err| ErrorKind::Maildir(err),
"Failed to store email in local directory"
);
#[cfg(feature = "maildir")]
impl_from_error!(
maildir::MailEntryError,
|err| ErrorKind::MailEntry(err),
"Failed to retrieve email from local directory"
);
#[cfg(feature = "maildir")]
impl_from_error!(
sled::Error,
|err| ErrorKind::Db(err),
"Failed to interact with sled database"
);
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.message)
}
}
pub(crate) use err;
pub type Result<T> = result::Result<T, Error>;