1use crate::status_code::{StatusCode, StatusCodeKind};
7use derive_more::From;
8use log::warn;
9use native_tls::{TlsConnector, TlsStream};
10use std::io::prelude::*;
11use std::io::BufReader;
12use std::io::{Read, Write};
13use std::net::TcpStream;
14
15#[derive(Debug, PartialEq)]
21pub struct ServerResponse {
22 message: String,
23 status_code: StatusCode,
24}
25
26impl ServerResponse {
27 pub fn summarize_error(&self, expected: Vec<StatusCodeKind>) -> String {
30 format!(
31 "Got {}: {}, expected {:?}",
32 self.status_code.code, self.message, expected
33 )
34 }
35}
36
37#[derive(Debug, Clone, Copy)]
52pub enum ClientMode {
53 Passive,
55 ExtendedPassive,
57 Active,
59}
60
61impl ServerResponse {
62 pub fn parse(text: &str) -> Self {
64 let status_code = StatusCode::parse(text);
65 let message = text[3..].trim().to_string();
66
67 Self {
68 message,
69 status_code,
70 }
71 }
72
73 pub fn is_failure_status(&self) -> bool {
75 self.status_code.is_failure()
76 }
77}
78
79#[derive(From)]
80enum ClientStream {
81 TcpStream(TcpStream),
82 TlsStream(TlsStream<TcpStream>),
83}
84
85impl ClientStream {
86 pub fn peer_addr(&self) -> Result<std::net::SocketAddr, std::io::Error> {
87 match self {
88 ClientStream::TcpStream(stream) => stream.peer_addr(),
89 ClientStream::TlsStream(stream) => stream.get_ref().peer_addr(),
90 }
91 }
92}
93
94impl Read for ClientStream {
95 fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
96 match self {
97 ClientStream::TcpStream(stream) => stream.read(buf),
98 ClientStream::TlsStream(stream) => stream.read(buf),
99 }
100 }
101}
102
103impl Write for ClientStream {
104 fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
105 match self {
106 ClientStream::TcpStream(stream) => stream.write(buf),
107 ClientStream::TlsStream(stream) => stream.write(buf),
108 }
109 }
110
111 fn flush(&mut self) -> Result<(), std::io::Error> {
112 match self {
113 ClientStream::TcpStream(stream) => stream.flush(),
114 ClientStream::TlsStream(stream) => stream.flush(),
115 }
116 }
117}
118
119pub struct Client {
124 stream: BufReader<ClientStream>,
125 buffer: String,
126 welcome_string: Option<String>,
127 mode: ClientMode,
128}
129
130impl Client {
131 pub fn set_mode(&mut self, mode: ClientMode) {
133 self.mode = mode
134 }
135
136 pub fn connect(
138 hostname: &str,
139 user: &str,
140 password: &str,
141 ) -> Result<Self, crate::error::Error> {
142 Self::connect_with_port(hostname, 21, user, password)
143 }
144
145 pub fn connect_tls(
147 hostname: &str,
148 user: &str,
149 password: &str,
150 ) -> Result<Self, crate::error::Error> {
151 Self::connect_tls_with_port(hostname, 21, user, password)
152 }
153
154 pub fn connect_tls_with_port(
156 hostname: &str,
157 port: u32,
158 user: &str,
159 password: &str,
160 ) -> Result<Self, crate::error::Error> {
161 let connector = TlsConnector::new()?;
162
163 let host = format!("{}:{}", hostname, port);
164 let raw_stream = TcpStream::connect(&host)?;
165 let tls_stream = connector.connect(&host, raw_stream)?;
166 let stream: BufReader<ClientStream> = BufReader::new(tls_stream.into());
167
168 let buffer = String::new();
169 let mut client = Client {
170 stream,
171 buffer,
172 welcome_string: None,
173 mode: ClientMode::ExtendedPassive,
174 };
175 let response = client.parse_reply_expecting(vec![StatusCodeKind::ReadyForNewUser])?;
176 client.welcome_string = Some(response.message);
177 client.login(user, password)?;
178
179 Ok(client)
180 }
181
182 pub fn connect_with_port(
184 hostname: &str,
185 port: u32,
186 user: &str,
187 password: &str,
188 ) -> Result<Self, crate::error::Error> {
189 let host = format!("{}:{}", hostname, port);
190 let raw_stream = TcpStream::connect(&host)?;
191 let stream = BufReader::new(raw_stream.into());
192
193 let buffer = String::new();
194 let mut client = Client {
195 stream,
196 buffer,
197 welcome_string: None,
198 mode: ClientMode::ExtendedPassive,
199 };
200 let response = client.parse_reply_expecting(vec![StatusCodeKind::ReadyForNewUser])?;
201 client.welcome_string = Some(response.message);
202 client.login(user, password)?;
203
204 Ok(client)
205 }
206
207 pub fn get_welcome(&self) -> Option<&String> {
209 self.welcome_string.as_ref()
210 }
211
212 pub fn login(&mut self, user: &str, password: &str) -> Result<(), crate::error::Error> {
216 self.write_unary_command_expecting("USER", user, vec![StatusCodeKind::PasswordRequired])?;
217 self.write_unary_command_expecting("PASS", password, vec![StatusCodeKind::UserLoggedIn])?;
218
219 Ok(())
220 }
221
222 pub fn logout(&mut self) -> Result<(), crate::error::Error> {
224 self.write_command_expecting("QUIT", vec![StatusCodeKind::ClosingControlConnection])?;
225
226 Ok(())
227 }
228
229 pub fn cwd(&mut self, dir: &str) -> Result<(), crate::error::Error> {
231 self.write_unary_command_expecting(
232 "CWD",
233 dir,
234 vec![StatusCodeKind::RequestFileActionCompleted],
235 )?;
236
237 Ok(())
238 }
239
240 pub fn cdup(&mut self) -> Result<(), crate::error::Error> {
242 self.write_command_expecting("CDUP", vec![StatusCodeKind::RequestFileActionCompleted])?;
243
244 Ok(())
245 }
246
247 pub fn help(&mut self) -> Result<(), crate::error::Error> {
253 self.write_command_expecting(
254 "HELP",
255 vec![StatusCodeKind::SystemStatus, StatusCodeKind::HelpMessage],
256 )?;
257 Ok(())
258 }
259
260 pub fn noop(&mut self) -> Result<(), crate::error::Error> {
263 self.write_command_expecting("NOOP", vec![StatusCodeKind::Ok])?;
264 Ok(())
265 }
266
267 pub fn ascii(&mut self) -> Result<(), crate::error::Error> {
269 self.write_unary_command_expecting("TYPE", "A", vec![StatusCodeKind::Ok])?;
270 Ok(())
271 }
272
273 pub fn binary(&mut self) -> Result<(), crate::error::Error> {
275 self.write_unary_command_expecting("TYPE", "I", vec![StatusCodeKind::Ok])?;
276 Ok(())
277 }
278
279 pub fn status(&mut self) -> Result<String, crate::error::Error> {
284 let response = self.write_command_expecting("STAT", vec![StatusCodeKind::SystemStatus])?;
285
286 Ok(response.message)
287 }
288
289 pub fn list(&mut self, path: &str) -> Result<String, crate::error::Error> {
291 let mut conn = self.get_data_connection()?;
292 self.write_unary_command_expecting(
293 "LIST",
294 path,
295 vec![
296 StatusCodeKind::TransferStarted,
297 StatusCodeKind::TransferAboutToStart,
298 ],
299 )?;
300
301 let mut buffer = Vec::with_capacity(1024);
302 conn.read_to_end(&mut buffer)?;
303 self.parse_reply_expecting(vec![StatusCodeKind::RequestActionCompleted])?;
304 let text = String::from_utf8(buffer).map_err(|_| {
305 crate::error::Error::SerializationFailed(
306 "Invalid ASCII returned on server directory listing.".to_string(),
307 )
308 })?;
309 Ok(text)
310 }
311
312 pub fn list_names(&mut self, path: &str) -> Result<Vec<String>, crate::error::Error> {
314 let mut conn = self.get_data_connection()?;
315 self.write_unary_command_expecting(
316 "NLST",
317 path,
318 vec![
319 StatusCodeKind::TransferStarted,
320 StatusCodeKind::TransferAboutToStart,
321 ],
322 )?;
323
324 let mut buffer = Vec::with_capacity(1024);
325 conn.read_to_end(&mut buffer)?;
326 self.parse_reply_expecting(vec![StatusCodeKind::RequestActionCompleted])?;
327 let text = String::from_utf8(buffer).map_err(|_| {
328 crate::error::Error::SerializationFailed(
329 "Invalid ASCII returned on server directory name listing.".to_string(),
330 )
331 })?;
332 Ok(text.lines().map(|line| line.to_owned()).collect())
333 }
334
335 pub fn store<B: AsRef<[u8]>>(
337 &mut self,
338 path: &str,
339 data: B,
340 ) -> Result<(), crate::error::Error> {
341 {
343 let mut conn = self.get_data_connection()?;
344 self.write_unary_command_expecting(
345 "STOR",
346 path,
347 vec![
348 StatusCodeKind::TransferStarted,
349 StatusCodeKind::TransferAboutToStart,
350 ],
351 )?;
352 conn.get_mut().write_all(data.as_ref())?;
353 }
354
355 self.parse_reply_expecting(vec![StatusCodeKind::RequestActionCompleted])?;
356
357 Ok(())
358 }
359
360 pub fn store_unique<B: AsRef<[u8]>>(&mut self, data: B) -> Result<String, crate::error::Error> {
362 {
364 let mut conn = self.get_data_connection()?;
365 self.write_command_expecting(
366 "STOU",
367 vec![
368 StatusCodeKind::TransferStarted,
369 StatusCodeKind::TransferAboutToStart,
370 ],
371 )?;
372 conn.get_mut().write_all(data.as_ref())?;
373 }
374
375 let reply = self.parse_reply_expecting(vec![StatusCodeKind::RequestActionCompleted])?;
376
377 Ok(reply.message)
378 }
379
380 pub fn append<B: AsRef<[u8]>>(
382 &mut self,
383 path: &str,
384 data: B,
385 ) -> Result<(), crate::error::Error> {
386 {
388 let mut conn = self.get_data_connection()?;
389 self.write_unary_command_expecting(
390 "APPE",
391 path,
392 vec![
393 StatusCodeKind::TransferStarted,
394 StatusCodeKind::TransferAboutToStart,
395 ],
396 )?;
397 conn.get_mut().write_all(data.as_ref())?;
398 }
399
400 self.parse_reply_expecting(vec![
401 StatusCodeKind::RequestActionCompleted,
402 StatusCodeKind::RequestFileActionCompleted,
403 ])?;
404
405 Ok(())
406 }
407
408 pub fn restart(&mut self) -> Result<(), crate::error::Error> {
410 unimplemented!();
411 }
412
413 pub fn abort(&mut self) -> Result<(), crate::error::Error> {
415 unimplemented!();
416 }
417
418 pub fn allocate(
420 &mut self,
421 _logical_size: usize,
422 _logical_page_size: Option<usize>,
423 ) -> Result<(), crate::error::Error> {
424 unimplemented!();
425 }
426
427 pub fn rename_file(
429 &mut self,
430 path_from: &str,
431 path_to: &str,
432 ) -> Result<(), crate::error::Error> {
433 self.write_unary_command_expecting(
434 "RNFR",
435 path_from,
436 vec![StatusCodeKind::RequestActionPending],
437 )?;
438 self.write_unary_command_expecting(
439 "RNTO",
440 path_to,
441 vec![StatusCodeKind::RequestFileActionCompleted],
442 )?;
443
444 Ok(())
445 }
446
447 pub fn remove_directory(&mut self, dir_path: &str) -> Result<(), crate::error::Error> {
449 self.write_unary_command_expecting(
450 "RMD",
451 dir_path,
452 vec![StatusCodeKind::RequestFileActionCompleted],
453 )?;
454 Ok(())
455 }
456
457 pub fn make_directory(&mut self, dir_path: &str) -> Result<(), crate::error::Error> {
459 self.write_unary_command_expecting("MKD", dir_path, vec![StatusCodeKind::PathCreated])?;
460 Ok(())
461 }
462
463 pub fn pwd(&mut self) -> Result<String, crate::error::Error> {
465 let response = self.write_command_expecting("PWD", vec![StatusCodeKind::PathCreated])?;
466 Ok(response.message)
467 }
468
469 pub fn site_parameters(&mut self) -> Result<String, crate::error::Error> {
480 let response = self.write_command_expecting(
481 "SITE",
482 vec![StatusCodeKind::Ok, StatusCodeKind::FeatureNotImplemented],
483 )?;
484
485 Ok(response.message)
486 }
487
488 pub fn system(&mut self) -> Result<String, crate::error::Error> {
490 let response =
491 self.write_command_expecting("SYST", vec![StatusCodeKind::NameSystemType])?;
492
493 Ok(response.message)
494 }
495
496 pub fn delete_file(&mut self, dir_path: &str) -> Result<(), crate::error::Error> {
498 self.write_unary_command_expecting(
499 "DELE",
500 dir_path,
501 vec![StatusCodeKind::RequestFileActionCompleted],
502 )?;
503
504 Ok(())
505 }
506
507 pub fn retrieve_file(&mut self, path: &str) -> Result<Vec<u8>, crate::error::Error> {
509 let mut conn = self.get_data_connection()?;
510 self.write_unary_command_expecting(
511 "RETR",
512 path,
513 vec![
514 StatusCodeKind::TransferAboutToStart,
515 StatusCodeKind::TransferStarted,
516 ],
517 )?;
518
519 let mut buffer = Vec::with_capacity(1024);
520 conn.read_to_end(&mut buffer)?;
521 self.parse_reply_expecting(vec![StatusCodeKind::RequestActionCompleted])?;
522 Ok(buffer)
523 }
524
525 pub fn get_data_connection(&mut self) -> Result<BufReader<TcpStream>, crate::error::Error> {
527 match self.mode {
528 ClientMode::Active => unimplemented!(),
529 ClientMode::Passive => self.passive_mode_connection(),
530 ClientMode::ExtendedPassive => self.extended_passive_mode_connection(),
531 }
532 }
533
534 pub fn extended_passive_mode_connection(
536 &mut self,
537 ) -> Result<BufReader<TcpStream>, crate::error::Error> {
538 let response =
539 self.write_command_expecting("EPSV", vec![StatusCodeKind::EnteredExtendedPassiveMode])?;
540 let socket = self.decode_extended_passive_mode_socket(&response.message)?;
541
542 Ok(BufReader::new(TcpStream::connect(socket)?))
543 }
544
545 pub fn passive_mode_connection(&mut self) -> Result<BufReader<TcpStream>, crate::error::Error> {
547 let response =
548 self.write_command_expecting("PASV", vec![StatusCodeKind::EnteredPassiveMode])?;
549 let socket = self.decode_passive_mode_ip(&response.message)?;
550
551 Ok(BufReader::new(TcpStream::connect(socket)?))
552 }
553
554 pub fn write_unary_command_expecting(
556 &mut self,
557 cmd: &str,
558 arg: &str,
559 valid_statuses: Vec<StatusCodeKind>,
560 ) -> Result<ServerResponse, crate::error::Error> {
561 self.write_unary_command(cmd, arg)?;
562 self.parse_reply_expecting(valid_statuses)
563 }
564
565 pub fn write_unary_command(&mut self, cmd: &str, arg: &str) -> Result<(), crate::error::Error> {
567 let text = format!("{} {}\r\n", cmd, arg);
568 self.stream.get_mut().write_all(text.as_bytes())?;
569
570 Ok(())
571 }
572
573 pub fn write_command_expecting(
575 &mut self,
576 cmd: &str,
577 valid_statuses: Vec<StatusCodeKind>,
578 ) -> Result<ServerResponse, crate::error::Error> {
579 self.write_command(cmd)?;
580 self.parse_reply_expecting(valid_statuses)
581 }
582
583 pub fn write_command(&mut self, cmd: &str) -> Result<(), crate::error::Error> {
585 let text = format!("{}\r\n", cmd);
586 self.stream.get_mut().write_all(text.as_bytes())?;
587
588 Ok(())
589 }
590
591 pub fn parse_reply_expecting(
593 &mut self,
594 valid_statuses: Vec<StatusCodeKind>,
595 ) -> Result<ServerResponse, crate::error::Error> {
596 let response = self.parse_reply()?;
597
598 let is_expected_status = valid_statuses.contains(&response.status_code.kind);
599 let is_positive_status = response.status_code.is_valid();
601 warn!(
602 "Unexpected positive status was accepted: {:?}",
603 response.status_code
604 );
605
606 if is_expected_status || is_positive_status {
607 Ok(response)
608 } else {
609 Err(crate::error::Error::UnexpectedStatusCode(
610 response.summarize_error(valid_statuses),
611 ))
612 }
613 }
614
615 pub fn parse_reply(&mut self) -> Result<ServerResponse, crate::error::Error> {
617 self.buffer.clear();
618 self.stream.read_line(&mut self.buffer)?;
619 Ok(ServerResponse::parse(&self.buffer))
620 }
621
622 pub fn read_reply(&mut self) -> Result<String, crate::error::Error> {
624 self.buffer.clear();
625 self.stream.read_line(&mut self.buffer)?;
626 Ok(self.buffer.clone())
627 }
628
629 fn decode_passive_mode_ip(
630 &self,
631 message: &str,
632 ) -> Result<std::net::SocketAddrV4, crate::error::Error> {
633 let first_bracket = message.find('(');
634 let second_bracket = message.find(')');
635 let cant_parse_error = || {
636 crate::error::Error::InvalidSocketPassiveMode(format!(
637 "Cannot parse socket sent from server for passive mode: {}.",
638 message
639 ))
640 };
641
642 match (first_bracket, second_bracket) {
643 (Some(start), Some(end)) => {
644 let nums: Vec<u8> = message[start + 1..end]
646 .split(',')
647 .flat_map(|val| val.parse())
649 .collect();
650 if nums.len() < 4 {
651 Err(cant_parse_error())
652 } else {
653 let ip = std::net::Ipv4Addr::new(nums[0], nums[1], nums[2], nums[3]);
654
655 Ok(std::net::SocketAddrV4::new(
656 ip,
657 256 * nums[4] as u16 + nums[5] as u16,
658 ))
659 }
660 }
661 _ => Err(cant_parse_error()),
662 }
663 }
664
665 fn decode_extended_passive_mode_socket(
666 &self,
667 response: &str,
668 ) -> Result<std::net::SocketAddr, crate::error::Error> {
669 let first_delimiter = response.find("|||");
670 let second_delimiter = response.rfind('|');
671 let cant_parse_error = || {
672 crate::error::Error::InvalidSocketPassiveMode(format!(
673 "Cannot parse socket sent from server for passive mode: {}.",
674 response
675 ))
676 };
677
678 match (first_delimiter, second_delimiter) {
679 (Some(start), Some(end)) => {
680 let port: u16 = response[start + 3..end]
681 .parse()
682 .map_err(move |_| cant_parse_error())?;
683 let ip = self
684 .stream
685 .get_ref()
686 .peer_addr()
687 .map_err(move |_| cant_parse_error())?
688 .ip();
689 Ok(std::net::SocketAddr::new(ip, port))
690 }
691 _ => Err(cant_parse_error()),
692 }
693 }
694}