use crate::{
auth::UserDetail,
server::{
controlchan::{
Reply, ReplyCode,
error::ControlChanError,
handler::{CommandContext, CommandHandler},
},
ftpserver::options::SiteMd5,
},
storage::{FEATURE_RESTART, FEATURE_SITEMD5, Metadata, StorageBackend},
};
use async_trait::async_trait;
#[derive(Debug)]
pub struct Feat;
#[async_trait]
impl<Storage, User> CommandHandler<Storage, User> for Feat
where
User: UserDetail + 'static,
Storage: StorageBackend<User> + 'static,
Storage::Metadata: Metadata,
{
#[tracing_attributes::instrument]
async fn handle(&self, args: CommandContext<Storage, User>) -> Result<Reply, ControlChanError> {
let mut feat_text = vec![" SIZE", " MDTM", " UTF8", " EPSV", " MLST", " MLSD"];
if args.tls_configured {
feat_text.push(" AUTH TLS");
feat_text.push(" PBSZ");
feat_text.push(" PROT");
}
if args.storage_features & FEATURE_RESTART > 0 {
feat_text.push(" REST STREAM");
}
if args.sitemd5 != SiteMd5::None && args.storage_features & FEATURE_SITEMD5 > 0 {
feat_text.push(" SITE MD5");
}
feat_text.sort_unstable();
feat_text.insert(0, "Extensions supported:");
feat_text.push("END");
let reply = Reply::new_multiline(ReplyCode::SystemStatus, feat_text);
Ok(reply)
}
}