🐝 My patches for macos etc...
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2221 lines
92 KiB

4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
2 years ago
  1. /*
  2. * meli - accounts module.
  3. *
  4. * Copyright 2017 Manos Pitsidianakis
  5. *
  6. * This file is part of meli.
  7. *
  8. * meli is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * meli is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with meli. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. /*!
  22. * Account management from user configuration.
  23. */
  24. use super::{AccountConf, FileMailboxConf};
  25. use crate::jobs::{JobChannel, JobExecutor, JobId, JoinHandle};
  26. use indexmap::IndexMap;
  27. use melib::backends::*;
  28. use melib::email::*;
  29. use melib::error::{MeliError, Result};
  30. use melib::text_processing::GlobMatch;
  31. use melib::thread::{SortField, SortOrder, Threads};
  32. use melib::AddressBook;
  33. use melib::Collection;
  34. use smallvec::SmallVec;
  35. use std::collections::BTreeMap;
  36. use std::collections::{HashMap, HashSet};
  37. use crate::types::UIEvent::{self, EnvelopeRemove, EnvelopeRename, EnvelopeUpdate, Notification};
  38. use crate::{StatusEvent, ThreadEvent};
  39. use crossbeam::Sender;
  40. use futures::channel::oneshot;
  41. use futures::future::FutureExt;
  42. pub use futures::stream::Stream;
  43. use futures::stream::StreamExt;
  44. use std::borrow::Cow;
  45. use std::collections::VecDeque;
  46. use std::convert::TryFrom;
  47. use std::fs;
  48. use std::io;
  49. use std::ops::{Index, IndexMut};
  50. use std::os::unix::fs::PermissionsExt;
  51. use std::pin::Pin;
  52. use std::result;
  53. use std::sync::{Arc, RwLock};
  54. #[macro_export]
  55. macro_rules! try_recv_timeout {
  56. ($oneshot:expr) => {{
  57. const _3_MS: std::time::Duration = std::time::Duration::from_millis(95);
  58. let now = std::time::Instant::now();
  59. let mut res = Ok(None);
  60. while now + _3_MS >= std::time::Instant::now() {
  61. res = $oneshot.try_recv().map_err(|_| MeliError::new("canceled"));
  62. if res.as_ref().map(|r| r.is_some()).unwrap_or(false) || res.is_err() {
  63. break;
  64. }
  65. }
  66. res
  67. }};
  68. }
  69. #[derive(Debug)]
  70. pub enum MailboxStatus {
  71. Available,
  72. Failed(MeliError),
  73. /// first argument is done work, and second is total work
  74. Parsing(usize, usize),
  75. None,
  76. }
  77. impl Default for MailboxStatus {
  78. fn default() -> Self {
  79. MailboxStatus::None
  80. }
  81. }
  82. impl MailboxStatus {
  83. pub fn is_available(&self) -> bool {
  84. if let MailboxStatus::Available = self {
  85. true
  86. } else {
  87. false
  88. }
  89. }
  90. pub fn is_parsing(&self) -> bool {
  91. if let MailboxStatus::Parsing(_, _) = self {
  92. true
  93. } else {
  94. false
  95. }
  96. }
  97. }
  98. #[derive(Debug)]
  99. pub struct MailboxEntry {
  100. pub status: MailboxStatus,
  101. pub name: String,
  102. pub ref_mailbox: Mailbox,
  103. pub conf: FileMailboxConf,
  104. }
  105. impl MailboxEntry {
  106. pub fn status(&self) -> String {
  107. match self.status {
  108. MailboxStatus::Available => format!(
  109. "{} [{} messages]",
  110. self.name(),
  111. self.ref_mailbox.count().ok().unwrap_or((0, 0)).1
  112. ),
  113. MailboxStatus::Failed(ref e) => e.to_string(),
  114. MailboxStatus::None => "Retrieving mailbox.".to_string(),
  115. MailboxStatus::Parsing(done, total) => {
  116. format!("Parsing messages. [{}/{}]", done, total)
  117. }
  118. }
  119. }
  120. pub fn name(&self) -> &str {
  121. if let Some(name) = self.conf.mailbox_conf.alias.as_ref() {
  122. name
  123. } else {
  124. &self.ref_mailbox.name()
  125. }
  126. }
  127. }
  128. #[derive(Debug)]
  129. pub struct Account {
  130. name: String,
  131. hash: AccountHash,
  132. pub is_online: Result<()>,
  133. pub(crate) mailbox_entries: IndexMap<MailboxHash, MailboxEntry>,
  134. pub(crate) mailboxes_order: Vec<MailboxHash>,
  135. tree: Vec<MailboxNode>,
  136. sent_mailbox: Option<MailboxHash>,
  137. pub(crate) collection: Collection,
  138. pub(crate) address_book: AddressBook,
  139. pub(crate) settings: AccountConf,
  140. pub(crate) backend: Arc<RwLock<Box<dyn MailBackend>>>,
  141. pub job_executor: Arc<JobExecutor>,
  142. pub active_jobs: HashMap<JobId, JobRequest>,
  143. pub active_job_instants: BTreeMap<std::time::Instant, JobId>,
  144. sender: Sender<ThreadEvent>,
  145. event_queue: VecDeque<(MailboxHash, RefreshEvent)>,
  146. pub backend_capabilities: MailBackendCapabilities,
  147. }
  148. pub enum JobRequest {
  149. Mailboxes(
  150. JoinHandle,
  151. oneshot::Receiver<Result<HashMap<MailboxHash, Mailbox>>>,
  152. ),
  153. Fetch(
  154. MailboxHash,
  155. JoinHandle,
  156. oneshot::Receiver<(
  157. Option<Result<Vec<Envelope>>>,
  158. Pin<Box<dyn Stream<Item = Result<Vec<Envelope>>> + Send + 'static>>,
  159. )>,
  160. ),
  161. Generic {
  162. name: Cow<'static, str>,
  163. logging_level: melib::LoggingLevel,
  164. handle: JoinHandle,
  165. channel: JobChannel<()>,
  166. on_finish: Option<crate::types::CallbackFn>,
  167. },
  168. IsOnline(JoinHandle, oneshot::Receiver<Result<()>>),
  169. Refresh(MailboxHash, JoinHandle, oneshot::Receiver<Result<()>>),
  170. SetFlags(EnvelopeHashBatch, JoinHandle, oneshot::Receiver<Result<()>>),
  171. SaveMessage {
  172. bytes: Vec<u8>,
  173. mailbox_hash: MailboxHash,
  174. handle: JoinHandle,
  175. channel: oneshot::Receiver<Result<()>>,
  176. },
  177. SendMessage,
  178. SendMessageBackground(JoinHandle, JobChannel<()>),
  179. CopyTo(MailboxHash, JoinHandle, oneshot::Receiver<Result<Vec<u8>>>),
  180. DeleteMessages(EnvelopeHashBatch, JoinHandle, oneshot::Receiver<Result<()>>),
  181. CreateMailbox {
  182. path: String,
  183. handle: JoinHandle,
  184. channel: JobChannel<(MailboxHash, HashMap<MailboxHash, Mailbox>)>,
  185. },
  186. DeleteMailbox {
  187. mailbox_hash: MailboxHash,
  188. handle: JoinHandle,
  189. channel: JobChannel<HashMap<MailboxHash, Mailbox>>,
  190. },
  191. //RenameMailbox,
  192. Search(JoinHandle),
  193. AsBytes(JoinHandle),
  194. SetMailboxPermissions(MailboxHash, JoinHandle, oneshot::Receiver<Result<()>>),
  195. SetMailboxSubscription(MailboxHash, JoinHandle, oneshot::Receiver<Result<()>>),
  196. Watch {
  197. channel: oneshot::Receiver<Result<()>>,
  198. handle: JoinHandle,
  199. },
  200. }
  201. impl Drop for JobRequest {
  202. fn drop(&mut self) {
  203. match self {
  204. JobRequest::Generic { handle, .. } => handle.0.cancel(),
  205. JobRequest::Mailboxes(h, _) => h.0.cancel(),
  206. JobRequest::Fetch(_, h, _) => h.0.cancel(),
  207. JobRequest::IsOnline(h, _) => h.0.cancel(),
  208. JobRequest::Refresh(_, h, _) => h.0.cancel(),
  209. JobRequest::SetFlags(_, h, _) => h.0.cancel(),
  210. JobRequest::SaveMessage { handle, .. } => handle.0.cancel(),
  211. JobRequest::CopyTo(_, h, _) => h.0.cancel(),
  212. JobRequest::DeleteMessages(_, h, _) => h.0.cancel(),
  213. JobRequest::CreateMailbox { handle, .. } => handle.0.cancel(),
  214. JobRequest::DeleteMailbox { handle, .. } => handle.0.cancel(),
  215. //JobRequest::RenameMailbox,
  216. JobRequest::Search(h) => h.0.cancel(),
  217. JobRequest::AsBytes(h) => h.0.cancel(),
  218. JobRequest::SetMailboxPermissions(_, h, _) => {
  219. h.0.cancel();
  220. }
  221. JobRequest::SetMailboxSubscription(_, h, _) => {
  222. h.0.cancel();
  223. }
  224. JobRequest::Watch { handle, .. } => handle.0.cancel(),
  225. JobRequest::SendMessage => {}
  226. JobRequest::SendMessageBackground(h, _) => {
  227. h.0.cancel();
  228. }
  229. }
  230. }
  231. }
  232. impl core::fmt::Debug for JobRequest {
  233. fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
  234. match self {
  235. JobRequest::Generic { name, .. } => write!(f, "JobRequest::Generic({})", name),
  236. JobRequest::Mailboxes(_, _) => write!(f, "JobRequest::Mailboxes"),
  237. JobRequest::Fetch(hash, _, _) => write!(f, "JobRequest::Fetch({})", hash),
  238. JobRequest::IsOnline(_, _) => write!(f, "JobRequest::IsOnline"),
  239. JobRequest::Refresh(_, _, _) => write!(f, "JobRequest::Refresh"),
  240. JobRequest::SetFlags(_, _, _) => write!(f, "JobRequest::SetFlags"),
  241. JobRequest::SaveMessage { .. } => write!(f, "JobRequest::SaveMessage"),
  242. JobRequest::CopyTo(_, _, _) => write!(f, "JobRequest::CopyTo"),
  243. JobRequest::DeleteMessages(_, _, _) => write!(f, "JobRequest::DeleteMessages"),
  244. JobRequest::CreateMailbox { .. } => write!(f, "JobRequest::CreateMailbox"),
  245. JobRequest::DeleteMailbox { mailbox_hash, .. } => {
  246. write!(f, "JobRequest::DeleteMailbox({})", mailbox_hash)
  247. }
  248. //JobRequest::RenameMailbox,
  249. JobRequest::Search(_) => write!(f, "JobRequest::Search"),
  250. JobRequest::AsBytes(_) => write!(f, "JobRequest::AsBytes"),
  251. JobRequest::SetMailboxPermissions(_, _, _) => {
  252. write!(f, "JobRequest::SetMailboxPermissions")
  253. }
  254. JobRequest::SetMailboxSubscription(_, _, _) => {
  255. write!(f, "JobRequest::SetMailboxSubscription")
  256. }
  257. JobRequest::Watch { .. } => write!(f, "JobRequest::Watch"),
  258. JobRequest::SendMessage => write!(f, "JobRequest::SendMessage"),
  259. JobRequest::SendMessageBackground(_, _) => {
  260. write!(f, "JobRequest::SendMessageBackground")
  261. }
  262. }
  263. }
  264. }
  265. impl core::fmt::Display for JobRequest {
  266. fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
  267. match self {
  268. JobRequest::Generic { name, .. } => write!(f, "{}", name),
  269. JobRequest::Mailboxes(_, _) => write!(f, "Get mailbox list"),
  270. JobRequest::Fetch(_, _, _) => write!(f, "Mailbox fetch"),
  271. JobRequest::IsOnline(_, _) => write!(f, "Online status check"),
  272. JobRequest::Refresh(_, _, _) => write!(f, "Refresh mailbox"),
  273. JobRequest::SetFlags(batch, _, _) => write!(
  274. f,
  275. "Set flags for {} message{}",
  276. batch.len(),
  277. if batch.len() == 1 { "" } else { "s" }
  278. ),
  279. JobRequest::SaveMessage { .. } => write!(f, "Save message"),
  280. JobRequest::CopyTo(_, _, _) => write!(f, "Copy message."),
  281. JobRequest::DeleteMessages(batch, _, _) => write!(
  282. f,
  283. "Delete {} message{}",
  284. batch.len(),
  285. if batch.len() == 1 { "" } else { "s" }
  286. ),
  287. JobRequest::CreateMailbox { path, .. } => write!(f, "Create mailbox {}", path),
  288. JobRequest::DeleteMailbox { .. } => write!(f, "Delete mailbox"),
  289. //JobRequest::RenameMailbox,
  290. JobRequest::Search(_) => write!(f, "Search"),
  291. JobRequest::AsBytes(_) => write!(f, "Message body fetch"),
  292. JobRequest::SetMailboxPermissions(_, _, _) => write!(f, "Set mailbox permissions"),
  293. JobRequest::SetMailboxSubscription(_, _, _) => write!(f, "Set mailbox subscription"),
  294. JobRequest::Watch { .. } => write!(f, "Background watch"),
  295. JobRequest::SendMessageBackground(_, _) | JobRequest::SendMessage => {
  296. write!(f, "Sending message")
  297. }
  298. }
  299. }
  300. }
  301. impl JobRequest {
  302. pub fn is_watch(&self) -> bool {
  303. match self {
  304. JobRequest::Watch { .. } => true,
  305. _ => false,
  306. }
  307. }
  308. pub fn is_fetch(&self, mailbox_hash: MailboxHash) -> bool {
  309. match self {
  310. JobRequest::Fetch(h, _, _) if *h == mailbox_hash => true,
  311. _ => false,
  312. }
  313. }
  314. pub fn is_online(&self) -> bool {
  315. match self {
  316. JobRequest::IsOnline(_, _) => true,
  317. _ => false,
  318. }
  319. }
  320. }
  321. impl Drop for Account {
  322. fn drop(&mut self) {
  323. if let Ok(data_dir) = xdg::BaseDirectories::with_profile("meli", &self.name) {
  324. if let Ok(data) = data_dir.place_data_file("addressbook") {
  325. /* place result in cache directory */
  326. let f = match fs::File::create(data) {
  327. Ok(f) => f,
  328. Err(e) => {
  329. eprintln!("{}", e);
  330. return;
  331. }
  332. };
  333. let metadata = f.metadata().unwrap();
  334. let mut permissions = metadata.permissions();
  335. permissions.set_mode(0o600); // Read/write for owner only.
  336. f.set_permissions(permissions).unwrap();
  337. let writer = io::BufWriter::new(f);
  338. if let Err(err) = serde_json::to_writer(writer, &self.address_book) {
  339. eprintln!("{}", err);
  340. return;
  341. };
  342. };
  343. /*
  344. if let Ok(data) = data_dir.place_data_file("mailbox") {
  345. /* place result in cache directory */
  346. let f = match fs::File::create(data) {
  347. Ok(f) => f,
  348. Err(e) => {
  349. eprintln!("{}", e);
  350. return;
  351. }
  352. };
  353. let metadata = f.metadata().unwrap();
  354. let mut permissions = metadata.permissions();
  355. permissions.set_mode(0o600); // Read/write for owner only.
  356. f.set_permissions(permissions).unwrap();
  357. let writer = io::BufWriter::new(f);
  358. if let Err(err) = bincode::serialize_into(writer, &self.collection) {
  359. eprintln!("{}", err);
  360. };
  361. };
  362. */
  363. }
  364. }
  365. }
  366. #[derive(Serialize, Debug, Clone, Default)]
  367. pub struct MailboxNode {
  368. pub hash: MailboxHash,
  369. pub depth: usize,
  370. pub indentation: u32,
  371. pub has_sibling: bool,
  372. pub children: Vec<MailboxNode>,
  373. }
  374. impl Account {
  375. pub fn new(
  376. hash: AccountHash,
  377. name: String,
  378. mut settings: AccountConf,
  379. map: &Backends,
  380. job_executor: Arc<JobExecutor>,
  381. sender: Sender<ThreadEvent>,
  382. event_consumer: BackendEventConsumer,
  383. ) -> Result<Self> {
  384. let s = settings.clone();
  385. let backend = map.get(settings.account().format())(
  386. settings.account(),
  387. Box::new(move |path: &str| {
  388. s.account.subscribed_mailboxes.is_empty()
  389. || (s.mailbox_confs.contains_key(path)
  390. && s.mailbox_confs[path].mailbox_conf().subscribe.is_true())
  391. || s.account
  392. .subscribed_mailboxes
  393. .iter()
  394. .any(|m| path.matches_glob(m))
  395. }),
  396. event_consumer,
  397. )?;
  398. let data_dir = xdg::BaseDirectories::with_profile("meli", &name).unwrap();
  399. let mut address_book = AddressBook::with_account(&settings.account());
  400. if let Ok(data) = data_dir.place_data_file("addressbook") {
  401. if data.exists() {
  402. let reader = io::BufReader::new(fs::File::open(data).unwrap());
  403. let result: result::Result<AddressBook, _> = serde_json::from_reader(reader);
  404. if let Ok(data_t) = result {
  405. for (id, c) in data_t.cards {
  406. if !address_book.card_exists(id) && !c.external_resource() {
  407. address_book.add_card(c);
  408. }
  409. }
  410. }
  411. }
  412. };
  413. if settings.conf.search_backend == crate::conf::SearchBackend::Auto {
  414. if backend.capabilities().supports_search {
  415. settings.conf.search_backend = crate::conf::SearchBackend::None;
  416. } else {
  417. #[cfg(feature = "sqlite3")]
  418. {
  419. settings.conf.search_backend = crate::conf::SearchBackend::Sqlite3;
  420. }
  421. #[cfg(not(feature = "sqlite3"))]
  422. {
  423. settings.conf.search_backend = crate::conf::SearchBackend::None;
  424. }
  425. }
  426. }
  427. let mut active_jobs = HashMap::default();
  428. let mut active_job_instants = BTreeMap::default();
  429. if let Ok(mailboxes_job) = backend.mailboxes() {
  430. if let Ok(online_job) = backend.is_online() {
  431. let (rcvr, handle, job_id) = if backend.capabilities().is_async {
  432. job_executor.spawn_specialized(online_job.then(|_| mailboxes_job))
  433. } else {
  434. job_executor.spawn_blocking(online_job.then(|_| mailboxes_job))
  435. };
  436. active_jobs.insert(job_id, JobRequest::Mailboxes(handle, rcvr));
  437. active_job_instants.insert(std::time::Instant::now(), job_id);
  438. sender
  439. .send(ThreadEvent::UIEvent(UIEvent::StatusEvent(
  440. StatusEvent::NewJob(job_id),
  441. )))
  442. .unwrap();
  443. }
  444. }
  445. Ok(Account {
  446. hash,
  447. name,
  448. is_online: if !backend.capabilities().is_remote {
  449. Ok(())
  450. } else {
  451. Err(MeliError::new("Attempting connection."))
  452. },
  453. mailbox_entries: Default::default(),
  454. mailboxes_order: Default::default(),
  455. tree: Default::default(),
  456. address_book,
  457. sent_mailbox: Default::default(),
  458. collection: Default::default(),
  459. settings,
  460. sender,
  461. job_executor,
  462. active_jobs,
  463. active_job_instants,
  464. event_queue: VecDeque::with_capacity(8),
  465. backend_capabilities: backend.capabilities(),
  466. backend: Arc::new(RwLock::new(backend)),
  467. })
  468. }
  469. fn init(&mut self, mut ref_mailboxes: HashMap<MailboxHash, Mailbox>) -> Result<()> {
  470. self.backend_capabilities = self.backend.read().unwrap().capabilities();
  471. let mut mailbox_entries: IndexMap<MailboxHash, MailboxEntry> =
  472. IndexMap::with_capacity_and_hasher(ref_mailboxes.len(), Default::default());
  473. let mut mailboxes_order: Vec<MailboxHash> = Vec::with_capacity(ref_mailboxes.len());
  474. let mut sent_mailbox = None;
  475. /* Keep track of which mailbox config values we encounter in the actual mailboxes returned
  476. * by the backend. For each of the actual mailboxes, delete the key from the hash set. If
  477. * any are left, they are misconfigurations (eg misspelling) and a warning is shown to the
  478. * user */
  479. let mut mailbox_conf_hash_set = self
  480. .settings
  481. .mailbox_confs
  482. .keys()
  483. .cloned()
  484. .collect::<HashSet<String>>();
  485. for f in ref_mailboxes.values_mut() {
  486. if let Some(conf) = self.settings.mailbox_confs.get_mut(f.path()) {
  487. mailbox_conf_hash_set.remove(f.path());
  488. conf.mailbox_conf.usage = if f.special_usage() != SpecialUsageMailbox::Normal {
  489. Some(f.special_usage())
  490. } else {
  491. let tmp = SpecialUsageMailbox::detect_usage(f.name());
  492. if tmp != Some(SpecialUsageMailbox::Normal) && tmp != None {
  493. let _ = f.set_special_usage(tmp.unwrap());
  494. }
  495. tmp
  496. };
  497. match conf.mailbox_conf.usage {
  498. Some(SpecialUsageMailbox::Sent) => {
  499. sent_mailbox = Some(f.hash());
  500. }
  501. None => {
  502. if f.special_usage() == SpecialUsageMailbox::Sent {
  503. sent_mailbox = Some(f.hash());
  504. }
  505. }
  506. _ => {}
  507. }
  508. mailbox_entries.insert(
  509. f.hash(),
  510. MailboxEntry {
  511. ref_mailbox: f.clone(),
  512. name: f.path().to_string(),
  513. status: MailboxStatus::None,
  514. conf: conf.clone(),
  515. },
  516. );
  517. } else {
  518. let mut new = FileMailboxConf::default();
  519. new.mailbox_conf.usage = if f.special_usage() != SpecialUsageMailbox::Normal {
  520. Some(f.special_usage())
  521. } else {
  522. let tmp = SpecialUsageMailbox::detect_usage(f.name());
  523. if tmp != Some(SpecialUsageMailbox::Normal) && tmp != None {
  524. let _ = f.set_special_usage(tmp.unwrap());
  525. }
  526. tmp
  527. };
  528. if new.mailbox_conf.usage == Some(SpecialUsageMailbox::Sent) {
  529. sent_mailbox = Some(f.hash());
  530. }
  531. mailbox_entries.insert(
  532. f.hash(),
  533. MailboxEntry {
  534. ref_mailbox: f.clone(),
  535. name: f.path().to_string(),
  536. status: MailboxStatus::None,
  537. conf: new,
  538. },
  539. );
  540. }
  541. }
  542. for missing_mailbox in &mailbox_conf_hash_set {
  543. melib::log(
  544. format!(
  545. "Account `{}` mailbox `{}` configured but not present in account's mailboxes. Is it misspelled?",
  546. &self.name, missing_mailbox,
  547. ),
  548. melib::WARN,
  549. );
  550. self.sender
  551. .send(ThreadEvent::UIEvent(UIEvent::StatusEvent(
  552. StatusEvent::DisplayMessage(format!(
  553. "Account `{}` mailbox `{}` configured but not present in account's mailboxes. Is it misspelled?",
  554. &self.name, missing_mailbox,
  555. )),
  556. )))
  557. .unwrap();
  558. }
  559. if !mailbox_conf_hash_set.is_empty() {
  560. let mut mailbox_comma_sep_list_string = mailbox_entries
  561. .values()
  562. .map(|e| e.name.as_str())
  563. .fold(String::new(), |mut acc, el| {
  564. acc.push('`');
  565. acc.push_str(el);
  566. acc.push('`');
  567. acc.push_str(", ");
  568. acc
  569. });
  570. mailbox_comma_sep_list_string.drain(mailbox_comma_sep_list_string.len() - 2..);
  571. melib::log(
  572. format!(
  573. "Account `{}` has the following mailboxes: [{}]",
  574. &self.name, mailbox_comma_sep_list_string,
  575. ),
  576. melib::WARN,
  577. );
  578. }
  579. let mut tree: Vec<MailboxNode> = Vec::new();
  580. for (h, f) in ref_mailboxes.iter() {
  581. if !f.is_subscribed() {
  582. /* Skip unsubscribed mailbox */
  583. continue;
  584. }
  585. mailbox_entries.entry(*h).and_modify(|entry| {
  586. if entry.conf.mailbox_conf.autoload
  587. || entry.ref_mailbox.special_usage() == SpecialUsageMailbox::Inbox
  588. {
  589. let total = entry.ref_mailbox.count().ok().unwrap_or((0, 0)).1;
  590. entry.status = MailboxStatus::Parsing(0, total);
  591. if let Ok(mailbox_job) = self.backend.write().unwrap().fetch(*h) {
  592. let mailbox_job = mailbox_job.into_future();
  593. let (rcvr, handle, job_id) = if self.backend_capabilities.is_async {
  594. self.job_executor.spawn_specialized(mailbox_job)
  595. } else {
  596. self.job_executor.spawn_blocking(mailbox_job)
  597. };
  598. self.sender
  599. .send(ThreadEvent::UIEvent(UIEvent::StatusEvent(
  600. StatusEvent::NewJob(job_id),
  601. )))
  602. .unwrap();
  603. self.active_jobs
  604. .insert(job_id, JobRequest::Fetch(*h, handle, rcvr));
  605. self.active_job_instants
  606. .insert(std::time::Instant::now(), job_id);
  607. }
  608. }
  609. });
  610. self.collection.new_mailbox(*h);
  611. }
  612. build_mailboxes_order(&mut tree, &mailbox_entries, &mut mailboxes_order);
  613. self.mailboxes_order = mailboxes_order;
  614. self.mailbox_entries = mailbox_entries;
  615. self.tree = tree;
  616. self.sent_mailbox = sent_mailbox;
  617. Ok(())
  618. }
  619. pub fn reload(&mut self, event: RefreshEvent, mailbox_hash: MailboxHash) -> Option<UIEvent> {
  620. if !self.mailbox_entries[&mailbox_hash].status.is_available()
  621. && !self.mailbox_entries[&mailbox_hash].status.is_parsing()
  622. {
  623. self.event_queue.push_back((mailbox_hash, event));
  624. return None;
  625. }
  626. {
  627. //let mailbox: &mut Mailbox = self.mailboxes[idx].as_mut().unwrap().as_mut().unwrap();
  628. match event.kind {
  629. RefreshEventKind::Update(old_hash, envelope) => {
  630. if !self.collection.contains_key(&old_hash) {
  631. return self.reload(
  632. RefreshEvent {
  633. account_hash: event.account_hash,
  634. mailbox_hash: event.mailbox_hash,
  635. kind: RefreshEventKind::Create(envelope),
  636. },
  637. mailbox_hash,
  638. );
  639. }
  640. #[cfg(feature = "sqlite3")]
  641. if self.settings.conf.search_backend == crate::conf::SearchBackend::Sqlite3 {
  642. match crate::sqlite3::remove(old_hash).map(|_| {
  643. crate::sqlite3::insert(
  644. (*envelope).clone(),
  645. self.backend.clone(),
  646. self.name.clone(),
  647. )
  648. }) {
  649. Err(err) => {
  650. melib::log(
  651. format!(
  652. "Failed to update envelope {} in cache: {}",
  653. envelope.message_id_display(),
  654. err.to_string()
  655. ),
  656. melib::ERROR,
  657. );
  658. }
  659. Ok(job) => {
  660. let (channel, handle, job_id) =
  661. self.job_executor.spawn_blocking(job);
  662. self.insert_job(
  663. job_id,
  664. JobRequest::Generic {
  665. name: format!(
  666. "Update envelope {} in sqlite3 cache",
  667. envelope.message_id_display()
  668. )
  669. .into(),
  670. handle,
  671. channel,
  672. logging_level: melib::LoggingLevel::TRACE,
  673. on_finish: None,
  674. },
  675. );
  676. }
  677. }
  678. }
  679. self.collection.update(old_hash, *envelope, mailbox_hash);
  680. return Some(EnvelopeUpdate(old_hash));
  681. }
  682. RefreshEventKind::NewFlags(env_hash, (flags, tags)) => {
  683. if !self.collection.contains_key(&env_hash) {
  684. return None;
  685. }
  686. self.collection
  687. .envelopes
  688. .write()
  689. .unwrap()
  690. .entry(env_hash)
  691. .and_modify(|entry| {
  692. entry.labels_mut().clear();
  693. entry
  694. .labels_mut()
  695. .extend(tags.into_iter().map(|h| tag_hash!(h)));
  696. entry.set_flags(flags);
  697. });
  698. #[cfg(feature = "sqlite3")]
  699. if self.settings.conf.search_backend == crate::conf::SearchBackend::Sqlite3 {
  700. match crate::sqlite3::remove(env_hash).map(|_| {
  701. crate::sqlite3::insert(
  702. self.collection.envelopes.read().unwrap()[&env_hash].clone(),
  703. self.backend.clone(),
  704. self.name.clone(),
  705. )
  706. }) {
  707. Ok(job) => {
  708. let (channel, handle, job_id) =
  709. self.job_executor.spawn_blocking(job);
  710. self.insert_job(
  711. job_id,
  712. JobRequest::Generic {
  713. name: format!(
  714. "Update envelope {} in sqlite3 cache",
  715. self.collection.envelopes.read().unwrap()[&env_hash]
  716. .message_id_display()
  717. )
  718. .into(),
  719. handle,
  720. channel,
  721. logging_level: melib::LoggingLevel::TRACE,
  722. on_finish: None,
  723. },
  724. );
  725. }
  726. Err(err) => {
  727. melib::log(
  728. format!(
  729. "Failed to update envelope {} in cache: {}",
  730. self.collection.envelopes.read().unwrap()[&env_hash]
  731. .message_id_display(),
  732. err.to_string()
  733. ),
  734. melib::ERROR,
  735. );
  736. }
  737. }
  738. }
  739. self.collection.update_flags(env_hash, mailbox_hash);
  740. return Some(EnvelopeUpdate(env_hash));
  741. }
  742. RefreshEventKind::Rename(old_hash, new_hash) => {
  743. debug!("rename {} to {}", old_hash, new_hash);
  744. if !self.collection.rename(old_hash, new_hash, mailbox_hash) {
  745. return Some(EnvelopeRename(old_hash, new_hash));
  746. }
  747. #[cfg(feature = "sqlite3")]
  748. if self.settings.conf.search_backend == crate::conf::SearchBackend::Sqlite3 {
  749. match crate::sqlite3::remove(old_hash).map(|_| {
  750. crate::sqlite3::insert(
  751. self.collection.envelopes.read().unwrap()[&new_hash].clone(),
  752. self.backend.clone(),
  753. self.name.clone(),
  754. )
  755. }) {
  756. Err(err) => {
  757. melib::log(
  758. format!(
  759. "Failed to update envelope {} in cache: {}",
  760. &self.collection.envelopes.read().unwrap()[&new_hash]
  761. .message_id_display(),
  762. err.to_string()
  763. ),
  764. melib::ERROR,
  765. );
  766. }
  767. Ok(job) => {
  768. let (channel, handle, job_id) =
  769. self.job_executor.spawn_blocking(job);
  770. self.insert_job(
  771. job_id,
  772. JobRequest::Generic {
  773. name: format!(
  774. "Update envelope {} in sqlite3 cache",
  775. self.collection.envelopes.read().unwrap()[&new_hash]
  776. .message_id_display()
  777. )
  778. .into(),
  779. handle,
  780. channel,
  781. logging_level: melib::LoggingLevel::TRACE,
  782. on_finish: None,
  783. },
  784. );
  785. }
  786. }
  787. }
  788. return Some(EnvelopeRename(old_hash, new_hash));
  789. }
  790. RefreshEventKind::Create(envelope) => {
  791. let env_hash = envelope.hash();
  792. if self.collection.contains_key(&env_hash)
  793. && self
  794. .collection
  795. .get_mailbox(mailbox_hash)
  796. .contains(&env_hash)
  797. {
  798. return None;
  799. }
  800. let (is_seen, is_draft) =
  801. { (envelope.is_seen(), envelope.flags().contains(Flag::DRAFT)) };
  802. let (subject, from) = {
  803. (
  804. envelope.subject().into_owned(),
  805. envelope.field_from_to_string(),
  806. )
  807. };
  808. #[cfg(feature = "sqlite3")]
  809. if self.settings.conf.search_backend == crate::conf::SearchBackend::Sqlite3 {
  810. let (channel, handle, job_id) =
  811. self.job_executor.spawn_blocking(crate::sqlite3::insert(
  812. (*envelope).clone(),
  813. self.backend.clone(),
  814. self.name.clone(),
  815. ));
  816. self.insert_job(
  817. job_id,
  818. JobRequest::Generic {
  819. name: format!(
  820. "Update envelope {} in sqlite3 cache",
  821. envelope.message_id_display()
  822. )
  823. .into(),
  824. handle,
  825. channel,
  826. logging_level: melib::LoggingLevel::TRACE,
  827. on_finish: None,
  828. },
  829. );
  830. }
  831. if self.collection.insert(*envelope, mailbox_hash) {
  832. /* is a duplicate */
  833. return None;
  834. }
  835. if self.mailbox_entries[&mailbox_hash]
  836. .conf
  837. .mailbox_conf
  838. .ignore
  839. .is_true()
  840. {
  841. return Some(UIEvent::MailboxUpdate((self.hash, mailbox_hash)));
  842. }
  843. let thread_hash = self.collection.get_env(env_hash).thread();
  844. if self
  845. .collection
  846. .get_threads(mailbox_hash)
  847. .thread_nodes()
  848. .contains_key(&thread_hash)
  849. {
  850. let thread = self.collection.get_threads(mailbox_hash).find_group(
  851. self.collection.get_threads(mailbox_hash)[&thread_hash].group,
  852. );
  853. if self
  854. .collection
  855. .get_threads(mailbox_hash)
  856. .thread_ref(thread)
  857. .snoozed()
  858. {
  859. return Some(UIEvent::MailboxUpdate((self.hash, mailbox_hash)));
  860. }
  861. }
  862. if is_seen || is_draft {
  863. return Some(UIEvent::MailboxUpdate((self.hash, mailbox_hash)));
  864. }
  865. return Some(Notification(
  866. Some(format!("new e-mail from: {}", from)),
  867. format!(
  868. "{}\n{} {}",
  869. subject,
  870. self.name,
  871. self.mailbox_entries[&mailbox_hash].name()
  872. ),
  873. Some(crate::types::NotificationType::NewMail),
  874. ));
  875. }
  876. RefreshEventKind::Remove(env_hash) => {
  877. if !self.collection.contains_key(&env_hash) {
  878. return None;
  879. }
  880. #[cfg(feature = "sqlite3")]
  881. if self.settings.conf.search_backend == crate::conf::SearchBackend::Sqlite3 {
  882. if let Err(err) = crate::sqlite3::remove(env_hash) {
  883. let envelopes = self.collection.envelopes.read();
  884. let envelopes = envelopes.unwrap();
  885. melib::log(
  886. format!(
  887. "Failed to remove envelope {} [{}] in cache: {}",
  888. &envelopes[&env_hash].message_id_display(),
  889. env_hash,
  890. err.to_string()
  891. ),
  892. melib::ERROR,
  893. );
  894. }
  895. }
  896. let thread_hash = self.collection.get_env(env_hash).thread();
  897. if !self
  898. .collection
  899. .get_threads(mailbox_hash)
  900. .thread_nodes()
  901. .contains_key(&thread_hash)
  902. {
  903. return None;
  904. }
  905. let thread_hash = self
  906. .collection
  907. .get_threads(mailbox_hash)
  908. .find_group(self.collection.get_threads(mailbox_hash)[&thread_hash].group);
  909. self.collection.remove(env_hash, mailbox_hash);
  910. return Some(EnvelopeRemove(env_hash, thread_hash));
  911. }
  912. RefreshEventKind::Rescan => {
  913. self.watch();
  914. }
  915. RefreshEventKind::Failure(err) => {
  916. debug!("RefreshEvent Failure: {}", err.to_string());
  917. while let