Mechanisms as bit sets.

This commit is contained in:
Mauro D 2022-12-09 17:33:10 +00:00
parent e7df79ef68
commit 5765b4b9fe
6 changed files with 164 additions and 176 deletions

6
.gitignore vendored
View file

@ -8,9 +8,3 @@ Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# Added by cargo
/target
/Cargo.lock

View file

@ -3,9 +3,6 @@ name = "smtp-proto"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[dev-dependencies]
csv = "1.1"

View file

@ -27,7 +27,7 @@ pub enum Request<T> {
is_last: bool,
},
Auth {
mechanism: Mechanism,
mechanism: u64,
initial_response: T,
},
Noop {
@ -122,60 +122,55 @@ pub const NOTIFY_SUCCESS: u8 = 0x01;
pub const NOTIFY_FAILURE: u8 = 0x02;
pub const NOTIFY_DELAY: u8 = 0x04;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Mechanism {
_9798MDsaSha1,
_9798MEcdsaSha1,
_9798MRsaSha1Enc,
_9798UDsaSha1,
_9798UEcdsaSha1,
_9798URsaSha1Enc,
Anonymous,
CramMd5,
DigestMd5,
EapAes128,
EapAes128Plus,
EcdhX25519Challenge,
EcdsaNist256pChallenge,
External,
Gs2Krb5,
Gs2Krb5Plus,
GssSpnego,
Gssapi,
KerberosV4,
KerberosV5,
Login,
NmasSambaAuth,
NmasAuthen,
NmasLogin,
Ntlm,
Oauth10a,
Oauthbearer,
Openid20,
Otp,
Plain,
Saml20,
ScramSha1,
ScramSha1Plus,
ScramSha256,
ScramSha256Plus,
Securid,
Skey,
Spnego,
SpnegoPlus,
SxoverPlus,
Xoauth,
Xoauth2,
// Unknown
Unknown,
}
pub const AUTH_SCRAM_SHA_256_PLUS: u64 = 1u64 << 0;
pub const AUTH_SCRAM_SHA_256: u64 = 1u64 << 1;
pub const AUTH_SCRAM_SHA_1_PLUS: u64 = 1u64 << 2;
pub const AUTH_SCRAM_SHA_1: u64 = 1u64 << 3;
pub const AUTH_OAUTHBEARER: u64 = 1u64 << 4;
pub const AUTH_XOAUTH: u64 = 1u64 << 5;
pub const AUTH_XOAUTH2: u64 = 1u64 << 6;
pub const AUTH_9798_M_DSA_SHA1: u64 = 1u64 << 7;
pub const AUTH_9798_M_ECDSA_SHA1: u64 = 1u64 << 8;
pub const AUTH_9798_M_RSA_SHA1_ENC: u64 = 1u64 << 9;
pub const AUTH_9798_U_DSA_SHA1: u64 = 1u64 << 10;
pub const AUTH_9798_U_ECDSA_SHA1: u64 = 1u64 << 11;
pub const AUTH_9798_U_RSA_SHA1_ENC: u64 = 1u64 << 12;
pub const AUTH_EAP_AES128: u64 = 1u64 << 13;
pub const AUTH_EAP_AES128_PLUS: u64 = 1u64 << 14;
pub const AUTH_ECDH_X25519_CHALLENGE: u64 = 1u64 << 15;
pub const AUTH_ECDSA_NIST256P_CHALLENGE: u64 = 1u64 << 16;
pub const AUTH_EXTERNAL: u64 = 1u64 << 17;
pub const AUTH_GS2_KRB5: u64 = 1u64 << 18;
pub const AUTH_GS2_KRB5_PLUS: u64 = 1u64 << 19;
pub const AUTH_GSS_SPNEGO: u64 = 1u64 << 20;
pub const AUTH_GSSAPI: u64 = 1u64 << 21;
pub const AUTH_KERBEROS_V4: u64 = 1u64 << 22;
pub const AUTH_KERBEROS_V5: u64 = 1u64 << 23;
pub const AUTH_NMAS_SAMBA_AUTH: u64 = 1u64 << 24;
pub const AUTH_NMAS_AUTHEN: u64 = 1u64 << 25;
pub const AUTH_NMAS_LOGIN: u64 = 1u64 << 26;
pub const AUTH_NTLM: u64 = 1u64 << 27;
pub const AUTH_OAUTH10A: u64 = 1u64 << 28;
pub const AUTH_OPENID20: u64 = 1u64 << 29;
pub const AUTH_OTP: u64 = 1u64 << 30;
pub const AUTH_SAML20: u64 = 1u64 << 31;
pub const AUTH_SECURID: u64 = 1u64 << 32;
pub const AUTH_SKEY: u64 = 1u64 << 33;
pub const AUTH_SPNEGO: u64 = 1u64 << 34;
pub const AUTH_SPNEGO_PLUS: u64 = 1u64 << 35;
pub const AUTH_SXOVER_PLUS: u64 = 1u64 << 36;
pub const AUTH_CRAM_MD5: u64 = 1u64 << 37;
pub const AUTH_DIGEST_MD5: u64 = 1u64 << 38;
pub const AUTH_LOGIN: u64 = 1u64 << 39;
pub const AUTH_PLAIN: u64 = 1u64 << 40;
pub const AUTH_ANONYMOUS: u64 = 1u64 << 41;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Capability {
EightBitMime,
Atrn,
Auth {
mechanisms: Vec<Mechanism>,
mechanisms: u64,
},
BinaryMime,
Burl,
@ -219,6 +214,7 @@ pub enum MtPriority {
Mixer,
Stanag4406,
Nsep,
None,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@ -279,6 +275,7 @@ impl IntoString for Vec<u8> {
}
}
/*
#[cfg(test)]
mod tests {
@ -316,3 +313,4 @@ mod tests {
}
}
}
*/

View file

@ -1,9 +1,6 @@
use std::slice::Iter;
use crate::{
Body, By, Error, IntoString, Mechanism, Mtrk, Orcpt, Parameter, Request, Ret, Rrvs, LF,
NOTIFY_DELAY, NOTIFY_FAILURE, NOTIFY_SUCCESS, SP,
};
use crate::*;
use super::{receiver::ReceiverParser, *};
@ -1046,7 +1043,7 @@ impl<'x, 'y> Rfc5321Parser<'x, 'y> {
Ok(params)
}
pub(crate) fn mechanism(&mut self) -> Result<Option<Mechanism>, Error> {
pub(crate) fn mechanism(&mut self) -> Result<Option<u64>, Error> {
let mut trailing_chars = [0u8; 8];
let mut pos = 0;
let mechanism = self.hashed_value_long()?;
@ -1069,54 +1066,54 @@ impl<'x, 'y> Rfc5321Parser<'x, 'y> {
bytes_left: self.bytes_left,
});
} else if pos > 8 {
return Ok(Mechanism::Unknown.into());
return Ok(0.into());
}
}
Ok(match (mechanism, &trailing_chars[..pos]) {
(_9798_M_DSA_SHA1, b"") => Mechanism::_9798MDsaSha1.into(),
(_9798_M_ECDSA_SHA, b"1") => Mechanism::_9798MEcdsaSha1.into(),
(_9798_M_RSA_SHA1_, b"ENC") => Mechanism::_9798MRsaSha1Enc.into(),
(_9798_U_DSA_SHA1, b"") => Mechanism::_9798UDsaSha1.into(),
(_9798_U_ECDSA_SHA, b"1") => Mechanism::_9798UEcdsaSha1.into(),
(_9798_U_RSA_SHA1_, b"ENC") => Mechanism::_9798URsaSha1Enc.into(),
(ANONYMOUS, b"") => Mechanism::Anonymous.into(),
(CRAM_MD5, b"") => Mechanism::CramMd5.into(),
(DIGEST_MD5, b"") => Mechanism::DigestMd5.into(),
(EAP_AES128, b"") => Mechanism::EapAes128.into(),
(EAP_AES128_PLUS, b"") => Mechanism::EapAes128Plus.into(),
(ECDH_X25519_CHAL, b"LENGE") => Mechanism::EcdhX25519Challenge.into(),
(ECDSA_NIST256P_C, b"HALLENGE") => Mechanism::EcdsaNist256pChallenge.into(),
(EXTERNAL, b"") => Mechanism::External.into(),
(GS2_KRB5, b"") => Mechanism::Gs2Krb5.into(),
(GS2_KRB5_PLUS, b"") => Mechanism::Gs2Krb5Plus.into(),
(GSS_SPNEGO, b"") => Mechanism::GssSpnego.into(),
(GSSAPI, b"") => Mechanism::Gssapi.into(),
(KERBEROS_V4, b"") => Mechanism::KerberosV4.into(),
(KERBEROS_V5, b"") => Mechanism::KerberosV5.into(),
(LOGIN, b"") => Mechanism::Login.into(),
(NMAS_SAMBA_AUTH, b"") => Mechanism::NmasSambaAuth.into(),
(NMAS_AUTHEN, b"") => Mechanism::NmasAuthen.into(),
(NMAS_LOGIN, b"") => Mechanism::NmasLogin.into(),
(NTLM, b"") => Mechanism::Ntlm.into(),
(OAUTH10A, b"") => Mechanism::Oauth10a.into(),
(OAUTHBEARER, b"") => Mechanism::Oauthbearer.into(),
(OPENID20, b"") => Mechanism::Openid20.into(),
(OTP, b"") => Mechanism::Otp.into(),
(PLAIN, b"") => Mechanism::Plain.into(),
(SAML20, b"") => Mechanism::Saml20.into(),
(SCRAM_SHA_1, b"") => Mechanism::ScramSha1.into(),
(SCRAM_SHA_1_PLUS, b"") => Mechanism::ScramSha1Plus.into(),
(SCRAM_SHA_256, b"") => Mechanism::ScramSha256.into(),
(SCRAM_SHA_256_PL, b"US") => Mechanism::ScramSha256Plus.into(),
(SECURID, b"") => Mechanism::Securid.into(),
(SKEY, b"") => Mechanism::Skey.into(),
(SPNEGO, b"") => Mechanism::Spnego.into(),
(SPNEGO_PLUS, b"") => Mechanism::SpnegoPlus.into(),
(SXOVER_PLUS, b"") => Mechanism::SxoverPlus.into(),
(XOAUTH, b"") => Mechanism::Xoauth.into(),
(XOAUTH2, b"") => Mechanism::Xoauth2.into(),
(_9798_M_DSA_SHA1, b"") => AUTH_9798_M_DSA_SHA1.into(),
(_9798_M_ECDSA_SHA, b"1") => AUTH_9798_M_ECDSA_SHA1.into(),
(_9798_M_RSA_SHA1_, b"ENC") => AUTH_9798_M_RSA_SHA1_ENC.into(),
(_9798_U_DSA_SHA1, b"") => AUTH_9798_U_DSA_SHA1.into(),
(_9798_U_ECDSA_SHA, b"1") => AUTH_9798_U_ECDSA_SHA1.into(),
(_9798_U_RSA_SHA1_, b"ENC") => AUTH_9798_U_RSA_SHA1_ENC.into(),
(ANONYMOUS, b"") => AUTH_ANONYMOUS.into(),
(CRAM_MD5, b"") => AUTH_CRAM_MD5.into(),
(DIGEST_MD5, b"") => AUTH_DIGEST_MD5.into(),
(EAP_AES128, b"") => AUTH_EAP_AES128.into(),
(EAP_AES128_PLUS, b"") => AUTH_EAP_AES128_PLUS.into(),
(ECDH_X25519_CHAL, b"LENGE") => AUTH_ECDH_X25519_CHALLENGE.into(),
(ECDSA_NIST256P_C, b"HALLENGE") => AUTH_ECDSA_NIST256P_CHALLENGE.into(),
(EXTERNAL, b"") => AUTH_EXTERNAL.into(),
(GS2_KRB5, b"") => AUTH_GS2_KRB5.into(),
(GS2_KRB5_PLUS, b"") => AUTH_GS2_KRB5_PLUS.into(),
(GSS_SPNEGO, b"") => AUTH_GSS_SPNEGO.into(),
(GSSAPI, b"") => AUTH_GSSAPI.into(),
(KERBEROS_V4, b"") => AUTH_KERBEROS_V4.into(),
(KERBEROS_V5, b"") => AUTH_KERBEROS_V5.into(),
(LOGIN, b"") => AUTH_LOGIN.into(),
(NMAS_SAMBA_AUTH, b"") => AUTH_NMAS_SAMBA_AUTH.into(),
(NMAS_AUTHEN, b"") => AUTH_NMAS_AUTHEN.into(),
(NMAS_LOGIN, b"") => AUTH_NMAS_LOGIN.into(),
(NTLM, b"") => AUTH_NTLM.into(),
(OAUTH10A, b"") => AUTH_OAUTH10A.into(),
(OAUTHBEARER, b"") => AUTH_OAUTHBEARER.into(),
(OPENID20, b"") => AUTH_OPENID20.into(),
(OTP, b"") => AUTH_OTP.into(),
(PLAIN, b"") => AUTH_PLAIN.into(),
(SAML20, b"") => AUTH_SAML20.into(),
(SCRAM_SHA_1, b"") => AUTH_SCRAM_SHA_1.into(),
(SCRAM_SHA_1_PLUS, b"") => AUTH_SCRAM_SHA_1_PLUS.into(),
(SCRAM_SHA_256, b"") => AUTH_SCRAM_SHA_256.into(),
(SCRAM_SHA_256_PL, b"US") => AUTH_SCRAM_SHA_256_PLUS.into(),
(SECURID, b"") => AUTH_SECURID.into(),
(SKEY, b"") => AUTH_SKEY.into(),
(SPNEGO, b"") => AUTH_SPNEGO.into(),
(SPNEGO_PLUS, b"") => AUTH_SPNEGO_PLUS.into(),
(SXOVER_PLUS, b"") => AUTH_SXOVER_PLUS.into(),
(XOAUTH, b"") => AUTH_XOAUTH.into(),
(XOAUTH2, b"") => AUTH_XOAUTH2.into(),
(0, b"") => None,
_ => Mechanism::Unknown.into(),
_ => 0.into(),
})
}
}
@ -1137,8 +1134,9 @@ impl TryFrom<u128> for Body {
#[cfg(test)]
mod tests {
use crate::{
request::receiver::ReceiverParser, Body, By, Error, Mechanism, Mtrk, Orcpt, Parameter,
Request, Ret, Rrvs, NOTIFY_DELAY, NOTIFY_FAILURE, NOTIFY_SUCCESS,
request::receiver::ReceiverParser, Body, By, Error, Mtrk, Orcpt, Parameter, Request, Ret,
Rrvs, AUTH_ECDSA_NIST256P_CHALLENGE, AUTH_GSSAPI, AUTH_SCRAM_SHA_256_PLUS, NOTIFY_DELAY,
NOTIFY_FAILURE, NOTIFY_SUCCESS,
};
#[test]
@ -1312,28 +1310,28 @@ mod tests {
(
"AUTH GSSAPI",
Ok(Request::Auth {
mechanism: Mechanism::Gssapi,
mechanism: AUTH_GSSAPI,
initial_response: "".to_string(),
}),
),
(
"AUTH ECDSA-NIST256P-CHALLENGE =",
Ok(Request::Auth {
mechanism: Mechanism::EcdsaNist256pChallenge,
mechanism: AUTH_ECDSA_NIST256P_CHALLENGE,
initial_response: "=".to_string(),
}),
),
(
"AUTH SCRAM-SHA-256-PLUS base64_goes_here",
Ok(Request::Auth {
mechanism: Mechanism::ScramSha256Plus,
mechanism: AUTH_SCRAM_SHA_256_PLUS,
initial_response: "base64_goes_here".to_string(),
}),
),
(
"AUTH ECDSA-NIST256P-CHALLENGE100 abcde",
Ok(Request::Auth {
mechanism: Mechanism::Unknown,
mechanism: 0,
initial_response: "abcde".to_string(),
}),
),

View file

@ -3,7 +3,7 @@ use std::{
io::{self, Write},
};
use crate::{Capability, Category, EhloResponse, Mechanism, MtPriority, Response, Severity};
use crate::*;
impl<T: Display> EhloResponse<T> {
pub fn write(&self, mut writer: impl Write) -> io::Result<()> {
@ -17,8 +17,11 @@ impl<T: Display> EhloResponse<T> {
Capability::Atrn => write!(writer, "ATRN\r\n"),
Capability::Auth { mechanisms } => {
writer.write_all(b"AUTH")?;
for mechanism in mechanisms {
write!(writer, " {}", mechanism)?;
let mut mechanisms = *mechanisms;
while mechanisms != 0 {
let item = 63 - mechanisms.leading_zeros();
mechanisms ^= 1 << item;
write!(writer, " {}", (item as u64).as_mechanism())?;
}
writer.write_all(b"\r\n")
}
@ -55,6 +58,7 @@ impl<T: Display> EhloResponse<T> {
MtPriority::Mixer => "MIXER",
MtPriority::Stanag4406 => "STANAG4406",
MtPriority::Nsep => "NSEP",
MtPriority::None => "MIXER",
}
),
Capability::Mtrk => write!(writer, "MTRK\r\n"),
@ -102,53 +106,57 @@ impl<T: Display> Response<T> {
}
}
impl Display for Mechanism {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Mechanism::_9798MDsaSha1 => "9798-M-DSA-SHA1",
Mechanism::_9798MEcdsaSha1 => "9798-M-ECDSA-SHA1",
Mechanism::_9798MRsaSha1Enc => "9798-M-RSA-SHA1-ENC",
Mechanism::_9798UDsaSha1 => "9798-U-DSA-SHA1",
Mechanism::_9798UEcdsaSha1 => "9798-U-ECDSA-SHA1",
Mechanism::_9798URsaSha1Enc => "9798-U-RSA-SHA1-ENC",
Mechanism::Anonymous => "ANONYMOUS",
Mechanism::CramMd5 => "CRAM-MD5",
Mechanism::DigestMd5 => "DIGEST-MD5",
Mechanism::EapAes128 => "EAP-AES128",
Mechanism::EapAes128Plus => "EAP-AES128-PLUS",
Mechanism::EcdhX25519Challenge => "ECDH-X25519-CHALLENGE",
Mechanism::EcdsaNist256pChallenge => "ECDSA-NIST256P-CHALLENGE",
Mechanism::External => "EXTERNAL",
Mechanism::Gs2Krb5 => "GS2-KRB5",
Mechanism::Gs2Krb5Plus => "GS2-KRB5-PLUS",
Mechanism::GssSpnego => "GSS-SPNEGO",
Mechanism::Gssapi => "GSSAPI",
Mechanism::KerberosV4 => "KERBEROS_V4",
Mechanism::KerberosV5 => "KERBEROS_V5",
Mechanism::Login => "LOGIN",
Mechanism::NmasSambaAuth => "NMAS-SAMBA-AUTH",
Mechanism::NmasAuthen => "NMAS_AUTHEN",
Mechanism::NmasLogin => "NMAS_LOGIN",
Mechanism::Ntlm => "NTLM",
Mechanism::Oauth10a => "OAUTH10A",
Mechanism::Oauthbearer => "OAUTHBEARER",
Mechanism::Openid20 => "OPENID20",
Mechanism::Otp => "OTP",
Mechanism::Plain => "PLAIN",
Mechanism::Saml20 => "SAML20",
Mechanism::ScramSha1 => "SCRAM-SHA-1",
Mechanism::ScramSha1Plus => "SCRAM-SHA-1-PLUS",
Mechanism::ScramSha256 => "SCRAM-SHA-256",
Mechanism::ScramSha256Plus => "SCRAM-SHA-256-PLUS",
Mechanism::Securid => "SECURID",
Mechanism::Skey => "SKEY",
Mechanism::Spnego => "SPNEGO",
Mechanism::SpnegoPlus => "SPNEGO-PLUS",
Mechanism::SxoverPlus => "SXOVER-PLUS",
Mechanism::Xoauth => "XOAUTH",
Mechanism::Xoauth2 => "XOAUTH2",
Mechanism::Unknown => "",
})
trait AsMechanism {
fn as_mechanism(&self) -> &'static str;
}
impl AsMechanism for u64 {
fn as_mechanism(&self) -> &'static str {
match *self {
AUTH_SCRAM_SHA_256_PLUS => "SCRAM-SHA-256-PLUS",
AUTH_SCRAM_SHA_256 => "SCRAM-SHA-256",
AUTH_SCRAM_SHA_1_PLUS => "SCRAM-SHA-1-PLUS",
AUTH_SCRAM_SHA_1 => "SCRAM-SHA-1",
AUTH_OAUTHBEARER => "OAUTHBEARER",
AUTH_XOAUTH => "XOAUTH",
AUTH_XOAUTH2 => "XOAUTH2",
AUTH_9798_M_DSA_SHA1 => "9798-M-DSA-SHA1",
AUTH_9798_M_ECDSA_SHA1 => "9798-M-ECDSA-SHA1",
AUTH_9798_M_RSA_SHA1_ENC => "9798-M-RSA-SHA1-ENC",
AUTH_9798_U_DSA_SHA1 => "9798-U-DSA-SHA1",
AUTH_9798_U_ECDSA_SHA1 => "9798-U-ECDSA-SHA1",
AUTH_9798_U_RSA_SHA1_ENC => "9798-U-RSA-SHA1-ENC",
AUTH_EAP_AES128 => "EAP-AES128",
AUTH_EAP_AES128_PLUS => "EAP-AES128-PLUS",
AUTH_ECDH_X25519_CHALLENGE => "ECDH-X25519-CHALLENGE",
AUTH_ECDSA_NIST256P_CHALLENGE => "ECDSA-NIST256P-CHALLENGE",
AUTH_EXTERNAL => "EXTERNAL",
AUTH_GS2_KRB5 => "GS2-KRB5",
AUTH_GS2_KRB5_PLUS => "GS2-KRB5-PLUS",
AUTH_GSS_SPNEGO => "GSS-SPNEGO",
AUTH_GSSAPI => "GSSAPI",
AUTH_KERBEROS_V4 => "KERBEROS_V4",
AUTH_KERBEROS_V5 => "KERBEROS_V5",
AUTH_NMAS_SAMBA_AUTH => "NMAS-SAMBA-AUTH",
AUTH_NMAS_AUTHEN => "NMAS_AUTHEN",
AUTH_NMAS_LOGIN => "NMAS_LOGIN",
AUTH_NTLM => "NTLM",
AUTH_OAUTH10A => "OAUTH10A",
AUTH_OPENID20 => "OPENID20",
AUTH_OTP => "OTP",
AUTH_SAML20 => "SAML20",
AUTH_SECURID => "SECURID",
AUTH_SKEY => "SKEY",
AUTH_SPNEGO => "SPNEGO",
AUTH_SPNEGO_PLUS => "SPNEGO-PLUS",
AUTH_SXOVER_PLUS => "SXOVER-PLUS",
AUTH_CRAM_MD5 => "CRAM-MD5",
AUTH_DIGEST_MD5 => "DIGEST-MD5",
AUTH_LOGIN => "LOGIN",
AUTH_PLAIN => "PLAIN",
AUTH_ANONYMOUS => "ANONYMOUS",
_ => "",
}
}
}

View file

@ -57,10 +57,10 @@ impl ReceiverParser for EhloResponse<String> {
_8BITMIME => Capability::EightBitMime,
ATRN => Capability::Atrn,
AUTH => {
let mut mechanisms = Vec::new();
let mut mechanisms = 0;
while parser.stop_char != LF {
if let Some(mechanism) = parser.mechanism()? {
mechanisms.push(mechanism);
mechanisms |= mechanism;
}
}
@ -306,10 +306,7 @@ impl Capability {
} else if value.eq_ignore_ascii_case(b"ATRN") {
Capability::Atrn.into()
} else if value.eq_ignore_ascii_case(b"AUTH") {
Capability::Auth {
mechanisms: Vec::new(),
}
.into()
Capability::Auth { mechanisms: 0 }.into()
} else if value.eq_ignore_ascii_case(b"BINARYMIME") {
Capability::BinaryMime.into()
} else if value.eq_ignore_ascii_case(b"BURL") {
@ -374,8 +371,8 @@ impl Capability {
#[cfg(test)]
mod tests {
use crate::{
request::receiver::ReceiverParser, Capability, EhloResponse, Error, Mechanism, MtPriority,
Response,
request::receiver::ReceiverParser, Capability, EhloResponse, Error, MtPriority, Response,
AUTH_DIGEST_MD5, AUTH_GSSAPI, AUTH_PLAIN,
};
#[test]
@ -424,11 +421,7 @@ mod tests {
Capability::EightBitMime,
Capability::Atrn,
Capability::Auth {
mechanisms: vec![
Mechanism::Gssapi,
Mechanism::DigestMd5,
Mechanism::Plain,
],
mechanisms: AUTH_GSSAPI | AUTH_DIGEST_MD5 | AUTH_PLAIN,
},
Capability::BinaryMime,
Capability::Burl,