1use POP3StreamTypes::{Basic, Ssl};
2use POP3Command::{Greet, User, Pass, Stat, UidlAll, UidlOne, ListAll, ListOne, Retr, Dele, Noop, Rset, Quit};
3use std::string::String;
4use async_std::net::{ToSocketAddrs,TcpStream};
5use async_native_tls::{TlsStream, TlsConnector};
6use std::str::FromStr;
7use regex::Regex;
8use lazy_static::lazy_static;
9use async_std::io::{Error, ErrorKind, Result};
10use async_std::prelude::*;
11
12lazy_static! {
13 static ref ENDING_REGEX: Regex = Regex::new(r"^\.\r\n$").unwrap();
14 static ref OK_REGEX: Regex = Regex::new(r"\+OK(.*)").unwrap();
15 static ref ERR_REGEX: Regex = Regex::new(r"-ERR(.*)").unwrap();
16 static ref STAT_REGEX: Regex = Regex::new(r"\+OK (\d+) (\d+)\r\n").unwrap();
17 static ref MESSAGE_DATA_UIDL_ALL_REGEX: Regex = Regex::new(r"(\d+) ([\x21-\x7e]+)\r\n").unwrap();
18 static ref MESSAGE_DATA_UIDL_ONE_REGEX: Regex = Regex::new(r"\+OK (\d+) ([\x21-\x7e]+)\r\n").unwrap();
19 static ref MESSAGE_DATA_LIST_ALL_REGEX: Regex = Regex::new(r"(\d+) (\d+)\r\n").unwrap();
20}
21
22#[derive(Debug)]
24enum POP3StreamTypes {
25 Basic(TcpStream),
26 Ssl(TlsStream<TcpStream>)
27}
28
29#[derive(Debug)]
31pub struct POP3Stream {
32 stream: POP3StreamTypes,
33 pub is_authenticated: bool
34}
35
36#[derive(Clone)]
38enum POP3Command {
39 Greet,
40 User,
41 Pass,
42 Stat,
43 UidlAll,
44 UidlOne,
45 ListAll,
46 ListOne,
47 Retr,
48 Dele,
49 Noop,
50 Rset,
51 Quit
52}
53
54impl POP3Stream {
55
56 pub async fn connect<A:ToSocketAddrs>(addr: A,ssl_context: Option<TlsConnector>,domain: &str) -> Result<POP3Stream> {
58 let tcp_stream = TcpStream::connect(addr).await?;
59 let mut socket = match ssl_context {
60 Some(context) => POP3Stream {
61 stream: Ssl(TlsConnector::connect(&context, domain,tcp_stream).await.unwrap()),
62 is_authenticated: false},
63 None => POP3Stream {
64 stream: Basic(tcp_stream),
65 is_authenticated: false},
66 };
67 match socket.read_response(Greet).await {
68 Ok(_) => (),
69 Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read greet response"))
70 }
71 Ok(socket)
72 }
73
74 async fn write_str(&mut self, s: &str) -> Result<()> {
75 match self.stream {
76 Ssl(ref mut stream) => stream.write_fmt(format_args!("{}", s)).await,
77 Basic(ref mut stream) => stream.write_fmt(format_args!("{}", s)).await,
78 }
79 }
80
81 async fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
82 match self.stream {
83 Ssl(ref mut stream) => stream.read(buf).await,
84 Basic(ref mut stream) => stream.read(buf).await,
85 }
86 }
87
88 pub async fn login(&mut self, username: &str, password: &str) -> POP3Result {
90 let user_command = format!("USER {}\r\n", username);
91 let pass_command = format!("PASS {}\r\n", password);
92 match self.write_str(&user_command).await {
94 Ok(_) => {},
95 Err(_) => panic!("Error writing"),
96 }
97 match self.read_response(User).await {
98 Ok(_) => {
99 match self.write_str(&pass_command).await {
100 Ok(_) => self.is_authenticated = true,
101 Err(_) => panic!("Error writing"),
102 }
103 match self.read_response(Pass).await {
104 Ok(_) => {
105 POP3Result::POP3Ok
106 },
107 Err(_) => panic!("Failure to use PASS")
108 }
109 },
110 Err(_) => panic!("Failure to use USER")
111 }
112 }
113
114 pub async fn stat(&mut self) -> POP3Result {
116 if !self.is_authenticated {
117 panic!("login");
118 }
119
120 let stat_command = "STAT\r\n";
121 match self.write_str(&stat_command).await {
122 Ok(_) => {},
123 Err(_) => panic!("Error writing"),
124 }
125 match self.read_response(Stat).await {
126 Ok(res) => {
127 match res.result {
128 Some(s) => s,
129 None => POP3Result::POP3Err
130 }
131 },
132 Err(_) => POP3Result::POP3Err
133 }
134 }
135
136 pub async fn uidl(&mut self, message_number: Option<i32>) -> POP3Result {
137 if !self.is_authenticated {
138 panic!("login");
139 }
140
141 let uidl_command = match message_number {
142 Some(i) => format!("UIDL {}\r\n", i),
143 None => format!("UIDL\r\n"),
144 };
145 let command_type = match message_number {
146 Some(_) => UidlOne,
147 None => UidlAll,
148 };
149
150 match self.write_str(&uidl_command).await {
151 Ok(_) => {},
152 Err(_) => panic!("Error writing"),
153 }
154
155 match self.read_response(command_type).await {
156 Ok(res) => {
157 match res.result {
158 Some(s) => s,
159 None => POP3Result::POP3Err
160 }
161 },
162 Err(_) => POP3Result::POP3Err
163 }
164 }
165
166 pub async fn list(&mut self, message_number: Option<i32>) -> POP3Result {
168 if !self.is_authenticated {
169 panic!("login");
170 }
171
172 let list_command = match message_number {
173 Some(i) => format!("LIST {}\r\n", i),
174 None => format!("LIST\r\n"),
175 };
176 let command_type = match message_number {
177 Some(_) => ListOne,
178 None => ListAll,
179 };
180
181 match self.write_str(&list_command).await {
182 Ok(_) => {},
183 Err(_) => panic!("Error writing"),
184 }
185
186 match self.read_response(command_type).await {
187 Ok(res) => {
188 match res.result {
189 Some(s) => s,
190 None => POP3Result::POP3Err
191 }
192 },
193 Err(_) => POP3Result::POP3Err
194 }
195 }
196
197 pub async fn retr(&mut self, message_id: i32) -> POP3Result {
199 if !self.is_authenticated {
200 panic!("login");
201 }
202
203 let retr_command = format!("RETR {}\r\n", message_id);
204
205 match self.write_str(&retr_command).await {
206 Ok(_) => {},
207 Err(_) => panic!("Error writing"),
208 }
209
210 match self.read_response(Retr).await {
211 Ok(res) => {
212 match res.result {
213 Some(s) => s,
214 None => POP3Result::POP3Err
215 }
216 },
217 Err(_) => POP3Result::POP3Err
218 }
219 }
220
221 pub async fn dele(&mut self, message_id: i32) -> POP3Result {
223 if !self.is_authenticated {
224 panic!("login");
225 }
226
227 let dele_command = format!("DELE {}\r\n", message_id);
228
229 match self.write_str(&dele_command).await {
230 Ok(_) => {},
231 Err(_) => panic!("Error writing"),
232 }
233
234 match self.read_response(Dele).await {
235 Ok(res) => {
236 match res.result {
237 Some(s) => s,
238 None => POP3Result::POP3Err
239 }
240 },
241 Err(_) => POP3Result::POP3Err
242 }
243 }
244
245 pub async fn rset(&mut self) -> POP3Result {
247 if !self.is_authenticated {
248 panic!("Not Logged In");
249 }
250
251 let retr_command = format!("RETR\r\n");
252
253 match self.write_str(&retr_command).await {
254 Ok(_) => {},
255 Err(_) => panic!("Error writing"),
256 }
257
258 match self.read_response(Rset).await {
259 Ok(res) => {
260 match res.result {
261 Some(s) => s,
262 None => POP3Result::POP3Err
263 }
264 },
265 Err(_) => POP3Result::POP3Err
266 }
267 }
268
269 pub async fn quit(&mut self) -> POP3Result {
271 let quit_command = "QUIT\r\n";
272
273 match self.write_str(&quit_command).await {
274 Ok(_) => {},
275 Err(_) => panic!("Error writing"),
276 }
277
278 match self.read_response(Quit).await {
279 Ok(res) => {
280 match res.result {
281 Some(s) => s,
282 None => POP3Result::POP3Err
283 }
284 },
285 Err(_) => POP3Result::POP3Err
286 }
287 }
288
289 pub async fn noop(&mut self) -> POP3Result {
291 if !self.is_authenticated {
292 panic!("Not Logged In");
293 }
294
295 let noop_command = "noop\r\n";
296
297 match self.write_str(noop_command).await {
298 Ok(_) => {},
299 Err(_) => panic!("Error writing"),
300 }
301
302 match self.read_response(Noop).await {
303 Ok(res) => {
304 match res.result {
305 Some(s) => s,
306 None => POP3Result::POP3Err
307 }
308 },
309 Err(_) => panic!("Error noop")
310 }
311 }
312
313 async fn read_response(&mut self, command: POP3Command) -> Result<Box<POP3Response>> {
314 let mut response = Box::new(POP3Response::new());
315 let cr = 0x0d;
317 let lf = 0x0a;
319 let mut line_buffer: Vec<u8> = Vec::new();
320
321 while !response.complete {
322 while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
323 let byte_buffer: &mut [u8] = &mut [0];
324 match self.read(byte_buffer).await {
325 Ok(_) => {},
326 Err(_) => println!("Error Reading!"),
327 }
328 line_buffer.push(byte_buffer[0]);
329 }
330
331 match String::from_utf8(line_buffer.clone()) {
332 Ok(res) => {
333 response.add_line(res, command.clone());
334 line_buffer = Vec::new();
335 },
336 Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read the response"))
337 }
338 }
339 Ok(response)
340 }
341}
342
343#[derive(Clone,Copy,Debug)]
344pub struct POP3EmailMetadata {
345 pub message_id: i32,
346 pub message_size: i32
347}
348
349#[derive(Clone,Debug)]
350pub struct POP3EmailUidldata {
351 pub message_id: i32,
352 pub message_uid: String
353}
354
355#[derive(Debug)]
356pub enum POP3Result {
357 POP3Ok,
358 POP3Err,
359 POP3Stat {
360 num_email: i32,
361 mailbox_size: i32
362 },
363 POP3Uidl {
364 emails_metadata: Vec<POP3EmailUidldata>,
365 },
366 POP3List {
367 emails_metadata: Vec<POP3EmailMetadata>,
368 },
369 POP3Message {
370 raw: Vec<String>,
371 },
372}
373
374#[derive(Default)]
375struct POP3Response {
376 complete: bool,
377 lines: Vec<String>,
378 result: Option<POP3Result>
379}
380
381impl POP3Response {
382 fn new() -> POP3Response {
383 POP3Response {
384 complete: false,
385 lines: Vec::new(),
386 result: None
387 }
388 }
389
390 fn add_line(&mut self, line: String, command: POP3Command) {
391 if self.lines.len() == 0 {
393 if OK_REGEX.is_match(&line) {
394 self.lines.push(line);
395 match command {
396 Greet|User|Pass|Quit|Dele|Rset => {
397 self.result = Some(POP3Result::POP3Ok);
398 self.complete = true;
399 },
400 Stat => {
401 self.complete = true;
402 self.parse_stat()
403 },
404 UidlAll => {
405
406 },
407 UidlOne => {
408 self.complete = true;
409 self.parse_uidl_one();
410 },
411 ListAll => {
412
413 },
414 ListOne => {
415 self.complete = true;
416 self.parse_list_one();
417 },
418 Retr => {
419
420 },
421 _ => self.complete = true,
422 }
423 } else if ERR_REGEX.is_match(&line) {
424 self.lines.push(line);
425 self.result = Some(POP3Result::POP3Err);
426 self.complete = true;
427 }
428 } else {
429 if ENDING_REGEX.is_match(&line) {
430 self.lines.push(line);
431 match command {
432 UidlAll => {
433 self.complete = true;
434 self.parse_uidl_all();
435 },
436 ListAll => {
437 self.complete = true;
438 self.parse_list_all();
439 },
440 Retr => {
441 self.complete = true;
442 self.parse_message();
443 },
444 _ => self.complete = true,
445 }
446 } else {
447 self.lines.push(line);
448 }
449 }
450 }
451
452 fn parse_stat(&mut self) {
453 let caps = STAT_REGEX.captures(&self.lines[0]).unwrap();
454 let num_emails = FromStr::from_str(caps.get(1).unwrap().as_str());
455 let total_email_size = FromStr::from_str(caps.get(2).unwrap().as_str());
456 self.result = Some(POP3Result::POP3Stat {
457 num_email: num_emails.unwrap(),
458 mailbox_size: total_email_size.unwrap()
459 })
460 }
461
462
463 fn parse_uidl_all(&mut self) {
464 let mut metadata = Vec::new();
465
466 for i in 1..self.lines.len() - 1 {
467 let caps = MESSAGE_DATA_UIDL_ALL_REGEX.captures(&self.lines[i]).unwrap();
468 let message_id = FromStr::from_str(caps.get(1).unwrap().as_str());
469 let message_uid = caps.get(2).unwrap().as_str();
470
471 metadata.push(POP3EmailUidldata {
472 message_id: message_id.unwrap(),
473 message_uid: message_uid.to_owned()
474 });
475 }
476
477 self.result = Some(POP3Result::POP3Uidl {
478 emails_metadata: metadata
479 });
480 }
481
482 fn parse_uidl_one(&mut self) {
483 let caps = MESSAGE_DATA_UIDL_ONE_REGEX.captures(&self.lines[0]).unwrap();
484 let message_id = FromStr::from_str(caps.get(1).unwrap().as_str());
485 let message_uid = caps.get(2).unwrap().as_str();
486
487 self.result = Some(POP3Result::POP3Uidl {
488 emails_metadata: vec![POP3EmailUidldata{
489 message_id: message_id.unwrap(),
490 message_uid: message_uid.to_owned()
491 }]
492 });
493 }
494
495 fn parse_list_all(&mut self) {
496 let mut metadata = Vec::new();
497
498 for i in 1 .. self.lines.len()-1 {
499 let caps = MESSAGE_DATA_LIST_ALL_REGEX.captures(&self.lines[i]).unwrap();
500 let message_id = FromStr::from_str(caps.get(1).unwrap().as_str());
501 let message_size = FromStr::from_str(caps.get(2).unwrap().as_str());
502 metadata.push(POP3EmailMetadata{ message_id: message_id.unwrap(), message_size: message_size.unwrap()});
503 }
504 self.result = Some(POP3Result::POP3List {
505 emails_metadata: metadata
506 });
507 }
508
509 fn parse_list_one(&mut self) {
510 let caps = STAT_REGEX.captures(&self.lines[0]).unwrap();
511 let message_id = FromStr::from_str(caps.get(1).unwrap().as_str());
512 let message_size = FromStr::from_str(caps.get(2).unwrap().as_str());
513 self.result = Some(POP3Result::POP3List {
514 emails_metadata: vec![POP3EmailMetadata{ message_id: message_id.unwrap(), message_size: message_size.unwrap()}]
515 });
516 }
517
518 fn parse_message(&mut self) {
519 let mut raw = Vec::new();
520 for i in 1 .. self.lines.len()-1 {
521 raw.push(self.lines[i].clone());
522 }
523 self.result = Some(POP3Result::POP3Message{
524 raw: raw
525 });
526 }
527}