1#[macro_use] extern crate lazy_static;
2extern crate regex;
3
4use regex::Regex;
5use std::str;
6use std::fmt;
7use std::rc::Rc;
8use std::net::Ipv4Addr;
9use std::ptr;
10
11const OPENNING_DATA_CONNECTION:u32 = 150;
12const OPERATION_SUCCESS:u32 = 200;
13const SYSTEM_RECEIVED:u32 = 215;
14const LOGGED_EXPECTED:u32 = 220;
15const CLOSING_DATA_CONNECTION:u32 = 226;
16const PASSIVE_MODE:u32 = 227;
17const LOGGED_IN:u32 = 230;
18const CWD_CONFIRMED:u32 = 250;
19const PATHNAME_AVAILABLE:u32 = 257;
20const PASSWORD_EXPECTED:u32 = 331;
21const AUTHENTICATION_FAILED:u32 = 530;
22
23
24#[derive(Clone)]
26#[derive(PartialEq)]
27#[derive(Debug)]
28pub enum DataMode {
29 Binary,
30 Text
31}
32
33impl fmt::Display for DataMode {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35 match self {
36 &DataMode::Binary => write!(f, "data-mode:binary"),
37 &DataMode::Text => write!(f, "data-mode:text"),
38 }
39 }
40}
41
42enum State {
43 NonAuthorized,
44 Authorized,
45 LoginReady,
46 LoginReqSent,
47
48 PasswordExpected,
49 PasswordReqSent,
50
51 PwdReqSent,
52 PathReceived(String),
53
54 CwdReqSent(String),
55 CwdConfirmed,
56
57 DataTypeReqSent(DataMode),
58 DataTypeConfirmed(DataMode),
59
60 SystemReqSent,
61 SystemRecived(String, String),
62
63 PassiveReqSent,
64 PassiveConfirmed(Ipv4Addr, u16),
65
66 ListReqSent,
67 FileReqSent,
68
69 DataTransferStarted,
70 DataTransferCompleted,
71}
72
73impl fmt::Display for State {
74 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75 match self {
76 &State::PathReceived(ref value) => write!(f, "[state: path-received({})]", value),
77 &State::CwdReqSent(ref value) => write!(f, "[state: cwd-req-sent({})]", value),
78 &State::DataTypeReqSent(ref value) => write!(f, "[state: data-type-req-sent({})]", value),
79 &State::DataTypeConfirmed(ref value) => write!(f, "[state: data-type-confirmed({})]", value),
80 &State::SystemRecived(ref name, ref subtype) => write!(f, "[state: system-recieved({}/{})]", name, subtype),
81 &State::PassiveConfirmed(ref addr, ref port) => write!(f, "[state: passive-mode ({}:{})]", addr, port),
82 _ => {
83 let state = match self {
84 &State::NonAuthorized => "non-authorized",
85 &State::Authorized => "authorized",
86 &State::LoginReady => "login-ready",
87 &State::LoginReqSent => "login-req-sent",
88 &State::PasswordExpected => "password-expected",
89 &State::PasswordReqSent => "password-req-sent",
90 &State::PwdReqSent => "pwd-req-sent",
91 &State::SystemReqSent => "system-req-sent",
92 &State::PassiveReqSent => "passive-req-sent",
93 &State::ListReqSent => "list-req-sent",
94 &State::FileReqSent => "file-req-sent",
95 &State::DataTransferStarted => "data-transfer-started",
96 &State::DataTransferCompleted => "data-transfer-completed",
97 &State::CwdConfirmed => "cwd-confirmed",
98 _ => unreachable!(),
99 };
100 write!(f, "[state: {}]", state)
101 }
102 }
103 }
104}
105
106#[derive(PartialEq)]
108#[derive(Debug)]
109pub enum RemoteFileKind {
110 File,
111 Directory,
112}
113
114#[derive(PartialEq)]
116#[derive(Debug)]
117pub struct RemoteFile {
118 pub kind: RemoteFileKind,
119 pub size: usize,
120 pub name: String,
121}
122
123#[derive(PartialEq)]
124pub enum FtpError {
126 NotEnoughData,
128 ProtocolError(String),
130 GarbageData,
132 AuthFailed,
134}
135
136impl fmt::Display for FtpError {
137 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138 match self {
139 &FtpError::NotEnoughData => { write!(f, "[no enough data]") }
140 &FtpError::AuthFailed => { write!(f, "[authorization failed]") }
141 &FtpError::GarbageData => { write!(f, "[garbage]") }
142 &FtpError::ProtocolError(ref s) => { write!(f, "[protocol error: {}]", s) }
143 }
144 }
145}
146
147struct FtpInternals {
148 error: Option<FtpError>,
149 data_mode: Option<DataMode>,
150 working_dir: Option<String>,
151 sent_request: Option<Rc<State>>,
152 system: Option<(String, String)>,
153 endpoint: Option<(Ipv4Addr, u16)>,
154 state: Rc<State>,
155}
156
157pub struct FtpReceiver {
162 internals: Rc<FtpInternals>
163}
164
165pub struct FtpTransmitter {
168 internals: Rc<FtpInternals>
169}
170
171
172impl fmt::Debug for FtpError {
173 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174 match self {
175 &FtpError::GarbageData => write!(f, "garbage data"),
176 &FtpError::NotEnoughData => write!(f, "no enough data"),
177 &FtpError::ProtocolError(ref err) => write!(f, "protocol error: {}", err),
178 &FtpError::AuthFailed => write!(f, "authentication failed"),
179 }
180 }
181}
182
183impl FtpReceiver {
184 pub fn new() -> Self {
185 FtpReceiver {
186 internals: Rc::new(FtpInternals {
187 error: None,
188 data_mode: None,
189 working_dir: None,
190 sent_request: None,
191 system: None,
192 endpoint: None,
193 state: Rc::new(State::NonAuthorized),
194 })
195 }
196 }
197
198
199 fn advance_state(prev_state: &State, prev_req: &Option<Rc<State>>, bytes: &[u8]) -> Result<State, FtpError> {
200
201 lazy_static! {
202 static ref RE_RESPONCE_CODE: Regex = Regex::new("(?m:^(\\d{3}) (.+)\r$)").unwrap();
203 static ref RE_PATHNAME: Regex = Regex::new("\"(.+)\"").unwrap();
204 static ref RE_SYSTEM: Regex = Regex::new("(\\w+) [Tt]ype: (\\w+)").unwrap();
205 static ref RE_PARTRIAL_RESPONCE_CODE: Regex = Regex::new("(?m:^(\\d{3})-.+\r$)").unwrap();
206 static ref RE_PASSIVE_MODE: Regex = Regex::new("Entering Passive Mode \\((\\d+),(\\d+),(\\d+),(\\d+),(\\d+),(\\d+)\\)").unwrap();
207 }
208
209 str::from_utf8(bytes)
210 .map_err(|_| FtpError::GarbageData)
211 .and_then(|response|
212 RE_RESPONCE_CODE.captures(&response)
213 .ok_or_else(||{
214 if RE_PARTRIAL_RESPONCE_CODE.is_match(response) {
215 FtpError::NotEnoughData
216 } else {
217 FtpError::GarbageData
218 }
219 })
220 .and_then(|captures| {
221 let code_str = captures.at(1).unwrap();
222 let code:u32 = code_str.parse().unwrap();
223 match code {
224 LOGGED_EXPECTED => Ok(State::LoginReady),
225 PASSWORD_EXPECTED => Ok(State::PasswordExpected),
226 LOGGED_IN => Ok(State::Authorized),
227 AUTHENTICATION_FAILED => Err(FtpError::AuthFailed),
228 OPENNING_DATA_CONNECTION => Ok(State::DataTransferStarted),
229 CLOSING_DATA_CONNECTION => Ok(State::DataTransferCompleted),
230 CWD_CONFIRMED => Ok(State::CwdConfirmed),
231 OPERATION_SUCCESS => {
232 match &*prev_req {
233 &Some(ref prev_sent_req) => {
234 match &**prev_sent_req {
235 &State::DataTypeReqSent(ref value) => Ok(State::DataTypeConfirmed(value.clone())),
236 _ => Err(FtpError::GarbageData),
237 }
238 },
239 _ => Err(FtpError::GarbageData),
240 }
241 },
242 PATHNAME_AVAILABLE => {
243 let pathname_str = captures.at(2).unwrap();
244 RE_PATHNAME.captures(pathname_str)
245 .ok_or(FtpError::GarbageData)
246 .and_then(|path_capture|{
247 let path = path_capture.at(1).unwrap();
248 Ok(State::PathReceived(path.to_string()))
249 })
250 },
251 SYSTEM_RECEIVED => {
252 let system_str = captures.at(2).unwrap();
253 RE_SYSTEM.captures(system_str)
254 .ok_or(FtpError::GarbageData)
255 .and_then(|path_capture|{
256 let name = path_capture.at(1).unwrap();
257 let subtype = path_capture.at(2).unwrap();
258 Ok(State::SystemRecived(name.to_string(), subtype.to_string()))
259 })
260 },
261 PASSIVE_MODE => {
262 let addr_str = captures.at(2).unwrap();
263 RE_PASSIVE_MODE.captures(addr_str)
264 .ok_or(FtpError::GarbageData)
265 .and_then(|path_capture|{
266 let mut numbers = path_capture.iter().skip(1).map(|opt_value| {
267 let value = opt_value.unwrap();
268 let number:u8 = value.parse().unwrap();
269 number
270 });
271 let a = numbers.next().unwrap();
272 let b = numbers.next().unwrap();
273 let c = numbers.next().unwrap();
274 let d = numbers.next().unwrap();
275 let p1 = numbers.next().unwrap();
276 let p2 = numbers.next().unwrap();
277
278 let p1_16 = p1 as u16;
279 let p2_16 = p2 as u16;
280
281 let addr = Ipv4Addr::new(a, b, c, d);
282 let port = 256 * p1_16 + p2_16;
283 Ok(State::PassiveConfirmed(addr, port))
284 })
285 }
286 _ => panic!(format!("unknown responce: {}", response))
287 }
288 })
289 )
290 .and_then(|new_state|{
291 let allowed:bool = match (prev_state, &new_state) {
292 (&State::NonAuthorized, &State::LoginReady) => true,
293 (&State::LoginReqSent, &State::PasswordExpected) => true,
294 (&State::PasswordExpected, &State::PasswordReqSent) => true,
295 (&State::PasswordReqSent, &State::Authorized) => true,
296 (&State::PwdReqSent, &State::PathReceived(_)) => true,
297 (&State::DataTypeReqSent(_), &State::DataTypeConfirmed(_)) => true,
298 (&State::SystemReqSent, &State::SystemRecived(_, _)) => true,
299 (&State::PassiveReqSent, &State::PassiveConfirmed(_, _)) => true,
300 (&State::ListReqSent, &State::DataTransferStarted) => true,
301 (&State::FileReqSent, &State::DataTransferStarted) => true,
302 (&State::DataTransferStarted, &State::DataTransferCompleted) => true,
303 (&State::CwdReqSent(_), &State::CwdConfirmed) => true,
304 _ => false,
305 };
306 if allowed {
307 Ok(new_state)
308 } else {
309 println!("transition {} => {} is not allowed", prev_state, new_state);
310 Err(FtpError::ProtocolError(format!("{} => {} is not allowed", prev_state, new_state)))
311 }
312 })
313 }
314
315
316 pub fn try_advance(self, buffer: &[u8]) -> Result<FtpTransmitter, Self> {
323 let mut internals = self.internals;
324
325 let transition_result = FtpReceiver::advance_state(&internals.state, &internals.sent_request, buffer);
326
327 match transition_result {
328 Err(e) => {
329 println!("error on state: {}", internals.state);
330 if &e == &FtpError::AuthFailed {
331 Rc::get_mut(&mut internals).unwrap().state = Rc::new(State::LoginReady);
332 }
333 Rc::get_mut(&mut internals).unwrap().error = Some(e);
334 Err(FtpReceiver { internals: internals.clone() })
335 }
336 ,
337 Ok(new_state) => {
338 {
339 let mut int_ref = Rc::get_mut(&mut internals).unwrap();
340 let sent_request = int_ref.sent_request.clone();
341
342 let final_state = match new_state {
343 State::PathReceived(path) => {
344 int_ref.working_dir = Some(path);
345 State::Authorized
346 },
347 State::DataTypeConfirmed(data_type) => {
348 int_ref.data_mode = Some(data_type);
349 State::Authorized
350 },
351 State::SystemRecived(name, subtype) => {
352 int_ref.system = Some((name, subtype));
353 State::Authorized
354 }
355 State::PassiveConfirmed(addr, port) => {
356 int_ref.endpoint = Some((addr, port));
357 State::Authorized
358 }
359 State::CwdConfirmed => {
360 int_ref.working_dir = match &sent_request.unwrap().as_ref() {
361 &&State::CwdReqSent(ref path) => Some(path.clone()),
362 _ => { unreachable!() },
363 };
364 State::Authorized
365 }
366 State::DataTransferCompleted => {
367 State::Authorized
368 }
369 _ => new_state,
370 };
371
372 int_ref.state = Rc::new(final_state);
373 int_ref.sent_request = None;
374 }
375 Ok(FtpTransmitter { internals: internals })
376 }
377 }
378 }
379
380 pub fn take_error(&mut self) -> Option<FtpError> {
383 Rc::get_mut(&mut self.internals).unwrap().error.take()
384 }
385
386 pub fn to_transmitter(self) -> FtpTransmitter {
390 FtpTransmitter { internals: self.internals }
391 }
392
393}
394
395
396lazy_static! {
397 static ref DATA_USER: &'static [u8] = "USER ".as_bytes();
398 static ref DATA_PASS: &'static [u8] = "PASS ".as_bytes();
399 static ref DATA_PWD: &'static [u8] = "PWD\r\n".as_bytes();
400 static ref DATA_ENDING: &'static [u8] = "\r\n".as_bytes();
401 static ref DATA_DATA_BINARY: &'static [u8] = "TYPE I\r\n".as_bytes();
402 static ref DATA_DATA_TEXT: &'static [u8] = "TYPE T\r\n".as_bytes();
403 static ref DATA_SYST: &'static [u8] = "SYST\r\n".as_bytes();
404 static ref DATA_PASV: &'static [u8] = "PASV\r\n".as_bytes();
405 static ref DATA_LIST: &'static [u8] = "LIST -l\r\n".as_bytes();
406 static ref DATA_CWD: &'static [u8] = "CWD ".as_bytes();
407 static ref DATA_RETR: &'static [u8] = "RETR ".as_bytes();
408}
409
410
411impl FtpTransmitter {
412
413 pub fn to_receiver(self) -> FtpReceiver {
417 FtpReceiver { internals: self.internals }
418 }
419
420 pub fn send_login(self, buffer: &mut [u8], count: &mut usize, login: &str) -> FtpReceiver {
423 let mut internals = self.internals;
424 let current_state = internals.state.clone();
425
426 match &*internals.state {
427
428 &State::LoginReady => {
429 let data_login = login.as_bytes();
430 let mut my_count = 0;
431 unsafe {
432 ptr::copy_nonoverlapping(&DATA_USER[0], &mut buffer[my_count], DATA_USER.len());
433 my_count += DATA_USER.len();
434 ptr::copy_nonoverlapping(&data_login[0], &mut buffer[my_count], data_login.len());
435 my_count += data_login.len();
436 ptr::copy_nonoverlapping(&DATA_ENDING[0], &mut buffer[my_count], DATA_ENDING.len());
437 };
438 my_count += DATA_ENDING.len();
439 *count = my_count;
440 {
441 let mut int_ref = Rc::get_mut(&mut internals).unwrap();
442 int_ref.state = Rc::new(State::LoginReqSent);
443 int_ref.sent_request = Some(int_ref.state.clone());
444 }
445
446 FtpReceiver { internals: internals }
447 },
448 _ => panic!(format!("send_login is not allowed from the {}" , current_state)),
449 }
450 }
451
452 pub fn send_password(self, buffer: &mut [u8], count: &mut usize, pass: &str) -> FtpReceiver {
455 let mut internals = self.internals;
456
457 match &*internals.state {
458 &State::PasswordExpected => {
459 let data_password = pass.as_bytes();
460 let mut my_count = 0;
461 unsafe {
462 ptr::copy_nonoverlapping(&DATA_PASS[0], &mut buffer[my_count], DATA_PASS.len());
463 my_count += DATA_PASS.len();
464 ptr::copy_nonoverlapping(&data_password[0], &mut buffer[my_count], data_password.len());
465 my_count += data_password.len();
466 ptr::copy_nonoverlapping(&DATA_ENDING[0], &mut buffer[my_count], DATA_ENDING.len());
467 };
468 my_count += DATA_ENDING.len();
469 *count = my_count;
470 {
471 let mut int_ref = Rc::get_mut(&mut internals).unwrap();
472 int_ref.state = Rc::new(State::PasswordReqSent);
473 int_ref.sent_request = Some(int_ref.state.clone());
474 }
475
476 FtpReceiver { internals: internals }
477 },
478 _ => panic!("send_password is not allowed from the current state"),
479 }
480 }
481
482 pub fn send_pwd_req(self, buffer: &mut [u8], count: &mut usize) -> FtpReceiver {
485 let mut internals = self.internals;
486
487 match &*internals.state {
488 &State::Authorized => {
489 unsafe { ptr::copy_nonoverlapping(&DATA_PWD[0], &mut buffer[0], DATA_PWD.len()); }
490 *count = DATA_PWD.len();
491 {
492 let mut int_ref = Rc::get_mut(&mut internals).unwrap();
493 int_ref.state = Rc::new(State::PwdReqSent);
494 int_ref.sent_request = Some(int_ref.state.clone());
495 }
496
497 FtpReceiver { internals: internals }
498 },
499 _ => panic!("send_pwd_req is not allowed from the current state"),
500 }
501 }
502
503 pub fn get_wd(&self) -> &str {
506 match &self.internals.working_dir {
507 &Some(ref path) => &path,
508 &None => panic!("get_wd is not available (did you called send_pwd_req?)"),
509 }
510 }
511
512 pub fn send_type_req(self, buffer: &mut [u8], count: &mut usize, data_type: DataMode) -> FtpReceiver {
515 let mut internals = self.internals;
516
517 match &*internals.state {
518 &State::Authorized => {
519 match &data_type {
520 &DataMode::Binary => {
521 unsafe { ptr::copy_nonoverlapping(&DATA_DATA_BINARY[0], &mut buffer[0], DATA_DATA_BINARY.len()); }
522 *count = DATA_DATA_BINARY.len();
523 },
524 &DataMode::Text => {
525 unsafe { ptr::copy_nonoverlapping(&DATA_DATA_TEXT[0], &mut buffer[0], DATA_DATA_TEXT.len()); }
526 *count = DATA_DATA_TEXT.len();
527 }
528 };
529 {
530 let mut int_ref = Rc::get_mut(&mut internals).unwrap();
531 int_ref.state = Rc::new(State::DataTypeReqSent(data_type));
532 int_ref.sent_request = Some(int_ref.state.clone());
533 }
534
535 FtpReceiver { internals: internals }
536 },
537 _ => panic!("send_type_req is not allowed from the {}", internals.state),
538 }
539 }
540
541 pub fn get_type(&self) -> &DataMode {
544 match &self.internals.data_mode {
545 &Some(ref mode) => &mode,
546 &None => panic!("get_type is not available (did you called send_type_req?)"),
547 }
548 }
549
550 pub fn send_system_req(self, buffer: &mut [u8], count: &mut usize) -> FtpReceiver {
553 let mut internals = self.internals;
554
555 match &*internals.state {
556 &State::Authorized => {
557 unsafe { ptr::copy_nonoverlapping(&DATA_SYST[0], &mut buffer[0], DATA_SYST.len()); }
558 *count = DATA_SYST.len();
559 {
560 let mut int_ref = Rc::get_mut(&mut internals).unwrap();
561 int_ref.state = Rc::new(State::SystemReqSent);
562 int_ref.sent_request = Some(int_ref.state.clone());
563 }
564
565 FtpReceiver { internals: internals }
566 },
567 _ => panic!("send_type_req is not allowed from the {}", internals.state),
568 }
569 }
570
571 pub fn get_system(&self) -> (&String, &String) {
574 match &self.internals.system {
575 &Some((ref name, ref subtype)) => (&name, &subtype),
576 &None => panic!("get_system is not available (did you called send_system_req?)"),
577 }
578 }
579
580 pub fn send_pasv_req(self, buffer: &mut [u8], count: &mut usize) -> FtpReceiver {
583 let mut internals = self.internals;
584
585 match &*internals.state {
586 &State::Authorized => {
587 unsafe { ptr::copy_nonoverlapping(&DATA_PASV[0], &mut buffer[0], DATA_PASV.len()); }
588 *count = DATA_PASV.len();
589 {
590 let mut int_ref = Rc::get_mut(&mut internals).unwrap();
591 int_ref.state = Rc::new(State::PassiveReqSent);
592 int_ref.sent_request = Some(int_ref.state.clone());
593 }
594
595 FtpReceiver { internals: internals }
596 },
597 _ => panic!("send_pasv_req is not allowed from the {}", internals.state),
598 }
599 }
600
601 pub fn send_get_req(self, buffer: &mut [u8], count: &mut usize, file_path: &str) -> FtpReceiver {
604 let mut internals = self.internals;
605
606 match &*internals.state {
607 &State::Authorized => {
608 let data_path = file_path.as_bytes();
609 let mut my_count = 0;
610 unsafe {
611 ptr::copy_nonoverlapping(&DATA_RETR[0], &mut buffer[my_count], DATA_RETR.len());
612 my_count += DATA_RETR.len();
613 ptr::copy_nonoverlapping(&data_path[0], &mut buffer[my_count], data_path.len());
614 my_count += data_path.len();
615 ptr::copy_nonoverlapping(&DATA_ENDING[0], &mut buffer[my_count], DATA_ENDING.len());
616 };
617 my_count += DATA_ENDING.len();
618 {
619 let mut int_ref = Rc::get_mut(&mut internals).unwrap();
620 int_ref.state = Rc::new(State::FileReqSent);
621 int_ref.sent_request = Some(int_ref.state.clone());
622 }
623 *count = my_count;
624
625 FtpReceiver { internals: internals }
626 },
627 _ => panic!("send_get_req is not allowed from the {}", internals.state),
628 }
629 }
630
631
632 pub fn send_cwd_req(self, buffer: &mut [u8], count: &mut usize, path: &str) -> FtpReceiver {
635 let mut internals = self.internals;
636
637 match &*internals.state {
638 &State::Authorized => {
639 let data_path = path.as_bytes();
640 let mut my_count = 0;
641 unsafe {
642 ptr::copy_nonoverlapping(&DATA_CWD[0], &mut buffer[my_count], DATA_CWD.len());
643 my_count += DATA_CWD.len();
644 ptr::copy_nonoverlapping(&data_path[0], &mut buffer[my_count], path.len());
645 my_count += path.len();
646 ptr::copy_nonoverlapping(&DATA_ENDING[0], &mut buffer[my_count], DATA_ENDING.len());
647 };
648 my_count += DATA_ENDING.len();
649 {
650 let mut int_ref = Rc::get_mut(&mut internals).unwrap();
651 int_ref.state = Rc::new(State::CwdReqSent(path.to_string()));
652 int_ref.sent_request = Some(int_ref.state.clone());
653 }
654 *count = my_count;
655
656 FtpReceiver { internals: internals }
657 },
658 _ => panic!("send_cwd_req is not allowed from the {}", internals.state),
659 }
660 }
661
662
663 pub fn take_endpoint(&mut self) -> (Ipv4Addr, u16) {
666 match Rc::get_mut(&mut self.internals).unwrap().endpoint.take() {
667 Some((addr, port)) => (addr, port),
668 None => panic!("take_endpoint is not available (did you called send_pass_req?)"),
669 }
670 }
671
672 pub fn send_list_req(self, buffer: &mut [u8], count: &mut usize) -> FtpReceiver {
675 let mut internals = self.internals;
676
677 match &*internals.state {
678 &State::Authorized => {
679 unsafe { ptr::copy_nonoverlapping(&DATA_LIST[0], &mut buffer[0], DATA_LIST.len()); }
680 *count = DATA_LIST.len();
681 {
682 let mut int_ref = Rc::get_mut(&mut internals).unwrap();
683 int_ref.state = Rc::new(State::ListReqSent);
684 int_ref.sent_request = Some(int_ref.state.clone());
685 }
686 FtpReceiver { internals: internals }
687 },
688 _ => panic!("send_pass_req is not allowed from the {}", internals.state),
689 }
690 }
691
692 pub fn parse_list(&self, data: &[u8]) -> Result<Vec<RemoteFile>, FtpError> {
694
695 lazy_static! {
696 static ref RE_LINE: Regex = Regex::new("(?m:^(.+)\r$)").unwrap();
697 static ref RE_FILE: Regex = Regex::new("^([d-])(?:[rwx-]{3}){3} +\\d+ +\\w+ +\\w+ +(\\d+) +(.+) +(.+)$").unwrap();
698 }
699 str::from_utf8(data)
700 .map_err(|_| FtpError::GarbageData)
701 .and_then(|list|{
702 let line_captures = RE_LINE.captures_iter(list);
703 let files = line_captures
704 .filter_map(|line_cap| {
705 let line = line_cap.at(1).unwrap();
706 match RE_FILE.captures(line) {
708 None => None,
709 Some(captures) => {
710 let kind_str = captures.at(1).unwrap();
711 let size_str = captures.at(2).unwrap();
712 let name = captures.at(4).unwrap();
713 let kind = match kind_str {
714 "d" => RemoteFileKind::Directory,
715 "-" => RemoteFileKind::File,
716 _ => unreachable!(),
717 };
718 let size:usize = size_str.parse().unwrap();
719 let remote_file = RemoteFile {
721 kind: kind,
722 size: size,
723 name: name.to_string(),
724 };
725 Some(remote_file)
726 }
727 }
728 });
729 let mut vec:Vec<RemoteFile> = Vec::new();
730 for file in files {
731 vec.push(file);
732 }
733 Ok(vec)
734 })
735 }
736
737}