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