Skip to main content

hypermail/
message.rs

1use std::collections::HashMap;
2
3pub const HASHSIZE: usize = 673;
4pub const MAXLINE: usize = 1024;
5pub const NAMESTRLEN: usize = 80;
6pub const MAILSTRLEN: usize = 80;
7pub const DATESTRLEN: usize = 80;
8pub const SUBJSTRLEN: usize = 256;
9pub const URLSTRLEN: usize = 256;
10
11pub const BASEYEAR: i32 = 1970;
12
13pub const PROGNAME: &str = "hypermail";
14pub const HMURL: &str = "http://www.hypermail-project.org/";
15pub const INDEXNAME: &str = "index";
16pub const DIRNAME: &str = "archive";
17
18pub const NONAME: &str = "(no name)";
19pub const NODATE: &str = "(no date)";
20pub const NOEMAIL: &str = "(no email)";
21pub const NOSUBJECT: &str = "(no subject)";
22
23pub const GDBM_INDEX_NAME: &str = ".hm2index";
24pub const HAOF_NAME: &str = "archive_overview.haof";
25
26pub const FILE_SUFFIXER: &str = "part";
27pub const DIR_PREFIXER: &str = "att-";
28pub const REPLACEMENT_CHAR: char = '_';
29pub const META_DIR: &str = ".meta";
30pub const META_EXTENSION: &str = ".meta";
31
32pub const PATH_SEPARATOR: char = '/';
33
34pub const PAGE_TOP: i32 = 1;
35pub const PAGE_BOTTOM: i32 = 2;
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum IndexType {
39    Date,
40    Thread,
41    Subject,
42    Author,
43    Attachment,
44    Folders,
45    NoIndex,
46}
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum FilteredReason {
50    Delete = 1,
51    Expire = 2,
52    FilteredOut = 4,
53    FilteredRequired = 8,
54    FilteredOld = 16,
55    FilteredNew = 32,
56}
57
58#[derive(Debug, Clone)]
59pub struct Push {
60    pub string: String,
61}
62
63impl Default for Push {
64    fn default() -> Self {
65        Self::new()
66    }
67}
68
69impl Push {
70    pub fn new() -> Self {
71        Push { string: String::new() }
72    }
73
74    pub fn push_byte(&mut self, b: u8) {
75        self.string.push(b as char);
76    }
77
78    pub fn push_str(&mut self, s: &str) {
79        self.string.push_str(s);
80    }
81
82    pub fn push_nstring(&mut self, s: &str, n: usize) {
83        let len = s.len().min(n);
84        self.string.push_str(&s[..len]);
85    }
86
87    pub fn len(&self) -> usize {
88        self.string.len()
89    }
90
91    pub fn is_empty(&self) -> bool {
92        self.string.is_empty()
93    }
94
95    pub fn as_str(&self) -> &str {
96        &self.string
97    }
98
99    pub fn into_string(self) -> String {
100        self.string
101    }
102}
103
104#[derive(Debug, Clone)]
105pub struct Body {
106    pub line: String,
107    pub html: bool,
108    pub header: bool,
109    pub parsed_header: bool,
110    pub attached: bool,
111    pub demimed: bool,
112    pub msgnum: i32,
113}
114
115#[derive(Debug, Clone)]
116pub struct BodyChain {
117    pub bodies: Vec<Body>,
118}
119
120#[derive(Debug, Clone)]
121pub struct Reply {
122    pub from_msgnum: i32,
123    pub msgnum: i32,
124    pub data: Option<usize>,
125    pub maybe_reply: i32,
126}
127
128#[derive(Debug, Clone)]
129pub struct HmList {
130    pub values: Vec<String>,
131}
132
133#[derive(Debug, Clone)]
134pub struct HashEmail {
135    pub email_index: usize,
136}
137
138#[derive(Debug, Clone)]
139pub struct EmailSubdir {
140    pub first_email: Option<usize>,
141    pub last_email: Option<usize>,
142    pub subdir: String,
143    pub full_path: String,
144    pub rel_path_to_top: String,
145    pub count: i32,
146    pub description: Option<String>,
147    pub a_date: i64,
148}
149
150#[derive(Debug, Clone)]
151pub struct EmailInfo {
152    pub msgnum: i32,
153    pub name: Option<String>,
154    pub email_addr: Option<String>,
155    pub from_date_str: Option<String>,
156    pub from_date: i64,
157    pub date_str: Option<String>,
158    pub date: i64,
159    pub msgid: Option<String>,
160    pub subject: Option<String>,
161    pub unre_subject: Option<String>,
162    pub inreplyto: Option<String>,
163    pub charset: Option<String>,
164    pub datenum: i64,
165    pub flags: i32,
166    pub initial_next_in_thread: i32,
167    pub bodylist: BodyChain,
168    pub replylist: Vec<Reply>,
169    pub is_reply: bool,
170    pub subdir: Option<usize>,
171    pub exp_time: i64,
172    pub is_deleted: i32,
173    pub deletion_completed: i32,
174}
175
176impl Default for EmailInfo {
177    fn default() -> Self {
178        EmailInfo {
179            msgnum: 0,
180            name: None,
181            email_addr: None,
182            from_date_str: None,
183            from_date: 0,
184            date_str: None,
185            date: 0,
186            msgid: None,
187            subject: None,
188            unre_subject: None,
189            inreplyto: None,
190            charset: None,
191            datenum: 0,
192            flags: 0,
193            initial_next_in_thread: 0,
194            bodylist: BodyChain { bodies: Vec::new() },
195            replylist: Vec::new(),
196            is_reply: false,
197            subdir: None,
198            exp_time: 0,
199            is_deleted: 0,
200            deletion_completed: 0,
201        }
202    }
203}
204
205#[derive(Debug, Clone)]
206pub struct Header {
207    pub email_index: usize,
208    pub left: Option<Box<Header>>,
209    pub right: Option<Box<Header>>,
210}
211
212/// Iterative drop to avoid a stack overflow when dropping a deep tree.
213///
214/// A large near-sorted mailbox degenerates the ad-hoc BST in `structs.rs` into a
215/// linked list of depth N; Rust's default derived drop glue for `Box<Header>`
216/// recurses through `left`/`right`, so dropping such a tree (e.g. when the
217/// `EmailStore` goes out of scope) would recurse to depth N and could overflow
218/// the stack. This unlinks children into an explicit work stack instead.
219impl Drop for Header {
220    fn drop(&mut self) {
221        let mut stack: Vec<Box<Header>> = Vec::new();
222        if let Some(l) = self.left.take() {
223            stack.push(l);
224        }
225        if let Some(r) = self.right.take() {
226            stack.push(r);
227        }
228        while let Some(mut node) = stack.pop() {
229            if let Some(l) = node.left.take() {
230                stack.push(l);
231            }
232            if let Some(r) = node.right.take() {
233                stack.push(r);
234            }
235            // `node` drops here with left/right already None, so no recursion.
236        }
237    }
238}
239
240#[derive(Debug, Clone)]
241pub struct Attachment {
242    pub content_type: String,
243    pub name: Option<String>,
244    pub id: Option<String>,
245    pub stored_as: Option<String>,
246    pub descr: Option<String>,
247}
248
249#[derive(Debug, Clone)]
250pub struct AttachmentItem {
251    pub attachment: Attachment,
252}
253
254#[derive(Debug, Clone, Default)]
255pub struct ArchiveState {
256    pub emails: Vec<EmailInfo>,
257    pub subject_list: Option<Box<Header>>,
258    pub author_list: Option<Box<Header>>,
259    pub date_list: Option<Box<Header>>,
260    pub deleted_list: Vec<usize>,
261    pub reply_list: Vec<Reply>,
262    pub thread_list: Vec<Reply>,
263    pub etable: HashMap<String, Vec<usize>>,
264    pub msgid_table: HashMap<String, usize>,
265    pub folders: Vec<EmailSubdir>,
266    pub max_msgnum: i32,
267}