/*
* meli - mailbox threading module.
*
* Copyright 2017 Manos Pitsidianakis
*
* This file is part of meli.
*
* meli is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* meli is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
/*!
* This module implements Jamie Zawinski's (threading algorithm)
* [https://www.jwz.org/doc/threading.html]. It is a bit of a beast, so prepare for a lot of
* bloated code that's necessary for the crap modern e-mail is. Quoted comments (/* " .. " */) are
* taken almost verbatim from the algorithm.
*
* The entry point of this module is the `Threads` struct and its `new` method. It contains `ThreadNodes` which are the
* nodes in the thread trees that might have messages associated with them. The root nodes (first
* messages in each thread) are stored in `root_set` and `tree` vectors. The `ThreadTree` struct
* contains the sorted threads. `Threads` has inner mutability since we need to sort without the
* user having mutable ownership.
*/
use crate::mailbox::email::parser::BytesExt;
use crate::mailbox::email::*;
use fnv::{FnvHashMap, FnvHashSet};
use std::cell::{Ref, RefCell};
use std::cmp;
use std::cmp::Ordering;
use std::fmt;
use std::iter::FromIterator;
use std::mem;
use std::ops::Index;
use std::result::Result as StdResult;
use std::str::FromStr;
type Envelopes = FnvHashMap<EnvelopeHash, Envelope>;
/* Helper macros to avoid repeating ourselves */
fn rec_change_root_parent(b: &mut Vec<ThreadNode>, idx: usize, new_root: usize) {
b[idx].thread_group = new_root;
if let Some(p) = b[idx].parent {
rec_change_children(b, p, new_root);
rec_change_root_parent(b, p, new_root);
}
}
fn rec_change_children(b: &mut Vec<ThreadNode>, idx: usize, new_root: usize) {
b[idx].thread_group = new_root;
for c in b[idx].children.clone() {
rec_change_children(b, c, new_root);
}
}
macro_rules! remove_from_parent {
($buf:expr, $idx:expr) => {