|
1
|
use std::collections::HashSet; |
|
2
|
|
|
3
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)] |
|
4
|
pub enum MessageFlag { |
|
5
|
Seen, |
|
6
|
Answered, |
|
7
|
Flagged, |
|
8
|
Deleted, |
|
9
|
Draft, |
|
10
|
Recent, |
|
11
|
} |
|
12
|
|
|
13
|
impl MessageFlag { |
|
14
|
pub fn to_string(&self) -> &str { |
|
15
|
match self { |
|
16
|
MessageFlag::Seen => "\\Seen", |
|
17
|
MessageFlag::Answered => "\\Answered", |
|
18
|
MessageFlag::Flagged => "\\Flagged", |
|
19
|
MessageFlag::Deleted => "\\Deleted", |
|
20
|
MessageFlag::Draft => "\\Draft", |
|
21
|
MessageFlag::Recent => "\\Recent", |
|
22
|
} |
|
23
|
} |
|
24
|
|
|
25
|
pub fn from_string(s: &str) -> Option<Self> { |
|
26
|
match s.to_uppercase().as_str() { |
|
27
|
"\\SEEN" => Some(MessageFlag::Seen), |
|
28
|
"\\ANSWERED" => Some(MessageFlag::Answered), |
|
29
|
"\\FLAGGED" => Some(MessageFlag::Flagged), |
|
30
|
"\\DELETED" => Some(MessageFlag::Deleted), |
|
31
|
"\\DRAFT" => Some(MessageFlag::Draft), |
|
32
|
"\\RECENT" => Some(MessageFlag::Recent), |
|
33
|
_ => None, |
|
34
|
} |
|
35
|
} |
|
36
|
} |
|
37
|
|
|
38
|
#[derive(Debug, Clone)] |
|
39
|
pub struct Message { |
|
40
|
pub uid: u32, |
|
41
|
pub sequence_number: u32, |
|
42
|
pub flags: HashSet<MessageFlag>, |
|
43
|
pub from: String, |
|
44
|
pub to: Vec<String>, |
|
45
|
pub subject: String, |
|
46
|
pub body: String, |
|
47
|
pub raw_content: String, |
|
48
|
} |
|
49
|
|
|
50
|
impl Message { |
|
51
|
pub fn new(uid: u32, sequence_number: u32, from: String, to: Vec<String>, raw_content: String) -> Self { |
|
52
|
// Parse subject from raw content |
|
53
|
let subject = Self::extract_subject(&raw_content); |
|
54
|
let body = Self::extract_body(&raw_content); |
|
55
|
|
|
56
|
let mut flags = HashSet::new(); |
|
57
|
flags.insert(MessageFlag::Recent); |
|
58
|
|
|
59
|
Message { |
|
60
|
uid, |
|
61
|
sequence_number, |
|
62
|
flags, |
|
63
|
from, |
|
64
|
to, |
|
65
|
subject, |
|
66
|
body, |
|
67
|
raw_content, |
|
68
|
} |
|
69
|
} |
|
70
|
|
|
71
|
fn extract_subject(content: &str) -> String { |
|
72
|
for line in content.lines() { |
|
73
|
if line.to_lowercase().starts_with("subject:") { |
|
74
|
return line[8..].trim().to_string(); |
|
75
|
} |
|
76
|
} |
|
77
|
"(No Subject)".to_string() |
|
78
|
} |
|
79
|
|
|
80
|
fn extract_body(content: &str) -> String { |
|
81
|
let mut in_body = false; |
|
82
|
let mut body = String::new(); |
|
83
|
|
|
84
|
for line in content.lines() { |
|
85
|
if in_body { |
|
86
|
body.push_str(line); |
|
87
|
body.push('\n'); |
|
88
|
} else if line.trim().is_empty() { |
|
89
|
in_body = true; |
|
90
|
} |
|
91
|
} |
|
92
|
|
|
93
|
body |
|
94
|
} |
|
95
|
|
|
96
|
pub fn has_flag(&self, flag: &MessageFlag) -> bool { |
|
97
|
self.flags.contains(flag) |
|
98
|
} |
|
99
|
|
|
100
|
pub fn add_flag(&mut self, flag: MessageFlag) { |
|
101
|
self.flags.insert(flag); |
|
102
|
} |
|
103
|
|
|
104
|
pub fn remove_flag(&mut self, flag: &MessageFlag) { |
|
105
|
self.flags.remove(flag); |
|
106
|
} |
|
107
|
|
|
108
|
pub fn flags_string(&self) -> String { |
|
109
|
let flags: Vec<String> = self.flags.iter() |
|
110
|
.map(|f| f.to_string().to_string()) |
|
111
|
.collect(); |
|
112
|
format!("({})", flags.join(" ")) |
|
113
|
} |
|
114
|
} |