neo_email/
client_message.rs

1use std::fmt::Debug;
2
3use serde::{Deserialize, Serialize};
4
5use super::{command::Commands, errors::SMTPError};
6
7/// # Client Message
8///
9/// This struct represents a message from the client to the server.
10/// It contains the command and the data.
11/// Usually they are like this:
12///
13/// ```
14/// HELO example.com
15/// MAIL FROM: <...>
16/// RCPT TO: <...>
17/// DATA
18/// ...
19/// ```
20#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
21pub struct ClientMessage<T> {
22    /// The command that the client is sending.
23    pub command: Commands,
24    /// The data that the client is sending.
25    pub data: T,
26}
27
28/// # Client Message
29///
30/// This implementation is for the ClientMessage struct.
31impl<T> ClientMessage<T> {
32    /// # From Bytes
33    ///
34    /// This function converts a byte array to a ClientMessage struct.
35    pub fn from_bytes<'a>(bytes: Vec<u8>) -> Result<ClientMessage<T>, SMTPError>
36    where
37        // The data must be able to be converted from a Vec<u8>
38        T: std::convert::From<std::string::String> + Debug,
39    {
40        // Convert bytes to string
41        let message = match String::from_utf8(bytes.to_vec()) {
42            Ok(cmd) => cmd,
43            // If it fails, return an error
44            Err(_) => {
45                return Err(SMTPError::ParseError(
46                    "Cannot convert to String from bytes".to_owned(),
47                ))
48            }
49        };
50
51        // Split the message by spaces
52        let mut parts = message.split(" ");
53
54        // Get the command
55        let cmd = match parts.next() {
56            Some(cmd) => cmd.to_string(),
57            None => {
58                // If there is no command, return an error
59                return Err(SMTPError::ParseError(
60                    "Invalid Message, Message doesn't contain COMMAND".to_owned(),
61                ));
62            }
63        };
64
65        // Rejoin with spaces
66        let data = parts.collect::<Vec<&str>>().join(" ");
67        // remove \r\n
68        let data = data.trim_end_matches("\r\n").to_string();
69        // Convert the command to a Commands enum
70        let command = Commands::from_bytes(cmd.as_bytes());
71        // Return the ClientMessage
72        Ok(ClientMessage {
73            command,
74            data: data.into(),
75        })
76    }
77}