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 }