pub const CRLF: &[u8] = b"\r\n";
pub const MIN_RESPONSE_LENGTH: usize = 5;
pub const AUTH_REQUIRED: &[u8] = b"381 Password required\r\n";
pub const AUTH_ACCEPTED: &[u8] = b"281 Authentication accepted\r\n";
pub const AUTH_FAILED: &[u8] = b"481 Authentication failed\r\n";
pub const AUTH_REQUIRED_FOR_COMMAND: &[u8] = b"480 Authentication required\r\n";
pub const AUTH_OUT_OF_SEQUENCE: &[u8] = b"482 Authentication commands issued out of sequence\r\n";
pub const AUTH_ALREADY_AUTHENTICATED: &[u8] = b"502 Already authenticated\r\n";
pub const AUTH_UNKNOWN_SUBCOMMAND: &[u8] = b"501 Syntax error in command\r\n";
pub const PROXY_GREETING_PCR: &[u8] = b"201 NNTP Proxy Ready (Per-Command Routing)\r\n";
pub const CONNECTION_CLOSING: &[u8] = b"205 Connection closing\r\n";
pub const GOODBYE: &[u8] = b"205 Goodbye\r\n";
pub const POSTING_NOT_PERMITTED: &[u8] = b"440 Posting not permitted\r\n";
pub const BACKEND_ERROR: &[u8] = b"503 Backend error\r\n";
pub const BACKEND_UNAVAILABLE: &[u8] = b"400 Backend server unavailable\r\n";
pub const COMMAND_TOO_LONG: &[u8] = b"501 Command too long\r\n";
pub const COMMAND_SYNTAX_ERROR_RESPONSE: &[u8] = b"501 Syntax error in command\r\n";
pub const NO_SUCH_ARTICLE: &[u8] = b"430 No such article\r\n";
#[inline]
#[must_use]
pub fn greeting(message: &str) -> String {
format!("200 {message}\r\n")
}
#[inline]
#[must_use]
pub fn greeting_readonly(message: &str) -> String {
format!("201 {message}\r\n")
}
#[inline]
#[must_use]
pub fn ok_response(message: &str) -> String {
format!("200 {message}\r\n")
}
#[inline]
#[must_use]
pub fn error_response(code: u16, message: &str) -> String {
format!("{code} {message}\r\n")
}
#[inline]
#[must_use]
pub fn response(code: u16, message: &str) -> String {
format!("{code} {message}\r\n")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_constants() {
assert_eq!(CRLF, b"\r\n");
}
#[test]
fn test_greeting() {
assert_eq!(greeting("Ready"), "200 Ready\r\n");
assert_eq!(
greeting("news.example.com ready"),
"200 news.example.com ready\r\n"
);
assert_eq!(greeting_readonly("Read only"), "201 Read only\r\n");
}
#[test]
fn test_ok_response() {
assert_eq!(ok_response("OK"), "200 OK\r\n");
assert_eq!(ok_response("Command accepted"), "200 Command accepted\r\n");
}
#[test]
fn test_error_response() {
assert_eq!(
error_response(430, "No such article"),
"430 No such article\r\n"
);
assert_eq!(
error_response(500, "Command not recognized"),
"500 Command not recognized\r\n"
);
}
#[test]
fn test_response() {
assert_eq!(
response(215, "Newsgroups follow"),
"215 Newsgroups follow\r\n"
);
assert_eq!(
response(381, "Password required"),
"381 Password required\r\n"
);
}
#[test]
fn test_auth_constants() {
assert_eq!(AUTH_REQUIRED, b"381 Password required\r\n");
assert_eq!(AUTH_ACCEPTED, b"281 Authentication accepted\r\n");
assert_eq!(AUTH_FAILED, b"481 Authentication failed\r\n");
assert_eq!(
AUTH_REQUIRED_FOR_COMMAND,
b"480 Authentication required\r\n"
);
}
#[test]
fn test_standard_responses() {
assert!(PROXY_GREETING_PCR.starts_with(b"201"));
assert!(CONNECTION_CLOSING.starts_with(b"205"));
assert!(GOODBYE.starts_with(b"205"));
}
#[test]
fn test_error_constants() {
assert!(POSTING_NOT_PERMITTED.starts_with(b"440"));
assert!(BACKEND_ERROR.starts_with(b"503"));
assert!(BACKEND_UNAVAILABLE.starts_with(b"400"));
}
#[test]
fn test_all_responses_end_with_crlf() {
assert!(AUTH_REQUIRED.ends_with(CRLF));
assert!(AUTH_ACCEPTED.ends_with(CRLF));
assert!(AUTH_FAILED.ends_with(CRLF));
assert!(AUTH_REQUIRED_FOR_COMMAND.ends_with(CRLF));
assert!(PROXY_GREETING_PCR.ends_with(CRLF));
assert!(CONNECTION_CLOSING.ends_with(CRLF));
assert!(GOODBYE.ends_with(CRLF));
assert!(POSTING_NOT_PERMITTED.ends_with(CRLF));
assert!(BACKEND_ERROR.ends_with(CRLF));
assert!(BACKEND_UNAVAILABLE.ends_with(CRLF));
}
}