1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use std::str::FromStr;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum WaitMode {
Prompt,
Immediate,
Expect(usize, String),
}
impl Default for WaitMode { fn default() -> WaitMode { WaitMode::Prompt }}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ScriptCommand {
pub wait_mode: WaitMode,
pub skip_newline: bool,
pub timeout: Option<u64>,
pub command: String,
}
impl ScriptCommand {
pub fn basic<S: Into<String>>(s: S) -> ScriptCommand {
ScriptCommand {
command: s.into(),
..Default::default()
}
}
pub fn immediate(&self) -> bool {
self.wait_mode == WaitMode::Immediate
}
pub fn timeout(&self) -> Option<u64> {
self.timeout
}
pub fn skip_newline(&self) -> bool {
self.skip_newline
}
}
impl FromStr for ScriptCommand {
type Err = String;
fn from_str(s: &str) -> Result<ScriptCommand, Self::Err> {
let mut rest = s;
let mut scmd = ScriptCommand::default();
loop {
if rest.starts_with('~') {
rest = &rest[1..];
scmd.wait_mode = WaitMode::Immediate;
} else if rest.starts_with('!') {
rest = &rest[1..];
scmd.skip_newline = true;
} else if rest.starts_with('`') {
let ending = rest.char_indices()
.skip(1)
.find(|&(_, c)| c == '`');
match ending {
None => return Err(s.into()),
Some((i, _)) => {
let inner = &rest[1..i];
match inner.char_indices().find(|(_, c)| *c == ':') {
None => return Err(s.into()),
Some((i, _)) => {
let (timeout, expect) = (&inner[..i], &inner[i+1..]);
let num = match timeout.parse() {
Err(_) => return Err(s.into()),
Ok(n) => n,
};
scmd.wait_mode = WaitMode::Expect(num, expect.into());
}
}
rest = &rest[i+1..];
}
}
} else if rest.starts_with('%') {
let ending = rest.char_indices()
.skip(1)
.find(|(_, c)| *c == '%');
match ending {
None => return Err(s.into()),
Some((i, _)) => {
let inner = &rest[1..i];
let num: u64 = match inner.parse() {
Err(_) => return Err(s.into()),
Ok(n) => n,
};
scmd.timeout = Some(num);
rest = &rest[i+1..];
}
}
} else if rest.starts_with('\\') && rest.starts_with(|c| matches!(c, '!' | '~')) {
rest = &rest[1..];
} else {
break;
}
}
scmd.command = rest.into();
Ok(scmd)
}
}
struct LoginPair {
username: String,
password: String,
}
enum CtrlMessage {
GlobalAuth(LoginPair),
AuthConsole(LoginPair),
AuthEnable(LoginPair),
}