🐝 I really like where this mua is(was?) headed, but it seems as though there has not been much activity recently.
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.

1328 lines
50 KiB

4 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 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 melib::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
  26. use melib::backends::{
  27. AccountHash, BackendOp, Backends, MailBackend, Mailbox, MailboxHash, NotifyFn, ReadOnlyOp,
  28. RefreshEvent, RefreshEventConsumer, RefreshEventKind, SpecialUsageMailbox,
  29. };
  30. use melib::email::*;
  31. use melib::error::{MeliError, Result};
  32. use melib::text_processing::GlobMatch;
  33. use melib::thread::{SortField, SortOrder, ThreadNode, ThreadNodeHash, Threads};
  34. use melib::AddressBook;
  35. use melib::Collection;
  36. use smallvec::SmallVec;
  37. use std::collections::{HashMap, HashSet};
  38. use crate::types::UIEvent::{self, EnvelopeRemove, EnvelopeRename, EnvelopeUpdate, Notification};
  39. use crate::{StatusEvent, ThreadEvent};
  40. use crossbeam::Sender;
  41. use std::collections::VecDeque;
  42. use std::fs;
  43. use std::io;
  44. use std::ops::{Index, IndexMut};
  45. use std::os::unix::fs::PermissionsExt;
  46. use std::result;
  47. use std::sync::{Arc, RwLock};
  48. pub type Worker = Option<Async<Result<Vec<Envelope>>>>;
  49. #[derive(Debug)]
  50. pub enum MailboxStatus {
  51. Available,
  52. Failed(MeliError),
  53. /// first argument is done work, and second is total work
  54. Parsing(usize, usize),
  55. None,
  56. }
  57. impl Default for MailboxStatus {
  58. fn default() -> Self {
  59. MailboxStatus::None
  60. }
  61. }
  62. impl MailboxStatus {
  63. pub fn is_available(&self) -> bool {
  64. if let MailboxStatus::Available = self {
  65. true
  66. } else {
  67. false
  68. }
  69. }
  70. pub fn is_parsing(&self) -> bool {
  71. if let MailboxStatus::Parsing(_, _) = self {
  72. true
  73. } else {
  74. false
  75. }
  76. }
  77. }
  78. #[derive(Debug)]
  79. pub struct MailboxEntry {
  80. pub status: MailboxStatus,
  81. pub name: String,
  82. pub ref_mailbox: Mailbox,
  83. pub conf: FileMailboxConf,
  84. pub worker: Worker,
  85. }
  86. impl MailboxEntry {
  87. pub fn status(&self) -> String {
  88. match self.status {
  89. MailboxStatus::Available => self.name().to_string(),
  90. MailboxStatus::Failed(ref e) => e.to_string(),
  91. MailboxStatus::None => "Retrieving mailbox".to_string(),
  92. MailboxStatus::Parsing(done, total) => {
  93. format!("Parsing messages. [{}/{}]", done, total)
  94. }
  95. }
  96. }
  97. pub fn name(&self) -> &str {
  98. &self.name
  99. }
  100. }
  101. #[derive(Debug)]
  102. pub struct Account {
  103. pub index: usize,
  104. name: String,
  105. hash: AccountHash,
  106. pub is_online: bool,
  107. pub(crate) mailbox_entries: HashMap<MailboxHash, MailboxEntry>,
  108. pub(crate) mailboxes_order: Vec<MailboxHash>,
  109. tree: Vec<MailboxNode>,
  110. sent_mailbox: Option<MailboxHash>,
  111. pub(crate) collection: Collection,
  112. pub(crate) address_book: AddressBook,
  113. pub(crate) work_context: WorkContext,
  114. pub(crate) settings: AccountConf,
  115. pub(crate) backend: Arc<RwLock<Box<dyn MailBackend>>>,
  116. sender: Sender<ThreadEvent>,
  117. event_queue: VecDeque<(MailboxHash, RefreshEvent)>,
  118. notify_fn: Arc<NotifyFn>,
  119. }
  120. impl Drop for Account {
  121. fn drop(&mut self) {
  122. if let Ok(data_dir) = xdg::BaseDirectories::with_profile("meli", &self.name) {
  123. if let Ok(data) = data_dir.place_data_file("addressbook") {
  124. /* place result in cache directory */
  125. let f = match fs::File::create(data) {
  126. Ok(f) => f,
  127. Err(e) => {
  128. eprintln!("{}", e);
  129. return;
  130. }
  131. };
  132. let metadata = f.metadata().unwrap();
  133. let mut permissions = metadata.permissions();
  134. permissions.set_mode(0o600); // Read/write for owner only.
  135. f.set_permissions(permissions).unwrap();
  136. let writer = io::BufWriter::new(f);
  137. if let Err(err) = serde_json::to_writer(writer, &self.address_book) {
  138. eprintln!("{}", err);
  139. return;
  140. };
  141. };
  142. /*
  143. if let Ok(data) = data_dir.place_data_file("mailbox") {
  144. /* place result in cache directory */
  145. let f = match fs::File::create(data) {
  146. Ok(f) => f,
  147. Err(e) => {
  148. eprintln!("{}", e);
  149. return;
  150. }
  151. };
  152. let metadata = f.metadata().unwrap();
  153. let mut permissions = metadata.permissions();
  154. permissions.set_mode(0o600); // Read/write for owner only.
  155. f.set_permissions(permissions).unwrap();
  156. let writer = io::BufWriter::new(f);
  157. if let Err(err) = bincode::serialize_into(writer, &self.collection) {
  158. eprintln!("{}", err);
  159. };
  160. };
  161. */
  162. }
  163. }
  164. }
  165. #[derive(Serialize, Debug, Clone, Default)]
  166. pub struct MailboxNode {
  167. pub hash: MailboxHash,
  168. pub depth: usize,
  169. pub children: Vec<MailboxNode>,
  170. }
  171. impl Account {
  172. pub fn new(
  173. index: usize,
  174. hash: AccountHash,
  175. name: String,
  176. mut settings: AccountConf,
  177. map: &Backends,
  178. work_context: WorkContext,
  179. sender: Sender<ThreadEvent>,
  180. notify_fn: NotifyFn,
  181. ) -> Result<Self> {
  182. let s = settings.clone();
  183. let backend = map.get(settings.account().format())(
  184. settings.account(),
  185. Box::new(move |path: &str| {
  186. s.account.subscribed_mailboxes.is_empty()
  187. || (s.mailbox_confs.contains_key(path)
  188. && s.mailbox_confs[path].mailbox_conf().subscribe.is_true())
  189. || s.account
  190. .subscribed_mailboxes
  191. .iter()
  192. .any(|m| path.matches_glob(m))
  193. }),
  194. )?;
  195. let notify_fn = Arc::new(notify_fn);
  196. let data_dir = xdg::BaseDirectories::with_profile("meli", &name).unwrap();
  197. let mut address_book = AddressBook::with_account(&settings.account());
  198. if let Ok(data) = data_dir.place_data_file("addressbook") {
  199. if data.exists() {
  200. let reader = io::BufReader::new(fs::File::open(data).unwrap());
  201. let result: result::Result<AddressBook, _> = serde_json::from_reader(reader);
  202. if let Ok(data_t) = result {
  203. for (id, c) in data_t.cards {
  204. if !address_book.card_exists(id) && !c.external_resource() {
  205. address_book.add_card(c);
  206. }
  207. }
  208. }
  209. }
  210. };
  211. if settings.account().format() == "imap" {
  212. settings.conf.cache_type = crate::conf::CacheType::None;
  213. }
  214. Ok(Account {
  215. index,
  216. hash,
  217. name,
  218. is_online: false,
  219. mailbox_entries: Default::default(),
  220. mailboxes_order: Default::default(),
  221. tree: Default::default(),
  222. address_book,
  223. sent_mailbox: Default::default(),
  224. collection: Default::default(),
  225. work_context,
  226. settings,
  227. backend: Arc::new(RwLock::new(backend)),
  228. notify_fn,
  229. sender,
  230. event_queue: VecDeque::with_capacity(8),
  231. })
  232. }
  233. fn init(&mut self) {
  234. let mut ref_mailboxes: HashMap<MailboxHash, Mailbox> =
  235. match self.backend.read().unwrap().mailboxes() {
  236. Ok(f) => f,
  237. Err(err) => {
  238. debug!(&err);
  239. return;
  240. }
  241. };
  242. let mut mailbox_entries: HashMap<MailboxHash, MailboxEntry> =
  243. HashMap::with_capacity_and_hasher(ref_mailboxes.len(), Default::default());
  244. let mut mailboxes_order: Vec<MailboxHash> = Vec::with_capacity(ref_mailboxes.len());
  245. let mut sent_mailbox = None;
  246. /* Keep track of which mailbox config values we encounter in the actual mailboxes returned
  247. * by the backend. For each of the actual mailboxes, delete the key from the hash set. If
  248. * any are left, they are misconfigurations (eg misspelling) and a warning is shown to the
  249. * user */
  250. let mut mailbox_conf_hash_set = self
  251. .settings
  252. .mailbox_confs
  253. .keys()
  254. .cloned()
  255. .collect::<HashSet<String>>();
  256. for f in ref_mailboxes.values_mut() {
  257. if let Some(conf) = self.settings.mailbox_confs.get_mut(f.path()) {
  258. mailbox_conf_hash_set.remove(f.path());
  259. conf.mailbox_conf.usage = if f.special_usage() != SpecialUsageMailbox::Normal {
  260. Some(f.special_usage())
  261. } else {
  262. let tmp = SpecialUsageMailbox::detect_usage(f.name());
  263. if tmp != Some(SpecialUsageMailbox::Normal) && tmp != None {
  264. let _ = f.set_special_usage(tmp.unwrap());
  265. }
  266. tmp
  267. };
  268. match conf.mailbox_conf.usage {
  269. Some(SpecialUsageMailbox::Sent) => {
  270. sent_mailbox = Some(f.hash());
  271. }
  272. None => {
  273. if f.special_usage() == SpecialUsageMailbox::Sent {
  274. sent_mailbox = Some(f.hash());
  275. }
  276. }
  277. _ => {}
  278. }
  279. mailbox_entries.insert(
  280. f.hash(),
  281. MailboxEntry {
  282. ref_mailbox: f.clone(),
  283. name: f.path().to_string(),
  284. status: MailboxStatus::None,
  285. conf: conf.clone(),
  286. worker: None,
  287. },
  288. );
  289. } else {
  290. let mut new = FileMailboxConf::default();
  291. new.mailbox_conf.usage = if f.special_usage() != SpecialUsageMailbox::Normal {
  292. Some(f.special_usage())
  293. } else {
  294. let tmp = SpecialUsageMailbox::detect_usage(f.name());
  295. if tmp != Some(SpecialUsageMailbox::Normal) && tmp != None {
  296. let _ = f.set_special_usage(tmp.unwrap());
  297. }
  298. tmp
  299. };
  300. if new.mailbox_conf.usage == Some(SpecialUsageMailbox::Sent) {
  301. sent_mailbox = Some(f.hash());
  302. }
  303. mailbox_entries.insert(
  304. f.hash(),
  305. MailboxEntry {
  306. ref_mailbox: f.clone(),
  307. name: f.path().to_string(),
  308. status: MailboxStatus::None,
  309. conf: new,
  310. worker: None,
  311. },
  312. );
  313. }
  314. }
  315. for missing_mailbox in &mailbox_conf_hash_set {
  316. melib::log(
  317. format!(
  318. "Account `{}` mailbox `{}` configured but not present in account's mailboxes. Is it misspelled?",
  319. &self.name, missing_mailbox,
  320. ),
  321. melib::WARN,
  322. );
  323. self.sender
  324. .send(ThreadEvent::UIEvent(UIEvent::StatusEvent(
  325. StatusEvent::DisplayMessage(format!(
  326. "Account `{}` mailbox `{}` configured but not present in account's mailboxes. Is it misspelled?",
  327. &self.name, missing_mailbox,
  328. )),
  329. )))
  330. .unwrap();
  331. }
  332. if !mailbox_conf_hash_set.is_empty() {
  333. let mut mailbox_comma_sep_list_string = mailbox_entries
  334. .values()
  335. .map(|e| e.name.as_str())
  336. .fold(String::new(), |mut acc, el| {
  337. acc.push('`');
  338. acc.push_str(el);
  339. acc.push('`');
  340. acc.push_str(", ");
  341. acc
  342. });
  343. mailbox_comma_sep_list_string.drain(mailbox_comma_sep_list_string.len() - 2..);
  344. melib::log(
  345. format!(
  346. "Account `{}` has the following mailboxes: [{}]",
  347. &self.name, mailbox_comma_sep_list_string,
  348. ),
  349. melib::WARN,
  350. );
  351. }
  352. let mut tree: Vec<MailboxNode> = Vec::new();
  353. for (h, f) in ref_mailboxes.iter() {
  354. if !f.is_subscribed() {
  355. /* Skip unsubscribed mailbox */
  356. continue;
  357. }
  358. mailbox_entries.entry(*h).and_modify(|entry| {
  359. if entry.conf.mailbox_conf.autoload {
  360. entry.status = MailboxStatus::Parsing(0, 0);
  361. entry.worker = Account::new_worker(
  362. f.clone(),
  363. &mut self.backend,
  364. &self.work_context,
  365. self.notify_fn.clone(),
  366. );
  367. }
  368. });
  369. self.collection.new_mailbox(*h);
  370. }
  371. build_mailboxes_order(&mut tree, &mailbox_entries, &mut mailboxes_order);
  372. self.mailboxes_order = mailboxes_order;
  373. self.mailbox_entries = mailbox_entries;
  374. self.tree = tree;
  375. self.sent_mailbox = sent_mailbox;
  376. }
  377. fn new_worker(
  378. mailbox: Mailbox,
  379. backend: &Arc<RwLock<Box<dyn MailBackend>>>,
  380. work_context: &WorkContext,
  381. notify_fn: Arc<NotifyFn>,
  382. ) -> Worker {
  383. let mut mailbox_handle = backend.write().unwrap().get(&mailbox);
  384. let mut builder = AsyncBuilder::new();
  385. let our_tx = builder.tx();
  386. let mailbox_hash = mailbox.hash();
  387. let priority = match mailbox.special_usage() {
  388. SpecialUsageMailbox::Inbox => 0,
  389. SpecialUsageMailbox::Sent => 1,
  390. SpecialUsageMailbox::Drafts | SpecialUsageMailbox::Trash => 2,
  391. _ => {
  392. 3 * mailbox
  393. .path()
  394. .split(if mailbox.path().contains('/') {
  395. '/'
  396. } else {
  397. '.'
  398. })
  399. .count() as u64
  400. }
  401. };
  402. /* This polling closure needs to be 'static', that is to spawn its own thread instead of
  403. * being assigned to a worker thread. Otherwise the polling closures could fill up the
  404. * workers causing no actual parsing to be done. If we could yield from within the worker
  405. * threads' closures this could be avoided, but it requires green threads.
  406. */
  407. builder.set_priority(priority).set_is_static(true);
  408. let mut w = builder.build(Box::new(move |work_context| {
  409. let name = format!("Parsing {}", mailbox.path());
  410. let work = mailbox_handle.work().unwrap();
  411. work_context.new_work.send(work).unwrap();
  412. let thread_id = std::thread::current().id();
  413. work_context.set_name.send((thread_id, name)).unwrap();
  414. work_context
  415. .set_status
  416. .send((thread_id, "Waiting for subworkers..".to_string()))
  417. .unwrap();
  418. loop {
  419. match debug!(mailbox_handle.poll_block()) {
  420. Ok(s @ AsyncStatus::Payload(_)) => {
  421. our_tx.send(s).unwrap();
  422. debug!("notifying for {}", mailbox_hash);
  423. notify_fn.notify(mailbox_hash);
  424. }
  425. Ok(s @ AsyncStatus::Finished) => {
  426. our_tx.send(s).unwrap();
  427. notify_fn.notify(mailbox_hash);
  428. debug!("exiting");
  429. work_context.finished.send(thread_id).unwrap();
  430. return;
  431. }
  432. Ok(s) => {
  433. our_tx.send(s).unwrap();
  434. }
  435. Err(_) => {
  436. debug!("poll error");
  437. return;
  438. }
  439. }
  440. }
  441. }));
  442. if let Some(w) = w.work() {
  443. work_context.new_work.send(w).unwrap();
  444. }
  445. Some(w)
  446. }
  447. pub fn reload(&mut self, event: RefreshEvent, mailbox_hash: MailboxHash) -> Option<UIEvent> {
  448. if !self.mailbox_entries[&mailbox_hash].status.is_available() {
  449. self.event_queue.push_back((mailbox_hash, event));
  450. return None;
  451. }
  452. let kind = event.kind();
  453. {
  454. //let mailbox: &mut Mailbox = self.mailboxes[idx].as_mut().unwrap().as_mut().unwrap();
  455. match kind {
  456. RefreshEventKind::Update(old_hash, envelope) => {
  457. #[cfg(feature = "sqlite3")]
  458. {
  459. if let Err(err) = crate::sqlite3::remove(old_hash).and_then(|_| {
  460. crate::sqlite3::insert(&envelope, &self.backend, &self.name)
  461. }) {
  462. melib::log(
  463. format!(
  464. "Failed to update envelope {} in cache: {}",
  465. envelope.message_id_display(),
  466. err.to_string()
  467. ),
  468. melib::ERROR,
  469. );
  470. }
  471. }
  472. self.collection.update(old_hash, *envelope, mailbox_hash);
  473. return Some(EnvelopeUpdate(old_hash));
  474. }
  475. RefreshEventKind::NewFlags(env_hash, (flags, tags)) => {
  476. let mut envelopes = self.collection.envelopes.write().unwrap();
  477. envelopes.entry(env_hash).and_modify(|entry| {
  478. for f in tags {
  479. let hash = tag_hash!(f);
  480. if !entry.labels().contains(&hash) {
  481. entry.labels_mut().push(hash);
  482. }
  483. }
  484. entry.set_flags(flags);
  485. });
  486. #[cfg(feature = "sqlite3")]
  487. {
  488. if let Err(err) = crate::sqlite3::remove(env_hash).and_then(|_| {
  489. crate::sqlite3::insert(&envelopes[&env_hash], &self.backend, &self.name)
  490. }) {
  491. melib::log(
  492. format!(
  493. "Failed to update envelope {} in cache: {}",
  494. envelopes[&env_hash].message_id_display(),
  495. err.to_string()
  496. ),
  497. melib::ERROR,
  498. );
  499. }
  500. }
  501. return Some(EnvelopeUpdate(env_hash));
  502. }
  503. RefreshEventKind::Rename(old_hash, new_hash) => {
  504. debug!("rename {} to {}", old_hash, new_hash);
  505. self.collection.rename(old_hash, new_hash, mailbox_hash);
  506. #[cfg(feature = "sqlite3")]
  507. {
  508. let envelopes = self.collection.envelopes.read();
  509. let envelopes = envelopes.unwrap();
  510. if let Err(err) = crate::sqlite3::remove(old_hash).and_then(|_| {
  511. crate::sqlite3::insert(&envelopes[&new_hash], &self.backend, &self.name)
  512. }) {
  513. melib::log(
  514. format!(
  515. "Failed to update envelope {} in cache: {}",
  516. &envelopes[&new_hash].message_id_display(),
  517. err.to_string()
  518. ),
  519. melib::ERROR,
  520. );
  521. }
  522. }
  523. return Some(EnvelopeRename(old_hash, new_hash));
  524. }
  525. RefreshEventKind::Create(envelope) => {
  526. let env_hash = envelope.hash();
  527. if self.collection.contains_key(&env_hash)
  528. && self.collection[&mailbox_hash].contains(&env_hash)
  529. {
  530. return None;
  531. }
  532. let (is_seen, is_draft) =
  533. { (envelope.is_seen(), envelope.flags().contains(Flag::DRAFT)) };
  534. let (subject, from) = {
  535. (
  536. envelope.subject().into_owned(),
  537. envelope.field_from_to_string(),
  538. )
  539. };
  540. #[cfg(feature = "sqlite3")]
  541. {
  542. if let Err(err) =
  543. crate::sqlite3::insert(&envelope, &self.backend, &self.name)
  544. {
  545. melib::log(
  546. format!(
  547. "Failed to insert envelope {} in cache: {}",
  548. envelope.message_id_display(),
  549. err.to_string()
  550. ),
  551. melib::ERROR,
  552. );
  553. }
  554. }
  555. if self.collection.insert(*envelope, mailbox_hash) {
  556. /* is a duplicate */
  557. return None;
  558. }
  559. if self.mailbox_entries[&mailbox_hash]
  560. .conf
  561. .mailbox_conf
  562. .ignore
  563. .is_true()
  564. {
  565. return Some(UIEvent::MailboxUpdate((self.index, mailbox_hash)));
  566. }
  567. let thread = {
  568. let thread_hash = self.collection.get_env(env_hash).thread();
  569. self.collection.threads[&mailbox_hash]
  570. .find_group(self.collection.threads[&mailbox_hash][&thread_hash].group)
  571. };
  572. if self.collection.threads[&mailbox_hash]
  573. .thread_ref(thread)
  574. .snoozed()
  575. {
  576. return Some(UIEvent::MailboxUpdate((self.index, mailbox_hash)));
  577. }
  578. if is_seen || is_draft {
  579. return Some(UIEvent::MailboxUpdate((self.index, mailbox_hash)));
  580. }
  581. return Some(Notification(
  582. Some(format!("new e-mail from: {}", from)),
  583. format!(
  584. "{}\n{} {}",
  585. subject,
  586. self.name,
  587. self.mailbox_entries[&mailbox_hash].name()
  588. ),
  589. Some(crate::types::NotificationType::NewMail),
  590. ));
  591. }
  592. RefreshEventKind::Remove(envelope_hash) => {
  593. #[cfg(feature = "sqlite3")]
  594. {
  595. let envelopes = self.collection.envelopes.read();
  596. let envelopes = envelopes.unwrap();
  597. if let Err(err) = crate::sqlite3::remove(envelope_hash) {
  598. melib::log(
  599. format!(
  600. "Failed to remove envelope {} [{}] in cache: {}",
  601. &envelopes[&envelope_hash].message_id_display(),
  602. envelope_hash,
  603. err.to_string()
  604. ),
  605. melib::ERROR,
  606. );
  607. }
  608. }
  609. self.collection.remove(envelope_hash, mailbox_hash);
  610. return Some(EnvelopeRemove(envelope_hash));
  611. }
  612. RefreshEventKind::Rescan => {
  613. let handle = Account::new_worker(
  614. self.mailbox_entries[&mailbox_hash].ref_mailbox.clone(),
  615. &mut self.backend,
  616. &self.work_context,
  617. self.notify_fn.clone(),
  618. );
  619. self.mailbox_entries
  620. .entry(mailbox_hash)
  621. .and_modify(|entry| {
  622. entry.worker = handle;
  623. });
  624. }
  625. RefreshEventKind::Failure(e) => {
  626. debug!("RefreshEvent Failure: {}", e.to_string());
  627. /*
  628. context
  629. .1
  630. .send(ThreadEvent::UIEvent(UIEvent::Notification(
  631. Some(format!("{} watcher exited with error", &self.name)),
  632. e.to_string(),
  633. Some(crate::types::NotificationType::ERROR),
  634. )))
  635. .expect("Could not send event on main channel");
  636. */
  637. self.watch();
  638. }
  639. }
  640. }
  641. None
  642. }
  643. pub fn refresh(&mut self, mailbox_hash: MailboxHash) -> Result<()> {
  644. if let Some(ref refresh_command) = self.settings.conf().refresh_command {
  645. let child = std::process::Command::new("sh")
  646. .args(&["-c", refresh_command])
  647. .stdin(std::process::Stdio::null())
  648. .stdout(std::process::Stdio::null())
  649. .stderr(std::process::Stdio::piped())
  650. .spawn()?;
  651. self.sender
  652. .send(ThreadEvent::UIEvent(UIEvent::StatusEvent(
  653. StatusEvent::DisplayMessage(format!("Running command {}", refresh_command)),
  654. )))
  655. .unwrap();
  656. self.sender
  657. .send(ThreadEvent::UIEvent(UIEvent::Fork(
  658. crate::ForkType::Generic(child),
  659. )))
  660. .unwrap();
  661. return Ok(());
  662. }
  663. let sender_ = self.sender.clone();
  664. let r = RefreshEventConsumer::new(Box::new(move |r| {
  665. sender_.send(ThreadEvent::from(r)).unwrap();
  666. }));
  667. let mut h = self.backend.write().unwrap().refresh(mailbox_hash, r)?;
  668. self.work_context.new_work.send(h.work().unwrap()).unwrap();
  669. Ok(())
  670. }
  671. pub fn watch(&self) {
  672. if self.settings.account().manual_refresh {
  673. return;
  674. }
  675. let sender_ = self.sender.clone();
  676. let r = RefreshEventConsumer::new(Box::new(move |r| {
  677. sender_.send(ThreadEvent::from(r)).unwrap();
  678. }));
  679. match self
  680. .backend
  681. .read()
  682. .unwrap()
  683. .watch(r, self.work_context.clone())
  684. {
  685. Ok(id) => {
  686. self.sender
  687. .send(ThreadEvent::NewThread(
  688. id,
  689. format!("watching {}", self.name()).into(),
  690. ))
  691. .unwrap();
  692. }
  693. Err(e) => {
  694. self.sender
  695. .send(ThreadEvent::UIEvent(UIEvent::StatusEvent(
  696. StatusEvent::DisplayMessage(e.to_string()),
  697. )))
  698. .unwrap();
  699. }
  700. }
  701. }
  702. pub fn len(&self) -> usize {
  703. self.tree.len()
  704. }
  705. pub fn is_empty(&self) -> bool {
  706. self.tree.is_empty()
  707. }
  708. pub fn list_mailboxes(&self) -> Vec<MailboxNode> {
  709. let mut ret = Vec::with_capacity(self.mailbox_entries.len());
  710. fn rec(node: &MailboxNode, ret: &mut Vec<MailboxNode>) {
  711. ret.push(node.clone());
  712. for c in node.children.iter() {
  713. rec(c, ret);
  714. }
  715. }
  716. for node in &self.tree {
  717. rec(node, &mut ret);
  718. }
  719. ret
  720. }
  721. pub fn mailboxes_order(&self) -> &Vec<MailboxHash> {
  722. &self.mailboxes_order
  723. }
  724. pub fn name(&self) -> &str {
  725. &self.name
  726. }
  727. pub fn load(&mut self, mailbox_hash: MailboxHash) -> result::Result<(), usize> {
  728. if mailbox_hash == 0 {
  729. return Err(0);
  730. }
  731. loop {
  732. match self
  733. .mailbox_entries
  734. .get_mut(&mailbox_hash)
  735. .unwrap()
  736. .worker
  737. .as_mut()
  738. {
  739. None => {
  740. return match self.mailbox_entries[&mailbox_hash].status {
  741. MailboxStatus::Available | MailboxStatus::Parsing(_, _)
  742. if self.collection.mailboxes.contains_key(&mailbox_hash) =>
  743. {
  744. Ok(())
  745. }
  746. MailboxStatus::None => {
  747. let handle = Account::new_worker(
  748. self.mailbox_entries[&mailbox_hash].ref_mailbox.clone(),
  749. &mut self.backend,
  750. &self.work_context,
  751. self.notify_fn.clone(),
  752. );
  753. self.mailbox_entries
  754. .entry(mailbox_hash)
  755. .and_modify(|entry| {
  756. entry.worker = handle;
  757. });
  758. self.collection.new_mailbox(mailbox_hash);
  759. Err(0)
  760. }
  761. _ => Err(0),
  762. }
  763. }
  764. Some(ref mut w) => match debug!(w.poll()) {
  765. Ok(AsyncStatus::NoUpdate) => {
  766. break;
  767. }
  768. Ok(AsyncStatus::Payload(payload)) => {
  769. debug!("got payload in status for {}", mailbox_hash);
  770. if payload.is_err() {
  771. self.mailbox_entries
  772. .entry(mailbox_hash)
  773. .and_modify(|entry| {
  774. entry.status = MailboxStatus::Failed(payload.unwrap_err());
  775. });
  776. self.sender
  777. .send(ThreadEvent::UIEvent(UIEvent::StartupCheck(mailbox_hash)))
  778. .unwrap();
  779. return Err(0);
  780. }
  781. let envelopes = payload
  782. .unwrap()
  783. .into_iter()
  784. .map(|e| (e.hash(), e))
  785. .collect::<HashMap<EnvelopeHash, Envelope>>();
  786. if let Some(updated_mailboxes) =
  787. self.collection
  788. .merge(envelopes, mailbox_hash, self.sent_mailbox)
  789. {
  790. for f in updated_mailboxes {
  791. self.sender
  792. .send(ThreadEvent::UIEvent(UIEvent::StartupCheck(f)))
  793. .unwrap();
  794. }
  795. }
  796. self.sender
  797. .send(ThreadEvent::UIEvent(UIEvent::StartupCheck(mailbox_hash)))
  798. .unwrap();
  799. }
  800. Ok(AsyncStatus::Finished) => {
  801. debug!("got finished in status for {}", mailbox_hash);
  802. self.mailbox_entries
  803. .entry(mailbox_hash)
  804. .and_modify(|entry| {
  805. entry.status = MailboxStatus::Available;
  806. entry.worker = None;
  807. });
  808. self.sender
  809. .send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate((
  810. self.index,
  811. mailbox_hash,
  812. ))))
  813. .unwrap();
  814. }
  815. Ok(AsyncStatus::ProgressReport(n)) => {
  816. self.mailbox_entries
  817. .entry(mailbox_hash)
  818. .and_modify(|entry| match entry.status {
  819. MailboxStatus::Parsing(ref mut d, _) => {
  820. *d += n;
  821. }
  822. _ => {}
  823. });
  824. //return Err(n);
  825. }
  826. _ => {
  827. break;
  828. }
  829. },
  830. };
  831. }
  832. if self.mailbox_entries[&mailbox_hash].status.is_available()
  833. || (self.mailbox_entries[&mailbox_hash].status.is_parsing()
  834. && self.collection.mailboxes.contains_key(&mailbox_hash))
  835. {
  836. Ok(())
  837. } else {
  838. Err(0)
  839. }
  840. }
  841. pub fn save_special(
  842. &self,
  843. bytes: &[u8],
  844. mailbox_type: SpecialUsageMailbox,
  845. flags: Flag,
  846. ) -> Result<()> {
  847. let mut failure = true;
  848. for mailbox in &[
  849. self.special_use_mailbox(mailbox_type),
  850. self.special_use_mailbox(SpecialUsageMailbox::Inbox),
  851. self.special_use_mailbox(SpecialUsageMailbox::Normal),
  852. ] {
  853. if mailbox.is_none() {
  854. continue;
  855. }
  856. let mailbox = mailbox.unwrap();
  857. if let Err(e) = self.save(bytes, mailbox, Some(flags)) {
  858. debug!("{:?} could not save msg", e);
  859. melib::log(
  860. format!(
  861. "Could not save in '{}' mailbox: {}.",
  862. mailbox,
  863. e.to_string()
  864. ),
  865. melib::ERROR,
  866. );
  867. } else {
  868. failure = false;
  869. break;
  870. }
  871. }
  872. if failure {
  873. let file = crate::types::create_temp_file(bytes, None, None, false);
  874. debug!("message saved in {}", file.path.display());
  875. melib::log(
  876. format!(
  877. "Message was stored in {} so that you can restore it manually.",
  878. file.path.display()
  879. ),
  880. melib::INFO,
  881. );
  882. return Err(MeliError::new(format!(
  883. "Message was stored in {} so that you can restore it manually.",
  884. file.path.display()
  885. ))
  886. .set_summary("Could not save in any mailbox"));
  887. }
  888. Ok(())
  889. }
  890. pub fn save(&self, bytes: &[u8], mailbox_hash: MailboxHash, flags: Option<Flag>) -> Result<()> {
  891. if self.settings.account.read_only() {
  892. return Err(MeliError::new(format!(
  893. "Account {} is read-only.",
  894. self.name.as_str()
  895. )));
  896. }
  897. self.backend
  898. .write()
  899. .unwrap()
  900. .save(bytes, mailbox_hash, flags)
  901. }
  902. pub fn delete(&self, env_hash: EnvelopeHash, mailbox_hash: MailboxHash) -> Result<()> {
  903. if self.settings.account.read_only() {
  904. return Err(MeliError::new(format!(
  905. "Account {} is read-only.",
  906. self.name.as_str()
  907. )));
  908. }
  909. self.backend.write().unwrap().delete(env_hash, mailbox_hash)
  910. }
  911. pub fn contains_key(&self, h: EnvelopeHash) -> bool {
  912. self.collection.contains_key(&h)
  913. }
  914. pub fn operation(&self, h: EnvelopeHash) -> Box<dyn BackendOp> {
  915. let operation = self.backend.read().unwrap().operation(h);
  916. if self.settings.account.read_only() {
  917. ReadOnlyOp::new(operation)
  918. } else {
  919. operation
  920. }
  921. }
  922. pub fn thread(&self, h: ThreadNodeHash, f: MailboxHash) -> &ThreadNode {
  923. &self.collection.threads[&f].thread_nodes()[&h]
  924. }
  925. pub fn mailbox_operation(
  926. &mut self,
  927. op: crate::execute::actions::MailboxOperation,
  928. ) -> Result<String> {
  929. use crate::execute::actions::MailboxOperation;
  930. if self.settings.account.read_only() {
  931. return Err(MeliError::new("Account is read-only."));
  932. }
  933. match op {
  934. MailboxOperation::Create(path) => {
  935. let (mailbox_hash, mut mailboxes) = self
  936. .backend
  937. .write()
  938. .unwrap()
  939. .create_mailbox(path.to_string())?;
  940. self.sender
  941. .send(ThreadEvent::UIEvent(UIEvent::MailboxCreate((
  942. self.index,
  943. mailbox_hash,
  944. ))))
  945. .unwrap();
  946. let mut new = FileMailboxConf::default();
  947. new.mailbox_conf.subscribe = super::ToggleFlag::InternalVal(true);
  948. new.mailbox_conf.usage = if mailboxes[&mailbox_hash].special_usage()
  949. != SpecialUsageMailbox::Normal
  950. {
  951. Some(mailboxes[&mailbox_hash].special_usage())
  952. } else {
  953. let tmp = SpecialUsageMailbox::detect_usage(mailboxes[&mailbox_hash].name());
  954. if tmp != Some(SpecialUsageMailbox::Normal) && tmp != None {
  955. mailboxes.entry(mailbox_hash).and_modify(|entry| {
  956. let _ = entry.set_special_usage(tmp.unwrap());
  957. });
  958. }
  959. tmp
  960. };
  961. /* if new mailbox has parent, we need to update its children field */
  962. if let Some(parent_hash) = mailboxes[&mailbox_hash].parent() {
  963. self.mailbox_entries
  964. .entry(parent_hash)
  965. .and_modify(|parent| {
  966. parent.ref_mailbox = mailboxes.remove(&parent_hash).unwrap();
  967. });
  968. }
  969. self.mailbox_entries.insert(
  970. mailbox_hash,
  971. MailboxEntry {
  972. name: mailboxes[&mailbox_hash].path().to_string(),
  973. status: MailboxStatus::Parsing(0, 0),
  974. conf: new,
  975. worker: Account::new_worker(
  976. mailboxes[&mailbox_hash].clone(),
  977. &mut self.backend,
  978. &self.work_context,
  979. self.notify_fn.clone(),
  980. ),
  981. ref_mailbox: mailboxes.remove(&mailbox_hash).unwrap(),
  982. },
  983. );
  984. self.collection
  985. .threads
  986. .insert(mailbox_hash, Threads::default());
  987. self.collection
  988. .mailboxes
  989. .insert(mailbox_hash, Default::default());
  990. build_mailboxes_order(
  991. &mut self.tree,
  992. &self.mailbox_entries,
  993. &mut self.mailboxes_order,
  994. );
  995. Ok(format!("`{}` successfully created.", &path))
  996. }
  997. MailboxOperation::Delete(path) => {
  998. if self.mailbox_entries.len() == 1 {
  999. return Err(MeliError::new("Cannot delete only mailbox."));
  1000. }
  1001. let mailbox_hash = self.mailbox_by_path(&path)?;
  1002. let mut mailboxes = self.backend.write().unwrap().delete_mailbox(mailbox_hash)?;
  1003. self.sender
  1004. .send(ThreadEvent::UIEvent(UIEvent::MailboxDelete((
  1005. self.index,
  1006. mailbox_hash,
  1007. ))))
  1008. .unwrap();
  1009. if let Some(pos) = self.mailboxes_order.iter().position(|&h| h == mailbox_hash) {
  1010. self.mailboxes_order.remove(pos);
  1011. }
  1012. if let Some(pos) = self.tree.iter().position(|n| n.hash == mailbox_hash) {
  1013. self.tree.remove(pos);
  1014. }
  1015. if self.sent_mailbox == Some(mailbox_hash) {
  1016. self.sent_mailbox = None;
  1017. }
  1018. self.collection.threads.remove(&mailbox_hash);
  1019. let deleted_mailbox = self.mailbox_entries.remove(&mailbox_hash).unwrap();
  1020. /* if deleted mailbox had parent, we need to update its children field */
  1021. if let Some(parent_hash) = deleted_mailbox.ref_mailbox.parent() {
  1022. self.mailbox_entries
  1023. .entry(parent_hash)
  1024. .and_modify(|parent| {
  1025. parent.ref_mailbox = mailboxes.remove(&parent_hash).unwrap();
  1026. });
  1027. }
  1028. self.collection.mailboxes.remove(&mailbox_hash);
  1029. build_mailboxes_order(
  1030. &mut self.tree,
  1031. &self.mailbox_entries,
  1032. &mut self.mailboxes_order,
  1033. );
  1034. // FIXME Kill worker as well
  1035. // FIXME remove from settings as well
  1036. Ok(format!(
  1037. "'`{}` has been deleted.",
  1038. &deleted_mailbox.ref_mailbox.path()
  1039. ))
  1040. }
  1041. MailboxOperation::Subscribe(path) => {
  1042. let mailbox_hash = self.mailbox_by_path(&path)?;
  1043. self.backend
  1044. .write()
  1045. .unwrap()
  1046. .set_mailbox_subscription(mailbox_hash, true)?;
  1047. self.mailbox_entries.entry(mailbox_hash).and_modify(|m| {
  1048. m.conf.mailbox_conf.subscribe = super::ToggleFlag::True;
  1049. let _ = m.ref_mailbox.set_is_subscribed(true);
  1050. });
  1051. Ok(format!("'`{}` has been subscribed.", &path))
  1052. }
  1053. MailboxOperation::Unsubscribe(path) => {
  1054. let mailbox_hash = self.mailbox_by_path(&path)?;
  1055. self.backend
  1056. .write()
  1057. .unwrap()
  1058. .set_mailbox_subscription(mailbox_hash, false)?;
  1059. self.mailbox_entries.entry(mailbox_hash).and_modify(|m| {
  1060. m.conf.mailbox_conf.subscribe = super::ToggleFlag::False;
  1061. let _ = m.ref_mailbox.set_is_subscribed(false);
  1062. });
  1063. Ok(format!("'`{}` has been unsubscribed.", &path))
  1064. }
  1065. MailboxOperation::Rename(_, _) => Err(MeliError::new("Not implemented.")),
  1066. MailboxOperation::SetPermissions(_) => Err(MeliError::new("Not implemented.")),
  1067. }
  1068. }
  1069. pub fn special_use_mailbox(&self, special_use: SpecialUsageMailbox) -> Option<MailboxHash> {
  1070. let ret = self
  1071. .mailbox_entries
  1072. .iter()
  1073. .find(|(_, f)| f.conf.mailbox_conf().usage == Some(special_use));
  1074. if let Some(ret) = ret.as_ref() {
  1075. Some(ret.1.ref_mailbox.hash())
  1076. } else {
  1077. None
  1078. }
  1079. }
  1080. /* Call only in Context::is_online, since only Context can launch the watcher threads if an
  1081. * account goes from offline to online. */
  1082. pub fn is_online(&mut self) -> Result<()> {
  1083. if !self.is_online {
  1084. self.backend.write().unwrap().connect();
  1085. }
  1086. let ret = self.backend.read().unwrap().is_online();
  1087. if ret.is_ok() != self.is_online && ret.is_ok() {
  1088. self.init();
  1089. }
  1090. self.is_online = ret.is_ok();
  1091. if !self.is_online {
  1092. self.backend.write().unwrap().connect();
  1093. }
  1094. ret
  1095. }
  1096. pub fn search(
  1097. &self,
  1098. search_term: &str,
  1099. sort: (SortField, SortOrder),
  1100. mailbox_hash: MailboxHash,
  1101. ) -> Result<SmallVec<[EnvelopeHash; 512]>> {
  1102. if self.settings.account().format() == "imap" {
  1103. use melib::parsec::Parser;
  1104. let query = melib::search::query().parse(search_term)?.1;
  1105. return self
  1106. .backend
  1107. .read()
  1108. .unwrap()
  1109. .search(query, Some(mailbox_hash));
  1110. }
  1111. #[cfg(feature = "notmuch")]
  1112. {
  1113. if self.settings.account().format() == "notmuch" {
  1114. let backend_lck = self.backend.read().unwrap();
  1115. let b = (*backend_lck).as_any();
  1116. return if let Some(notmuch_backend) = b.downcast_ref::<melib::backends::NotmuchDb>()
  1117. {
  1118. notmuch_backend.search(search_term)
  1119. } else {
  1120. Err(MeliError::new(
  1121. "Internal error: Could not downcast backend to NotmuchDb",
  1122. ))
  1123. };
  1124. }
  1125. }
  1126. #[cfg(feature = "sqlite3")]
  1127. {
  1128. crate::sqlite3::search(search_term, sort)
  1129. }
  1130. #[cfg(not(feature = "sqlite3"))]
  1131. {
  1132. let mut ret = SmallVec::new();
  1133. let envelopes = self.collection.envelopes.read().unwrap();
  1134. for &env_hash in self.collection[&mailbox_hash].iter() {
  1135. let envelope = &envelopes[&env_hash];
  1136. if envelope.subject().contains(&search_term) {
  1137. ret.push(env_hash);
  1138. continue;
  1139. }
  1140. if envelope.field_from_to_string().contains(&search_term) {
  1141. ret.push(env_hash);
  1142. continue;
  1143. }
  1144. let op = self.operation(env_hash);
  1145. let body = envelope.body(op)?;
  1146. let decoded = decode_rec(&body, None);
  1147. let body_text = String::from_utf8_lossy(&decoded);
  1148. if body_text.contains(&search_term) {
  1149. ret.push(env_hash);
  1150. }
  1151. }
  1152. Ok(ret)
  1153. }
  1154. }
  1155. pub fn mailbox_by_path(&self, path: &str) -> Result<MailboxHash> {
  1156. if let Some((mailbox_hash, _)) = self
  1157. .mailbox_entries
  1158. .iter()
  1159. .find(|(_, f)| f.ref_mailbox.path() == path)
  1160. {
  1161. Ok(*mailbox_hash)
  1162. } else {
  1163. Err(MeliError::new("Mailbox with that path not found."))
  1164. }
  1165. }
  1166. }
  1167. impl Index<&MailboxHash> for Account {
  1168. type Output = MailboxEntry;
  1169. fn index(&self, index: &MailboxHash) -> &MailboxEntry {
  1170. &self.mailbox_entries[index]
  1171. }
  1172. }
  1173. impl IndexMut<&MailboxHash> for Account {
  1174. fn index_mut(&mut self, index: &MailboxHash) -> &mut MailboxEntry {
  1175. self.mailbox_entries.get_mut(index).unwrap()
  1176. }
  1177. }
  1178. fn build_mailboxes_order(
  1179. tree: &mut Vec<MailboxNode>,
  1180. mailbox_entries: &HashMap<MailboxHash, MailboxEntry>,
  1181. mailboxes_order: &mut Vec<MailboxHash>,
  1182. ) {
  1183. tree.clear();
  1184. mailboxes_order.clear();
  1185. for (h, f) in mailbox_entries.iter() {
  1186. if f.ref_mailbox.parent().is_none() {
  1187. fn rec(
  1188. h: MailboxHash,
  1189. mailbox_entries: &HashMap<MailboxHash, MailboxEntry>,
  1190. depth: usize,
  1191. ) -> MailboxNode {
  1192. let mut node = MailboxNode {
  1193. hash: h,
  1194. children: Vec::new(),
  1195. depth,
  1196. };
  1197. for &c in mailbox_entries[&h].ref_mailbox.children() {
  1198. if mailbox_entries.contains_key(&c) {
  1199. node.children.push(rec(c, mailbox_entries, depth + 1));
  1200. }
  1201. }
  1202. node
  1203. };
  1204. tree.push(rec(*h, &mailbox_entries, 0));
  1205. }
  1206. }
  1207. tree.sort_unstable_by(|a, b| {
  1208. if mailbox_entries[&b.hash]
  1209. .ref_mailbox
  1210. .path()
  1211. .eq_ignore_ascii_case("INBOX")
  1212. {
  1213. std::cmp::Ordering::Greater
  1214. } else if mailbox_entries[&a.hash]
  1215. .ref_mailbox
  1216. .path()
  1217. .eq_ignore_ascii_case("INBOX")
  1218. {
  1219. std::cmp::Ordering::Less
  1220. } else {
  1221. mailbox_entries[&a.hash]
  1222. .ref_mailbox
  1223. .path()
  1224. .cmp(&mailbox_entries[&b.hash].ref_mailbox.path())
  1225. }
  1226. });
  1227. let mut stack: SmallVec<[Option<&MailboxNode>; 16]> = SmallVec::new();
  1228. for n in tree.iter_mut() {
  1229. mailboxes_order.push(n.hash);
  1230. n.children.sort_unstable_by(|a, b| {
  1231. if mailbox_entries[&b.hash]
  1232. .ref_mailbox
  1233. .path()
  1234. .eq_ignore_ascii_case("INBOX")
  1235. {
  1236. std::cmp::Ordering::Greater
  1237. } else if mailbox_entries[&a.hash]
  1238. .ref_mailbox
  1239. .path()
  1240. .eq_ignore_ascii_case("INBOX")
  1241. {
  1242. std::cmp::Ordering::Less
  1243. } else {
  1244. mailbox_entries[&a.hash]
  1245. .ref_mailbox
  1246. .path()
  1247. .cmp(&mailbox_entries[&b.hash].ref_mailbox.path())
  1248. }
  1249. });
  1250. stack.extend(n.children.iter().rev().map(Some));
  1251. while let Some(Some(next)) = stack.pop() {
  1252. mailboxes_order.push(next.hash);
  1253. stack.extend(next.children.iter().rev().map(Some));
  1254. }
  1255. }
  1256. }