new_tokio_smtp/command/auth/
login.rs1use base64::encode;
2use futures::future::{self, Either, Future};
3
4use super::validate_auth_capability;
5use crate::{
6 error::{LogicError, MissingCapabilities},
7 future_ext::ResultWithContextExt,
8 Cmd, EhloData, ExecFuture, Io,
9};
10
11#[derive(Debug, Clone)]
13pub struct Login {
14 username: String,
15 password: String,
16}
17
18impl Login {
19 pub fn new(username: &str, password: &str) -> Self {
21 Login {
22 username: encode(username),
23 password: encode(password),
24 }
25 }
26
27 pub fn from_base64(username: String, password: String) -> Self {
29 Login { username, password }
30 }
31
32 pub fn base64_username(&self) -> &str {
34 &self.username
35 }
36
37 }
39
40impl Cmd for Login {
41 fn check_cmd_availability(&self, caps: Option<&EhloData>) -> Result<(), MissingCapabilities> {
42 validate_auth_capability(caps, "LOGIN")
43 }
44
45 fn exec(self, mut io: Io) -> ExecFuture {
46 let Login { username, password } = self;
47
48 io.write_line_from_parts(&["AUTH LOGIN", username.as_str()]);
49
50 let fut = io
51 .flush()
52 .and_then(Io::parse_response)
53 .ctx_and_then(move |io: Io, response| {
54 if !response.code().is_intermediate() {
55 Either::A(future::ok((io, Err(LogicError::UnexpectedCode(response)))))
56 } else {
57 let fut = io
58 .flush_line_from_parts(&[password.as_str()])
59 .and_then(Io::parse_response);
60
61 Either::B(fut)
62 }
63 });
64
65 Box::new(fut)
66 }
67}