1use bytes::{BufMut, Bytes, BytesMut};
3use num_derive::FromPrimitive;
4use std::convert::From;
5use std::io;
6use std::str;
7
8use crate::error::Result;
9use crate::parse::*;
10
11pub(crate) const PACKET_DATA_HEADER_LEN: usize = 4;
12
13#[derive(Debug, Clone, Copy, PartialEq, FromPrimitive)]
14#[repr(u16)]
15pub(crate) enum PacketType {
16 Rrq = 1,
17 Wrq = 2,
18 Data = 3,
19 Ack = 4,
20 Error = 5,
21 OAck = 6,
22}
23
24#[derive(Debug, Clone)]
26pub enum Error {
27 Msg(String),
28 UnknownError,
29 FileNotFound,
30 PermissionDenied,
31 DiskFull,
32 IllegalOperation,
33 UnknownTransferId,
34 FileAlreadyExists,
35 NoSuchUser,
36}
37
38#[derive(Debug)]
39pub(crate) enum Packet<'a> {
40 Rrq(RwReq),
41 Wrq(RwReq),
42 Data(u16, &'a [u8]),
43 Ack(u16),
44 Error(Error),
45 OAck(Opts),
46}
47
48#[derive(Debug, PartialEq)]
49pub(crate) enum Mode {
50 Netascii,
51 Octet,
52 Mail,
53}
54
55#[derive(Debug, PartialEq)]
56pub(crate) struct RwReq {
57 pub filename: String,
58 pub mode: Mode,
59 pub opts: Opts,
60}
61
62#[derive(Debug, Clone, Default, PartialEq)]
63pub(crate) struct Opts {
64 pub block_size: Option<u16>,
65 pub timeout: Option<u8>,
66 pub transfer_size: Option<u64>,
67}
68
69impl<'a> Packet<'a> {
70 pub(crate) fn decode(data: &[u8]) -> Result<Packet> {
71 parse_packet(data)
72 }
73
74 pub(crate) fn encode(&self, buf: &mut BytesMut) {
75 match self {
76 Packet::Rrq(req) => {
77 buf.put_u16(PacketType::Rrq as u16);
78 buf.put_slice(req.filename.as_bytes());
79 buf.put_u8(0);
80 buf.put_slice(req.mode.to_str().as_bytes());
81 buf.put_u8(0);
82 req.opts.encode(buf);
83 }
84 Packet::Wrq(req) => {
85 buf.put_u16(PacketType::Wrq as u16);
86 buf.put_slice(req.filename.as_bytes());
87 buf.put_u8(0);
88 buf.put_slice(req.mode.to_str().as_bytes());
89 buf.put_u8(0);
90 req.opts.encode(buf);
91 }
92 Packet::Data(block, data) => {
93 buf.put_u16(PacketType::Data as u16);
94 buf.put_u16(*block);
95 buf.put_slice(data);
96 }
97 Packet::Ack(block) => {
98 buf.put_u16(PacketType::Ack as u16);
99 buf.put_u16(*block);
100 }
101 Packet::Error(error) => {
102 buf.put_u16(PacketType::Error as u16);
103 buf.put_u16(error.code());
104 buf.put_slice(error.msg().as_bytes());
105 buf.put_u8(0);
106 }
107 Packet::OAck(opts) => {
108 buf.put_u16(PacketType::OAck as u16);
109 opts.encode(buf);
110 }
111 }
112 }
113
114 pub(crate) fn encode_data_head(block_id: u16, buf: &mut BytesMut) {
115 buf.put_u16(PacketType::Data as u16);
116 buf.put_u16(block_id);
117 }
118
119 pub(crate) fn to_bytes(&self) -> Bytes {
120 let mut buf = BytesMut::new();
121 self.encode(&mut buf);
122 buf.freeze()
123 }
124}
125
126impl Opts {
127 fn encode(&self, buf: &mut BytesMut) {
128 if let Some(block_size) = self.block_size {
129 buf.put_slice(&b"blksize\0"[..]);
130 buf.put_slice(block_size.to_string().as_bytes());
131 buf.put_u8(0);
132 }
133
134 if let Some(timeout) = self.timeout {
135 buf.put_slice(&b"timeout\0"[..]);
136 buf.put_slice(timeout.to_string().as_bytes());
137 buf.put_u8(0);
138 }
139
140 if let Some(transfer_size) = self.transfer_size {
141 buf.put_slice(&b"tsize\0"[..]);
142 buf.put_slice(transfer_size.to_string().as_bytes());
143 buf.put_u8(0);
144 }
145 }
146}
147
148impl Mode {
149 pub(crate) fn to_str(&self) -> &'static str {
150 match self {
151 Mode::Netascii => "netascii",
152 Mode::Octet => "octet",
153 Mode::Mail => "mail",
154 }
155 }
156}
157
158impl Error {
159 pub(crate) fn from_code(code: u16, msg: Option<&str>) -> Self {
160 #[allow(clippy::wildcard_in_or_patterns)]
161 match code {
162 1 => Error::FileNotFound,
163 2 => Error::PermissionDenied,
164 3 => Error::DiskFull,
165 4 => Error::IllegalOperation,
166 5 => Error::UnknownTransferId,
167 6 => Error::FileAlreadyExists,
168 7 => Error::NoSuchUser,
169 0 | _ => match msg {
170 Some(msg) => Error::Msg(msg.to_string()),
171 None => Error::UnknownError,
172 },
173 }
174 }
175
176 pub(crate) fn code(&self) -> u16 {
177 match self {
178 Error::Msg(..) => 0,
179 Error::UnknownError => 0,
180 Error::FileNotFound => 1,
181 Error::PermissionDenied => 2,
182 Error::DiskFull => 3,
183 Error::IllegalOperation => 4,
184 Error::UnknownTransferId => 5,
185 Error::FileAlreadyExists => 6,
186 Error::NoSuchUser => 7,
187 }
188 }
189
190 pub(crate) fn msg(&self) -> &str {
191 match self {
192 Error::Msg(msg) => msg,
193 Error::UnknownError => "Unknown error",
194 Error::FileNotFound => "File not found",
195 Error::PermissionDenied => "Permission denied",
196 Error::DiskFull => "Disk is full",
197 Error::IllegalOperation => "Illegal operation",
198 Error::UnknownTransferId => "Unknown transfer ID",
199 Error::FileAlreadyExists => "File already exists",
200 Error::NoSuchUser => "No such user",
201 }
202 }
203}
204
205impl From<Error> for Packet<'_> {
206 fn from(inner: Error) -> Self {
207 Packet::Error(inner)
208 }
209}
210
211impl From<io::Error> for Error {
212 fn from(io_err: io::Error) -> Self {
213 match io_err.kind() {
214 io::ErrorKind::NotFound => Error::FileNotFound,
215 io::ErrorKind::PermissionDenied => Error::PermissionDenied,
216 io::ErrorKind::WriteZero => Error::DiskFull,
217 io::ErrorKind::AlreadyExists => Error::FileAlreadyExists,
218 _ => match io_err.raw_os_error() {
219 Some(rc) => Error::Msg(format!("IO error: {}", rc)),
220 None => Error::UnknownError,
221 },
222 }
223 }
224}
225
226impl From<crate::Error> for Error {
227 fn from(err: crate::Error) -> Self {
228 match err {
229 crate::Error::Packet(e) => e,
230 crate::Error::Io(e) => e.into(),
231 crate::Error::InvalidPacket => Error::IllegalOperation,
232 crate::Error::MaxSendRetriesReached(..) => {
233 Error::Msg("Max retries reached".to_string())
234 }
235 _ => Error::UnknownError,
236 }
237 }
238}