NeoMutt  2021-10-29-225-gb9986f
Teaching an old dog new tricks
DOXYGEN
mx.c
Go to the documentation of this file.
1 
32 #include "config.h"
33 #include <errno.h>
34 #include <limits.h>
35 #include <locale.h>
36 #include <stdbool.h>
37 #include <string.h>
38 #include <sys/stat.h>
39 #include <time.h>
40 #include <unistd.h>
41 #include "mutt/lib.h"
42 #include "address/lib.h"
43 #include "email/lib.h"
44 #include "core/lib.h"
45 #include "alias/lib.h"
46 #include "mutt.h"
47 #include "mx.h"
48 #include "maildir/lib.h"
49 #include "mbox/lib.h"
50 #include "menu/lib.h"
51 #include "question/lib.h"
52 #include "commands.h"
53 #include "copy.h"
54 #include "hook.h"
55 #include "keymap.h"
56 #include "mutt_globals.h"
57 #include "mutt_header.h"
58 #include "mutt_logging.h"
59 #include "mutt_mailbox.h"
60 #include "muttlib.h"
61 #include "opcodes.h"
62 #include "options.h"
63 #include "protos.h"
64 #ifdef USE_COMP_MBOX
65 #include "compmbox/lib.h"
66 #endif
67 #ifdef USE_IMAP
68 #include "imap/lib.h"
69 #endif
70 #ifdef USE_POP
71 #include "pop/lib.h"
72 #endif
73 #ifdef USE_NNTP
74 #include "nntp/lib.h"
75 #include "nntp/adata.h" // IWYU pragma: keep
76 #include "nntp/mdata.h" // IWYU pragma: keep
77 #endif
78 #ifdef USE_NOTMUCH
79 #include "notmuch/lib.h"
80 #endif
81 #ifdef ENABLE_NLS
82 #include <libintl.h>
83 #endif
84 #ifdef __APPLE__
85 #include <xlocale.h>
86 #endif
87 
88 static const struct Mapping MboxTypeMap[] = {
89  // clang-format off
90  { "mbox", MUTT_MBOX, },
91  { "MMDF", MUTT_MMDF, },
92  { "MH", MUTT_MH, },
93  { "Maildir", MUTT_MAILDIR, },
94  { NULL, 0, },
95  // clang-format on
96 };
97 
98 struct EnumDef MboxTypeDef = {
99  "mbox_type",
100  4,
101  (struct Mapping *) &MboxTypeMap,
102 };
103 
107 const struct MxOps *MxOps[] = {
108 /* These mailboxes can be recognised by their Url scheme */
109 #ifdef USE_IMAP
110  &MxImapOps,
111 #endif
112 #ifdef USE_NOTMUCH
113  &MxNotmuchOps,
114 #endif
115 #ifdef USE_POP
116  &MxPopOps,
117 #endif
118 #ifdef USE_NNTP
119  &MxNntpOps,
120 #endif
121 
122  /* Local mailboxes */
123  &MxMaildirOps,
124  &MxMboxOps,
125  &MxMhOps,
126  &MxMmdfOps,
127 
128 /* If everything else fails... */
129 #ifdef USE_COMP_MBOX
130  &MxCompOps,
131 #endif
132  NULL,
133 };
134 
141 const struct MxOps *mx_get_ops(enum MailboxType type)
142 {
143  for (const struct MxOps **ops = MxOps; *ops; ops++)
144  if ((*ops)->type == type)
145  return *ops;
146 
147  return NULL;
148 }
149 
155 static bool mutt_is_spool(const char *str)
156 {
157  const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
158  if (mutt_str_equal(str, c_spool_file))
159  return true;
160 
161  struct Url *ua = url_parse(str);
162  struct Url *ub = url_parse(c_spool_file);
163 
164  const bool is_spool =
165  ua && ub && (ua->scheme == ub->scheme) &&
166  mutt_istr_equal(ua->host, ub->host) && mutt_istr_equal(ua->path, ub->path) &&
167  (!ua->user || !ub->user || mutt_str_equal(ua->user, ub->user));
168 
169  url_free(&ua);
170  url_free(&ub);
171  return is_spool;
172 }
173 
184 int mx_access(const char *path, int flags)
185 {
186 #ifdef USE_IMAP
187  if (imap_path_probe(path, NULL) == MUTT_IMAP)
188  return imap_access(path);
189 #endif
190 
191  return access(path, flags);
192 }
193 
201 static bool mx_open_mailbox_append(struct Mailbox *m, OpenMailboxFlags flags)
202 {
203  if (!m)
204  return false;
205 
206  struct stat st = { 0 };
207 
208  m->append = true;
209  if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR))
210  {
212 
213  if (m->type == MUTT_UNKNOWN)
214  {
215  if (flags & (MUTT_APPEND | MUTT_NEWFOLDER))
216  {
218  }
219  else
220  {
221  mutt_error(_("%s is not a mailbox"), mailbox_path(m));
222  return false;
223  }
224  }
225 
226  if (m->type == MUTT_MAILBOX_ERROR)
227  {
228  if (stat(mailbox_path(m), &st) == -1)
229  {
230  if (errno == ENOENT)
231  {
232 #ifdef USE_COMP_MBOX
233  if (mutt_comp_can_append(m))
234  m->type = MUTT_COMPRESSED;
235  else
236 #endif
237  m->type = cs_subset_enum(NeoMutt->sub, "mbox_type");
238  flags |= MUTT_APPENDNEW;
239  }
240  else
241  {
243  return false;
244  }
245  }
246  else
247  return false;
248  }
249 
250  m->mx_ops = mx_get_ops(m->type);
251  }
252 
253  if (!m->mx_ops || !m->mx_ops->mbox_open_append)
254  return false;
255 
256  const bool rc = m->mx_ops->mbox_open_append(m, flags);
257  m->opened++;
258  return rc;
259 }
260 
267 bool mx_mbox_ac_link(struct Mailbox *m)
268 {
269  if (!m)
270  return false;
271 
272  if (m->account)
273  return true;
274 
275  struct Account *a = mx_ac_find(m);
276  const bool new_account = !a;
277  if (new_account)
278  {
279  a = account_new(NULL, NeoMutt->sub);
280  a->type = m->type;
281  }
282  if (!mx_ac_add(a, m))
283  {
284  if (new_account)
285  {
286  account_free(&a);
287  }
288  return false;
289  }
290  if (new_account)
291  {
293  }
294  return true;
295 }
296 
304 bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
305 {
306  if (!m)
307  return false;
308 
309  if ((m->type == MUTT_UNKNOWN) && (flags & (MUTT_NEWFOLDER | MUTT_APPEND)))
310  {
311  m->type = cs_subset_enum(NeoMutt->sub, "mbox_type");
312  m->mx_ops = mx_get_ops(m->type);
313  }
314 
315  const bool newly_linked_account = !m->account;
316  if (newly_linked_account)
317  {
318  if (!mx_mbox_ac_link(m))
319  {
320  return false;
321  }
322  }
323 
324  m->verbose = !(flags & MUTT_QUIET);
325  m->readonly = (flags & MUTT_READONLY);
326  m->peekonly = (flags & MUTT_PEEK);
327 
328  if (flags & (MUTT_APPEND | MUTT_NEWFOLDER))
329  {
330  if (!mx_open_mailbox_append(m, flags))
331  {
332  goto error;
333  }
334  return true;
335  }
336 
337  if (m->opened > 0)
338  {
339  m->opened++;
340  return true;
341  }
342 
343  m->size = 0;
344  m->msg_unread = 0;
345  m->msg_flagged = 0;
346  m->rights = MUTT_ACL_ALL;
347 
348  if (m->type == MUTT_UNKNOWN)
349  {
351  m->mx_ops = mx_get_ops(m->type);
352  }
353 
354  if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR) || !m->mx_ops)
355  {
356  if (m->type == MUTT_MAILBOX_ERROR)
358  else if ((m->type == MUTT_UNKNOWN) || !m->mx_ops)
359  mutt_error(_("%s is not a mailbox"), mailbox_path(m));
360  goto error;
361  }
362 
364 
365  /* if the user has a 'push' command in their .neomuttrc, or in a folder-hook,
366  * it will cause the progress messages not to be displayed because
367  * mutt_refresh() will think we are in the middle of a macro. so set a
368  * flag to indicate that we should really refresh the screen. */
369  OptForceRefresh = true;
370 
371  if (m->verbose)
372  mutt_message(_("Reading %s..."), mailbox_path(m));
373 
374  // Clear out any existing emails
375  for (int i = 0; i < m->email_max; i++)
376  {
377  email_free(&m->emails[i]);
378  }
379 
380  m->msg_count = 0;
381  m->msg_unread = 0;
382  m->msg_flagged = 0;
383  m->msg_new = 0;
384  m->msg_deleted = 0;
385  m->msg_tagged = 0;
386  m->vcount = 0;
387 
388  enum MxOpenReturns rc = m->mx_ops->mbox_open(m);
389  m->opened++;
390 
391  if ((rc == MX_OPEN_OK) || (rc == MX_OPEN_ABORT))
392  {
393  if ((flags & MUTT_NOSORT) == 0)
394  {
395  /* avoid unnecessary work since the mailbox is completely unthreaded
396  * to begin with */
397  OptSortSubthreads = false;
398  OptNeedRescore = false;
399  }
400  if (m->verbose)
402  if (rc == MX_OPEN_ABORT)
403  {
404  mutt_error(_("Reading from %s interrupted..."), mailbox_path(m));
405  }
406  }
407  else
408  {
409  goto error;
410  }
411 
412  if (!m->peekonly)
413  m->has_new = false;
414  OptForceRefresh = false;
415 
416  return true;
417 
418 error:
419  mx_fastclose_mailbox(m, newly_linked_account);
420  if (newly_linked_account)
422  return false;
423 }
424 
430 void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
431 {
432  if (!m)
433  return;
434 
435  m->opened--;
436  if (m->opened != 0)
437  return;
438 
439  /* never announce that a mailbox we've just left has new mail.
440  * TODO: really belongs in mx_mbox_close, but this is a nice hook point */
441  if (!m->peekonly)
443 
444  if (m->mx_ops)
445  m->mx_ops->mbox_close(m);
446 
448  mutt_hash_free(&m->id_hash);
450 
451  if (m->emails)
452  {
453  for (int i = 0; i < m->msg_count; i++)
454  {
455  if (!m->emails[i])
456  break;
457  email_free(&m->emails[i]);
458  }
459  }
460 
461  if (m->flags & MB_HIDDEN)
462  {
463  mx_ac_remove(m, keep_account);
464  }
465 }
466 
472 static enum MxStatus sync_mailbox(struct Mailbox *m)
473 {
474  if (!m || !m->mx_ops || !m->mx_ops->mbox_sync)
475  return MX_STATUS_ERROR;
476 
477  if (m->verbose)
478  {
479  /* L10N: Displayed before/as a mailbox is being synced */
480  mutt_message(_("Writing %s..."), mailbox_path(m));
481  }
482 
483  enum MxStatus rc = m->mx_ops->mbox_sync(m);
484  if (rc != MX_STATUS_OK)
485  {
486  mutt_debug(LL_DEBUG2, "mbox_sync returned: %d\n", rc);
487  if ((rc == MX_STATUS_ERROR) && m->verbose)
488  {
489  /* L10N: Displayed if a mailbox sync fails */
490  mutt_error(_("Unable to write %s"), mailbox_path(m));
491  }
492  }
493 
494  return rc;
495 }
496 
503 static int trash_append(struct Mailbox *m)
504 {
505  if (!m)
506  return -1;
507 
508  struct stat st = { 0 };
509  struct stat stc = { 0 };
510  int rc;
511 
512  const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
513  const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
514  if (!c_trash || (m->msg_deleted == 0) || ((m->type == MUTT_MAILDIR) && c_maildir_trash))
515  {
516  return 0;
517  }
518 
519  int delmsgcount = 0;
520  int first_del = -1;
521  for (int i = 0; i < m->msg_count; i++)
522  {
523  struct Email *e = m->emails[i];
524  if (!e)
525  break;
526 
527  if (e->deleted && !e->purge)
528  {
529  if (first_del < 0)
530  first_del = i;
531  delmsgcount++;
532  }
533  }
534 
535  if (delmsgcount == 0)
536  return 0; /* nothing to be done */
537 
538  /* avoid the "append messages" prompt */
539  const bool c_confirm_append = cs_subset_bool(NeoMutt->sub, "confirm_append");
540  cs_subset_str_native_set(NeoMutt->sub, "confirm_append", false, NULL);
541  rc = mutt_save_confirm(c_trash, &st);
542  cs_subset_str_native_set(NeoMutt->sub, "confirm_append", c_confirm_append, NULL);
543  if (rc != 0)
544  {
545  /* L10N: Although we know the precise number of messages, we do not show it to the user.
546  So feel free to use a "generic plural" as plural translation if your language has one. */
547  mutt_error(ngettext("message not deleted", "messages not deleted", delmsgcount));
548  return -1;
549  }
550 
551  if ((lstat(mailbox_path(m), &stc) == 0) && (stc.st_ino == st.st_ino) &&
552  (stc.st_dev == st.st_dev) && (stc.st_rdev == st.st_rdev))
553  {
554  return 0; /* we are in the trash folder: simple sync */
555  }
556 
557 #ifdef USE_IMAP
558  if ((m->type == MUTT_IMAP) && (imap_path_probe(c_trash, NULL) == MUTT_IMAP))
559  {
560  if (imap_fast_trash(m, c_trash) == 0)
561  return 0;
562  }
563 #endif
564 
565  struct Mailbox *m_trash = mx_path_resolve(c_trash);
566  const bool old_append = m_trash->append;
567  if (!mx_mbox_open(m_trash, MUTT_APPEND))
568  {
569  mutt_error(_("Can't open trash folder"));
570  mailbox_free(&m_trash);
571  return -1;
572  }
573 
574  /* continue from initial scan above */
575  for (int i = first_del; i < m->msg_count; i++)
576  {
577  struct Email *e = m->emails[i];
578  if (!e)
579  break;
580 
581  if (e->deleted && !e->purge)
582  {
583  if (mutt_append_message(m_trash, m, e, NULL, MUTT_CM_NO_FLAGS, CH_NO_FLAGS) == -1)
584  {
585  mx_mbox_close(m_trash);
586  // L10N: Displayed if appending to $trash fails when syncing or closing a mailbox
587  mutt_error(_("Unable to append to trash folder"));
588  m_trash->append = old_append;
589  return -1;
590  }
591  }
592  }
593 
594  mx_mbox_close(m_trash);
595  m_trash->append = old_append;
596  if (m_trash->flags == MB_HIDDEN)
597  mailbox_free(&m_trash);
598 
599  return 0;
600 }
601 
616 enum MxStatus mx_mbox_close(struct Mailbox *m)
617 {
618  if (!m)
619  return MX_STATUS_ERROR;
620 
621  const bool c_mail_check_recent =
622  cs_subset_bool(NeoMutt->sub, "mail_check_recent");
623  if (c_mail_check_recent && !m->peekonly)
624  m->has_new = false;
625 
626  if (m->readonly || m->dontwrite || m->append || m->peekonly)
627  {
628  mx_fastclose_mailbox(m, false);
629  return 0;
630  }
631 
632  int i, read_msgs = 0;
633  enum MxStatus rc = MX_STATUS_ERROR;
634  enum QuadOption move_messages = MUTT_NO;
635  enum QuadOption purge = MUTT_YES;
636  struct Buffer *mbox = NULL;
637  struct Buffer *buf = mutt_buffer_pool_get();
638 
639 #ifdef USE_NNTP
640  if ((m->msg_unread != 0) && (m->type == MUTT_NNTP))
641  {
642  struct NntpMboxData *mdata = m->mdata;
643 
644  if (mdata && mdata->adata && mdata->group)
645  {
646  const enum QuadOption c_catchup_newsgroup =
647  cs_subset_quad(NeoMutt->sub, "catchup_newsgroup");
648  enum QuadOption ans =
649  query_quadoption(c_catchup_newsgroup, _("Mark all articles read?"));
650  if (ans == MUTT_ABORT)
651  goto cleanup;
652  if (ans == MUTT_YES)
653  mutt_newsgroup_catchup(m, mdata->adata, mdata->group);
654  }
655  }
656 #endif
657 
658  const bool c_keep_flagged = cs_subset_bool(NeoMutt->sub, "keep_flagged");
659  for (i = 0; i < m->msg_count; i++)
660  {
661  struct Email *e = m->emails[i];
662  if (!e)
663  break;
664 
665  if (!e->deleted && e->read && !(e->flagged && c_keep_flagged))
666  read_msgs++;
667  }
668 
669 #ifdef USE_NNTP
670  /* don't need to move articles from newsgroup */
671  if (m->type == MUTT_NNTP)
672  read_msgs = 0;
673 #endif
674 
675  const enum QuadOption c_move = cs_subset_quad(NeoMutt->sub, "move");
676  if ((read_msgs != 0) && (c_move != MUTT_NO))
677  {
678  bool is_spool;
679  mbox = mutt_buffer_pool_get();
680 
682  if (p)
683  {
684  is_spool = true;
685  mutt_buffer_strcpy(mbox, p);
686  }
687  else
688  {
689  const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
690  mutt_buffer_strcpy(mbox, c_mbox);
691  is_spool = mutt_is_spool(mailbox_path(m)) &&
693  }
694 
695  if (is_spool && !mutt_buffer_is_empty(mbox))
696  {
698  mutt_buffer_printf(buf,
699  /* L10N: The first argument is the number of read messages to be
700  moved, the second argument is the target mailbox. */
701  ngettext("Move %d read message to %s?",
702  "Move %d read messages to %s?", read_msgs),
703  read_msgs, mutt_buffer_string(mbox));
704  move_messages = query_quadoption(c_move, mutt_buffer_string(buf));
705  if (move_messages == MUTT_ABORT)
706  goto cleanup;
707  }
708  }
709 
710  /* There is no point in asking whether or not to purge if we are
711  * just marking messages as "trash". */
712  const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
713  if ((m->msg_deleted != 0) && !((m->type == MUTT_MAILDIR) && c_maildir_trash))
714  {
715  mutt_buffer_printf(buf,
716  ngettext("Purge %d deleted message?",
717  "Purge %d deleted messages?", m->msg_deleted),
718  m->msg_deleted);
719  const enum QuadOption c_delete = cs_subset_quad(NeoMutt->sub, "delete");
720  purge = query_quadoption(c_delete, mutt_buffer_string(buf));
721  if (purge == MUTT_ABORT)
722  goto cleanup;
723  }
724 
725  const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
726  if (c_mark_old && !m->peekonly)
727  {
728  for (i = 0; i < m->msg_count; i++)
729  {
730  struct Email *e = m->emails[i];
731  if (!e)
732  break;
733  if (!e->deleted && !e->old && !e->read)
734  mutt_set_flag(m, e, MUTT_OLD, true);
735  }
736  }
737 
738  if (move_messages)
739  {
740  if (m->verbose)
741  mutt_message(_("Moving read messages to %s..."), mutt_buffer_string(mbox));
742 
743 #ifdef USE_IMAP
744  /* try to use server-side copy first */
745  i = 1;
746 
747  if ((m->type == MUTT_IMAP) && (imap_path_probe(mutt_buffer_string(mbox), NULL) == MUTT_IMAP))
748  {
749  /* add messages for moving, and clear old tags, if any */
750  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
751  for (i = 0; i < m->msg_count; i++)
752  {
753  struct Email *e = m->emails[i];
754  if (!e)
755  break;
756 
757  if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
758  {
759  e->tagged = true;
760  emaillist_add_email(&el, e);
761  }
762  else
763  e->tagged = false;
764  }
765 
766  i = imap_copy_messages(m, &el, mutt_buffer_string(mbox), SAVE_MOVE);
767  emaillist_clear(&el);
768  }
769 
770  if (i == 0) /* success */
772  else if (i == -1) /* horrible error, bail */
773  goto cleanup;
774  else /* use regular append-copy mode */
775 #endif
776  {
777  struct Mailbox *m_read = mx_path_resolve(mutt_buffer_string(mbox));
778  if (!mx_mbox_open(m_read, MUTT_APPEND))
779  {
780  mailbox_free(&m_read);
781  goto cleanup;
782  }
783 
784  for (i = 0; i < m->msg_count; i++)
785  {
786  struct Email *e = m->emails[i];
787  if (!e)
788  break;
789  if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
790  {
791  if (mutt_append_message(m_read, m, e, NULL, MUTT_CM_NO_FLAGS, CH_UPDATE_LEN) == 0)
792  {
793  mutt_set_flag(m, e, MUTT_DELETE, true);
794  mutt_set_flag(m, e, MUTT_PURGE, true);
795  }
796  else
797  {
798  mx_mbox_close(m_read);
799  goto cleanup;
800  }
801  }
802  }
803 
804  mx_mbox_close(m_read);
805  }
806  }
807  else if (!m->changed && (m->msg_deleted == 0))
808  {
809  if (m->verbose)
810  mutt_message(_("Mailbox is unchanged"));
811  if ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF))
812  mbox_reset_atime(m, NULL);
813  mx_fastclose_mailbox(m, false);
814  rc = MX_STATUS_OK;
815  goto cleanup;
816  }
817 
818  /* copy mails to the trash before expunging */
819  const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
820  const struct Mailbox *m_trash = mx_mbox_find(m->account, c_trash);
821  if (purge && (m->msg_deleted != 0) && (m != m_trash))
822  {
823  if (trash_append(m) != 0)
824  goto cleanup;
825  }
826 
827 #ifdef USE_IMAP
828  /* allow IMAP to preserve the deleted flag across sessions */
829  if (m->type == MUTT_IMAP)
830  {
831  const enum MxStatus check = imap_sync_mailbox(m, (purge != MUTT_NO), true);
832  if (check == MX_STATUS_ERROR)
833  {
834  rc = check;
835  goto cleanup;
836  }
837  }
838  else
839 #endif
840  {
841  if (purge == MUTT_NO)
842  {
843  for (i = 0; i < m->msg_count; i++)
844  {
845  struct Email *e = m->emails[i];
846  if (!e)
847  break;
848 
849  e->deleted = false;
850  e->purge = false;
851  }
852  m->msg_deleted = 0;
853  }
854 
855  if (m->changed || (m->msg_deleted != 0))
856  {
857  enum MxStatus check = sync_mailbox(m);
858  if (check != MX_STATUS_OK)
859  {
860  rc = check;
861  goto cleanup;
862  }
863  }
864  }
865 
866  if (m->verbose)
867  {
868  if (move_messages)
869  {
870  mutt_message(_("%d kept, %d moved, %d deleted"),
871  m->msg_count - m->msg_deleted, read_msgs, m->msg_deleted);
872  }
873  else
874  mutt_message(_("%d kept, %d deleted"), m->msg_count - m->msg_deleted, m->msg_deleted);
875  }
876 
877  const bool c_save_empty = cs_subset_bool(NeoMutt->sub, "save_empty");
878  if ((m->msg_count == m->msg_deleted) &&
879  ((m->type == MUTT_MMDF) || (m->type == MUTT_MBOX)) &&
880  !mutt_is_spool(mailbox_path(m)) && !c_save_empty)
881  {
883  }
884 
885 #ifdef USE_SIDEBAR
886  if ((purge == MUTT_YES) && (m->msg_deleted != 0))
887  {
888  for (i = 0; i < m->msg_count; i++)
889  {
890  struct Email *e = m->emails[i];
891  if (!e)
892  break;
893  if (e->deleted && !e->read)
894  {
895  m->msg_unread--;
896  if (!e->old)
897  m->msg_new--;
898  }
899  if (e->deleted && e->flagged)
900  m->msg_flagged--;
901  }
902  }
903 #endif
904 
905  mx_fastclose_mailbox(m, false);
906 
907  rc = MX_STATUS_OK;
908 
909 cleanup:
912  return rc;
913 }
914 
922 enum MxStatus mx_mbox_sync(struct Mailbox *m)
923 {
924  if (!m)
925  return MX_STATUS_ERROR;
926 
927  enum MxStatus rc = MX_STATUS_OK;
928  int purge = 1;
929  int msgcount, deleted;
930 
931  if (m->dontwrite)
932  {
933  char buf[256], tmp[256];
934  if (km_expand_key(buf, sizeof(buf), km_find_func(MENU_MAIN, OP_TOGGLE_WRITE)))
935  snprintf(tmp, sizeof(tmp), _(" Press '%s' to toggle write"), buf);
936  else
937  mutt_str_copy(tmp, _("Use 'toggle-write' to re-enable write"), sizeof(tmp));
938 
939  mutt_error(_("Mailbox is marked unwritable. %s"), tmp);
940  return MX_STATUS_ERROR;
941  }
942  else if (m->readonly)
943  {
944  mutt_error(_("Mailbox is read-only"));
945  return MX_STATUS_ERROR;
946  }
947 
948  if (!m->changed && (m->msg_deleted == 0))
949  {
950  if (m->verbose)
951  mutt_message(_("Mailbox is unchanged"));
952  return MX_STATUS_OK;
953  }
954 
955  if (m->msg_deleted != 0)
956  {
957  char buf[128];
958 
959  snprintf(buf, sizeof(buf),
960  ngettext("Purge %d deleted message?", "Purge %d deleted messages?", m->msg_deleted),
961  m->msg_deleted);
962  const enum QuadOption c_delete = cs_subset_quad(NeoMutt->sub, "delete");
963  purge = query_quadoption(c_delete, buf);
964  if (purge == MUTT_ABORT)
965  return MX_STATUS_ERROR;
966  if (purge == MUTT_NO)
967  {
968  if (!m->changed)
969  return MX_STATUS_OK; /* nothing to do! */
970  /* let IMAP servers hold on to D flags */
971  if (m->type != MUTT_IMAP)
972  {
973  for (int i = 0; i < m->msg_count; i++)
974  {
975  struct Email *e = m->emails[i];
976  if (!e)
977  break;
978  e->deleted = false;
979  e->purge = false;
980  }
981  m->msg_deleted = 0;
982  }
983  }
985  }
986 
987  /* really only for IMAP - imap_sync_mailbox results in a call to
988  * ctx_update_tables, so m->msg_deleted is 0 when it comes back */
989  msgcount = m->msg_count;
990  deleted = m->msg_deleted;
991 
992  const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
993  const struct Mailbox *m_trash = mx_mbox_find(m->account, c_trash);
994  if (purge && (m->msg_deleted != 0) && (m != m_trash))
995  {
996  if (trash_append(m) != 0)
997  return MX_STATUS_OK;
998  }
999 
1000 #ifdef USE_IMAP
1001  if (m->type == MUTT_IMAP)
1002  rc = imap_sync_mailbox(m, purge, false);
1003  else
1004 #endif
1005  rc = sync_mailbox(m);
1006  if (rc != MX_STATUS_ERROR)
1007  {
1008 #ifdef USE_IMAP
1009  if ((m->type == MUTT_IMAP) && !purge)
1010  {
1011  if (m->verbose)
1012  mutt_message(_("Mailbox checkpointed"));
1013  }
1014  else
1015 #endif
1016  {
1017  if (m->verbose)
1018  mutt_message(_("%d kept, %d deleted"), msgcount - deleted, deleted);
1019  }
1020 
1021  mutt_sleep(0);
1022 
1023  const bool c_save_empty = cs_subset_bool(NeoMutt->sub, "save_empty");
1024  if ((m->msg_count == m->msg_deleted) &&
1025  ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) &&
1026  !mutt_is_spool(mailbox_path(m)) && !c_save_empty)
1027  {
1028  unlink(mailbox_path(m));
1029  mx_fastclose_mailbox(m, false);
1030  return MX_STATUS_OK;
1031  }
1032 
1033  /* if we haven't deleted any messages, we don't need to resort
1034  * ... except for certain folder formats which need "unsorted"
1035  * sort order in order to synchronize folders.
1036  *
1037  * MH and maildir are safe. mbox-style seems to need re-sorting,
1038  * at least with the new threading code. */
1039  if (purge || ((m->type != MUTT_MAILDIR) && (m->type != MUTT_MH)))
1040  {
1041  /* IMAP does this automatically after handling EXPUNGE */
1042  if (m->type != MUTT_IMAP)
1043  {
1046  }
1047  }
1048  }
1049 
1050  return rc;
1051 }
1052 
1060 struct Message *mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
1061 {
1062  if (!m)
1063  return NULL;
1064 
1065  struct Address *p = NULL;
1066  struct Message *msg = NULL;
1067 
1068  if (!m->mx_ops || !m->mx_ops->msg_open_new)
1069  {
1070  mutt_debug(LL_DEBUG1, "function unimplemented for mailbox type %d\n", m->type);
1071  return NULL;
1072  }
1073 
1074  msg = mutt_mem_calloc(1, sizeof(struct Message));
1075  msg->write = true;
1076 
1077  if (e)
1078  {
1079  msg->flags.flagged = e->flagged;
1080  msg->flags.replied = e->replied;
1081  msg->flags.read = e->read;
1082  msg->flags.draft = (flags & MUTT_SET_DRAFT);
1083  msg->received = e->received;
1084  }
1085 
1086  if (msg->received == 0)
1087  msg->received = mutt_date_epoch();
1088 
1089  if (m->mx_ops->msg_open_new(m, msg, e))
1090  {
1091  if (m->type == MUTT_MMDF)
1092  fputs(MMDF_SEP, msg->fp);
1093 
1094  if (((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) && (flags & MUTT_ADD_FROM))
1095  {
1096  if (e)
1097  {
1098  p = TAILQ_FIRST(&e->env->return_path);
1099  if (!p)
1100  p = TAILQ_FIRST(&e->env->sender);
1101  if (!p)
1102  p = TAILQ_FIRST(&e->env->from);
1103  }
1104 
1105  // Force a 'C' locale for the date, so that day/month names are in English
1106  locale_t loc = newlocale(LC_TIME_MASK, "C", 0);
1107  char buf[64] = { 0 };
1108  struct tm tm = mutt_date_localtime(msg->received);
1109  strftime_l(buf, sizeof(buf), "%a %b %e %H:%M:%S %Y", &tm, loc);
1110  freelocale(loc);
1111  fprintf(msg->fp, "From %s %s\n", p ? p->mailbox : NONULL(Username), buf);
1112  }
1113  }
1114  else
1115  FREE(&msg);
1116 
1117  return msg;
1118 }
1119 
1125 enum MxStatus mx_mbox_check(struct Mailbox *m)
1126 {
1127  if (!m || !m->mx_ops)
1128  return MX_STATUS_ERROR;
1129 
1130  enum MxStatus rc = m->mx_ops->mbox_check(m);
1131  if ((rc == MX_STATUS_NEW_MAIL) || (rc == MX_STATUS_REOPENED))
1132  {
1134  }
1135 
1136  return rc;
1137 }
1138 
1146 struct Message *mx_msg_open(struct Mailbox *m, int msgno)
1147 {
1148  if (!m || !m->emails || (msgno < 0) || (msgno >= m->msg_count))
1149  return NULL;
1150 
1151  if (!m->mx_ops || !m->mx_ops->msg_open)
1152  {
1153  mutt_debug(LL_DEBUG1, "function not implemented for mailbox type %d\n", m->type);
1154  return NULL;
1155  }
1156 
1157  struct Message *msg = mutt_mem_calloc(1, sizeof(struct Message));
1158  if (!m->mx_ops->msg_open(m, msg, msgno))
1159  FREE(&msg);
1160 
1161  return msg;
1162 }
1163 
1171 int mx_msg_commit(struct Mailbox *m, struct Message *msg)
1172 {
1173  if (!m || !m->mx_ops || !m->mx_ops->msg_commit || !msg)
1174  return -1;
1175 
1176  if (!(msg->write && m->append))
1177  {
1178  mutt_debug(LL_DEBUG1, "msg->write = %d, m->append = %d\n", msg->write, m->append);
1179  return -1;
1180  }
1181 
1182  return m->mx_ops->msg_commit(m, msg);
1183 }
1184 
1192 int mx_msg_close(struct Mailbox *m, struct Message **msg)
1193 {
1194  if (!m || !msg || !*msg)
1195  return 0;
1196 
1197  int rc = 0;
1198 
1199  if (m->mx_ops && m->mx_ops->msg_close)
1200  rc = m->mx_ops->msg_close(m, *msg);
1201 
1202  if ((*msg)->path)
1203  {
1204  mutt_debug(LL_DEBUG1, "unlinking %s\n", (*msg)->path);
1205  unlink((*msg)->path);
1206  FREE(&(*msg)->path);
1207  }
1208 
1209  FREE(&(*msg)->committed_path);
1210  FREE(msg);
1211  return rc;
1212 }
1213 
1218 void mx_alloc_memory(struct Mailbox *m)
1219 {
1220  const int grow = 25;
1221  size_t s = MAX(sizeof(struct Email *), sizeof(int));
1222 
1223  if (((m->email_max + grow) * s) < (m->email_max * s))
1224  {
1225  mutt_error(_("Out of memory"));
1226  mutt_exit(1);
1227  }
1228 
1229  m->email_max += grow;
1230  if (m->emails)
1231  {
1232  mutt_mem_realloc(&m->emails, m->email_max * sizeof(struct Email *));
1233  mutt_mem_realloc(&m->v2r, m->email_max * sizeof(int));
1234  }
1235  else
1236  {
1237  m->emails = mutt_mem_calloc(m->email_max, sizeof(struct Email *));
1238  m->v2r = mutt_mem_calloc(m->email_max, sizeof(int));
1239  }
1240  for (int i = m->email_max - grow; i < m->email_max; i++)
1241  {
1242  if (i < m->email_max)
1243  {
1244  m->emails[i] = NULL;
1245  m->v2r[i] = -1;
1246  }
1247  }
1248 }
1249 
1257 int mx_path_is_empty(const char *path)
1258 {
1259  if (!path || (*path == '\0'))
1260  return -1;
1261 
1262  enum MailboxType type = mx_path_probe(path);
1263  const struct MxOps *ops = mx_get_ops(type);
1264  if (!ops || !ops->path_is_empty)
1265  return -1;
1266 
1267  return ops->path_is_empty(path);
1268 }
1269 
1279 int mx_tags_edit(struct Mailbox *m, const char *tags, struct Buffer *buf)
1280 {
1281  if (!m || !buf)
1282  return -1;
1283 
1284  if (m->mx_ops->tags_edit)
1285  return m->mx_ops->tags_edit(m, tags, buf);
1286 
1287  mutt_message(_("Folder doesn't support tagging, aborting"));
1288  return -1;
1289 }
1290 
1299 int mx_tags_commit(struct Mailbox *m, struct Email *e, const char *tags)
1300 {
1301  if (!m || !e || !tags)
1302  return -1;
1303 
1304  if (m->mx_ops->tags_commit)
1305  return m->mx_ops->tags_commit(m, e, tags);
1306 
1307  mutt_message(_("Folder doesn't support tagging, aborting"));
1308  return -1;
1309 }
1310 
1317 {
1318  return m && m->mx_ops->tags_commit && m->mx_ops->tags_edit;
1319 }
1320 
1326 enum MailboxType mx_path_probe(const char *path)
1327 {
1328  if (!path)
1329  return MUTT_UNKNOWN;
1330 
1331  enum MailboxType rc = MUTT_UNKNOWN;
1332 
1333  // First, search the non-local Mailbox types (is_local == false)
1334  for (const struct MxOps **ops = MxOps; *ops; ops++)
1335  {
1336  if ((*ops)->is_local)
1337  continue;
1338  rc = (*ops)->path_probe(path, NULL);
1339  if (rc != MUTT_UNKNOWN)
1340  return rc;
1341  }
1342 
1343  struct stat st = { 0 };
1344  if (stat(path, &st) != 0)
1345  {
1346  mutt_debug(LL_DEBUG1, "unable to stat %s: %s (errno %d)\n", path, strerror(errno), errno);
1347  return MUTT_UNKNOWN;
1348  }
1349 
1350  if (S_ISFIFO(st.st_mode))
1351  {
1352  mutt_error(_("Can't open %s: it is a pipe"), path);
1353  return MUTT_UNKNOWN;
1354  }
1355 
1356  // Next, search the local Mailbox types (is_local == true)
1357  for (const struct MxOps **ops = MxOps; *ops; ops++)
1358  {
1359  if (!(*ops)->is_local)
1360  continue;
1361  rc = (*ops)->path_probe(path, &st);
1362  if (rc != MUTT_UNKNOWN)
1363  return rc;
1364  }
1365 
1366  return rc;
1367 }
1368 
1372 int mx_path_canon(char *buf, size_t buflen, const char *folder, enum MailboxType *type)
1373 {
1374  if (!buf)
1375  return -1;
1376 
1377  for (size_t i = 0; i < 3; i++)
1378  {
1379  /* Look for !! ! - < > or ^ followed by / or NUL */
1380  if ((buf[0] == '!') && (buf[1] == '!'))
1381  {
1382  if (((buf[2] == '/') || (buf[2] == '\0')))
1383  {
1384  mutt_str_inline_replace(buf, buflen, 2, LastFolder);
1385  }
1386  }
1387  else if ((buf[0] == '+') || (buf[0] == '='))
1388  {
1389  size_t folder_len = mutt_str_len(folder);
1390  if ((folder_len > 0) && (folder[folder_len - 1] != '/'))
1391  {
1392  buf[0] = '/';
1393  mutt_str_inline_replace(buf, buflen, 0, folder);
1394  }
1395  else
1396  {
1397  mutt_str_inline_replace(buf, buflen, 1, folder);
1398  }
1399  }
1400  else if ((buf[1] == '/') || (buf[1] == '\0'))
1401  {
1402  if (buf[0] == '!')
1403  {
1404  const char *const c_spool_file =
1405  cs_subset_string(NeoMutt->sub, "spool_file");
1406  mutt_str_inline_replace(buf, buflen, 1, c_spool_file);
1407  }
1408  else if (buf[0] == '-')
1409  {
1410  mutt_str_inline_replace(buf, buflen, 1, LastFolder);
1411  }
1412  else if (buf[0] == '<')
1413  {
1414  const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
1415  mutt_str_inline_replace(buf, buflen, 1, c_record);
1416  }
1417  else if (buf[0] == '>')
1418  {
1419  const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
1420  mutt_str_inline_replace(buf, buflen, 1, c_mbox);
1421  }
1422  else if (buf[0] == '^')
1423  {
1424  mutt_str_inline_replace(buf, buflen, 1, CurrentFolder);
1425  }
1426  else if (buf[0] == '~')
1427  {
1428  mutt_str_inline_replace(buf, buflen, 1, HomeDir);
1429  }
1430  }
1431  else if (buf[0] == '@')
1432  {
1433  /* elm compatibility, @ expands alias to user name */
1434  struct AddressList *al = alias_lookup(buf + 1);
1435  if (!al || TAILQ_EMPTY(al))
1436  break;
1437 
1438  struct Email *e = email_new();
1439  e->env = mutt_env_new();
1440  mutt_addrlist_copy(&e->env->from, al, false);
1441  mutt_addrlist_copy(&e->env->to, al, false);
1442  mutt_default_save(buf, buflen, e);
1443  email_free(&e);
1444  break;
1445  }
1446  else
1447  {
1448  break;
1449  }
1450  }
1451 
1452  // if (!folder) //XXX - use inherited version, or pass NULL to backend?
1453  // return -1;
1454 
1455  enum MailboxType type2 = mx_path_probe(buf);
1456  if (type)
1457  *type = type2;
1458  const struct MxOps *ops = mx_get_ops(type2);
1459  if (!ops || !ops->path_canon)
1460  return -1;
1461 
1462  if (ops->path_canon(buf, buflen) < 0)
1463  {
1464  mutt_path_canon(buf, buflen, HomeDir, true);
1465  }
1466 
1467  return 0;
1468 }
1469 
1477 int mx_path_canon2(struct Mailbox *m, const char *folder)
1478 {
1479  if (!m)
1480  return -1;
1481 
1482  char buf[PATH_MAX];
1483 
1484  if (m->realpath)
1485  mutt_str_copy(buf, m->realpath, sizeof(buf));
1486  else
1487  mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
1488 
1489  int rc = mx_path_canon(buf, sizeof(buf), folder, &m->type);
1490 
1491  mutt_str_replace(&m->realpath, buf);
1492 
1493  if (rc >= 0)
1494  {
1495  m->mx_ops = mx_get_ops(m->type);
1497  }
1498 
1499  return rc;
1500 }
1501 
1505 int mx_path_pretty(char *buf, size_t buflen, const char *folder)
1506 {
1507  if (!buf)
1508  return -1;
1509 
1510  enum MailboxType type = mx_path_probe(buf);
1511  const struct MxOps *ops = mx_get_ops(type);
1512  if (!ops)
1513  return -1;
1514 
1515  if (!ops->path_canon)
1516  return -1;
1517 
1518  if (ops->path_canon(buf, buflen) < 0)
1519  return -1;
1520 
1521  if (!ops->path_pretty)
1522  return -1;
1523 
1524  if (ops->path_pretty(buf, buflen, folder) < 0)
1525  return -1;
1526 
1527  return 0;
1528 }
1529 
1533 int mx_path_parent(char *buf, size_t buflen)
1534 {
1535  if (!buf)
1536  return -1;
1537 
1538  return 0;
1539 }
1540 
1550 {
1551  if (!m || !m->mx_ops || !m->mx_ops->msg_padding_size)
1552  return 0;
1553 
1554  return m->mx_ops->msg_padding_size(m);
1555 }
1556 
1563 struct Account *mx_ac_find(struct Mailbox *m)
1564 {
1565  if (!m || !m->mx_ops || !m->realpath)
1566  return NULL;
1567 
1568  struct Account *np = NULL;
1569  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1570  {
1571  if (np->type != m->type)
1572  continue;
1573 
1574  if (m->mx_ops->ac_owns_path(np, m->realpath))
1575  return np;
1576  }
1577 
1578  return NULL;
1579 }
1580 
1587 struct Mailbox *mx_mbox_find(struct Account *a, const char *path)
1588 {
1589  if (!a || !path)
1590  return NULL;
1591 
1592  struct MailboxNode *np = NULL;
1593  struct Url *url_p = NULL;
1594  struct Url *url_a = NULL;
1595 
1596  const bool use_url = (a->type == MUTT_IMAP);
1597  if (use_url)
1598  {
1599  url_p = url_parse(path);
1600  if (!url_p)
1601  goto done;
1602  }
1603 
1604  STAILQ_FOREACH(np, &a->mailboxes, entries)
1605  {
1606  if (!use_url)
1607  {
1608  if (mutt_str_equal(np->mailbox->realpath, path))
1609  return np->mailbox;
1610  continue;
1611  }
1612 
1613  url_free(&url_a);
1614  url_a = url_parse(np->mailbox->realpath);
1615  if (!url_a)
1616  continue;
1617 
1618  if (!mutt_istr_equal(url_a->host, url_p->host))
1619  continue;
1620  if (url_p->user && !mutt_istr_equal(url_a->user, url_p->user))
1621  continue;
1622  if (a->type == MUTT_IMAP)
1623  {
1624  if (imap_mxcmp(url_a->path, url_p->path) == 0)
1625  break;
1626  }
1627  else
1628  {
1629  if (mutt_str_equal(url_a->path, url_p->path))
1630  break;
1631  }
1632  }
1633 
1634 done:
1635  url_free(&url_p);
1636  url_free(&url_a);
1637 
1638  if (!np)
1639  return NULL;
1640  return np->mailbox;
1641 }
1642 
1649 struct Mailbox *mx_mbox_find2(const char *path)
1650 {
1651  if (!path)
1652  return NULL;
1653 
1654  char buf[PATH_MAX];
1655  mutt_str_copy(buf, path, sizeof(buf));
1656  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1657  mx_path_canon(buf, sizeof(buf), c_folder, NULL);
1658 
1659  struct Account *np = NULL;
1660  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1661  {
1662  struct Mailbox *m = mx_mbox_find(np, buf);
1663  if (m)
1664  return m;
1665  }
1666 
1667  return NULL;
1668 }
1669 
1677 struct Mailbox *mx_path_resolve(const char *path)
1678 {
1679  if (!path)
1680  return NULL;
1681 
1682  struct Mailbox *m = mx_mbox_find2(path);
1683  if (m)
1684  return m;
1685 
1686  m = mailbox_new();
1687  m->flags = MB_HIDDEN;
1688  mutt_buffer_strcpy(&m->pathbuf, path);
1689  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1690  mx_path_canon2(m, c_folder);
1691 
1692  return m;
1693 }
1694 
1701 static struct Mailbox *mx_mbox_find_by_name_ac(struct Account *a, const char *name)
1702 {
1703  if (!a || !name)
1704  return NULL;
1705 
1706  struct MailboxNode *np = NULL;
1707 
1708  STAILQ_FOREACH(np, &a->mailboxes, entries)
1709  {
1710  if (mutt_str_equal(np->mailbox->name, name))
1711  return np->mailbox;
1712  }
1713 
1714  return NULL;
1715 }
1716 
1722 static struct Mailbox *mx_mbox_find_by_name(const char *name)
1723 {
1724  if (!name)
1725  return NULL;
1726 
1727  struct Account *np = NULL;
1728  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1729  {
1730  struct Mailbox *m = mx_mbox_find_by_name_ac(np, name);
1731  if (m)
1732  return m;
1733  }
1734 
1735  return NULL;
1736 }
1737 
1747 struct Mailbox *mx_resolve(const char *path_or_name)
1748 {
1749  if (!path_or_name)
1750  return NULL;
1751 
1752  // Order is name first because you can create a Mailbox from
1753  // a path, but can't from a name. So fallback behavior creates
1754  // a new Mailbox for us.
1755  struct Mailbox *m = mx_mbox_find_by_name(path_or_name);
1756  if (!m)
1757  m = mx_path_resolve(path_or_name);
1758 
1759  return m;
1760 }
1761 
1765 bool mx_ac_add(struct Account *a, struct Mailbox *m)
1766 {
1767  if (!a || !m || !m->mx_ops || !m->mx_ops->ac_add)
1768  return false;
1769 
1770  return m->mx_ops->ac_add(a, m) && account_mailbox_add(a, m);
1771 }
1772 
1782 int mx_ac_remove(struct Mailbox *m, bool keep_account)
1783 {
1784  if (!m || !m->account)
1785  return -1;
1786 
1787  struct Account *a = m->account;
1789  if (!keep_account && STAILQ_EMPTY(&a->mailboxes))
1790  {
1792  }
1793  return 0;
1794 }
1795 
1801 enum MxStatus mx_mbox_check_stats(struct Mailbox *m, uint8_t flags)
1802 {
1803  if (!m)
1804  return MX_STATUS_ERROR;
1805 
1806  enum MxStatus rc = m->mx_ops->mbox_check_stats(m, flags);
1807  if (rc != MX_STATUS_ERROR)
1808  {
1809  struct EventMailbox ev_m = { m };
1811  }
1812 
1813  return rc;
1814 }
1815 
1825 int mx_save_hcache(struct Mailbox *m, struct Email *e)
1826 {
1827  if (!m || !m->mx_ops || !m->mx_ops->msg_save_hcache || !e)
1828  return 0;
1829 
1830  return m->mx_ops->msg_save_hcache(m, e);
1831 }
1832 
1838 enum MailboxType mx_type(struct Mailbox *m)
1839 {
1840  return m ? m->type : MUTT_MAILBOX_ERROR;
1841 }
1842 
1849 int mx_toggle_write(struct Mailbox *m)
1850 {
1851  if (!m)
1852  return -1;
1853 
1854  if (m->readonly)
1855  {
1856  mutt_error(_("Can't toggle write on a readonly mailbox"));
1857  return -1;
1858  }
1859 
1860  if (m->dontwrite)
1861  {
1862  m->dontwrite = false;
1863  mutt_message(_("Changes to folder will be written on folder exit"));
1864  }
1865  else
1866  {
1867  m->dontwrite = true;
1868  mutt_message(_("Changes to folder will not be written"));
1869  }
1870 
1871  struct EventMailbox ev_m = { m };
1873  return 0;
1874 }
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:96
struct Account * account_new(const char *name, struct ConfigSubset *sub)
Create a new Account.
Definition: account.c:43
bool account_mailbox_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account.
Definition: account.c:66
void account_free(struct Account **ptr)
Free an Account.
Definition: account.c:139
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:737
Email Address Handling.
Email Aliases.
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:280
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
Manage where the email is piped to external commands.
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: commands.h:51
bool mutt_comp_can_append(struct Mailbox *m)
Can we append to this path?
Definition: compress.c:359
Compressed mbox local mailbox type.
char * HomeDir
User's home directory.
Definition: mutt_globals.h:49
int mutt_append_message(struct Mailbox *m_dst, struct Mailbox *m_src, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
Append a message.
Definition: copy.c:952
Duplicate the structure of an entire email.
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:35
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:51
Convenience wrapper for the core headers.
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:654
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
int emaillist_add_email(struct EmailList *el, struct Email *e)
Add an Email to a list.
Definition: email.c:159
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:138
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
Structs that make up an email.
void mutt_file_unlink_empty(const char *path)
Delete a file if it's empty.
Definition: file.c:1342
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
struct MxOps MxMaildirOps
Maildir Mailbox - Implements MxOps -.
Definition: maildir.c:1652
struct MxOps MxMhOps
MH Mailbox - Implements MxOps -.
Definition: mh.c:1258
struct MxOps MxCompOps
Compressed Mailbox - Implements MxOps -.
Definition: compress.c:934
struct MxOps MxMmdfOps
MMDF Mailbox - Implements MxOps -.
Definition: mbox.c:1877
struct MxOps MxNntpOps
NNTP Mailbox - Implements MxOps -.
Definition: nntp.c:2752
struct MxOps MxImapOps
IMAP Mailbox - Implements MxOps -.
Definition: imap.c:2491
struct MxOps MxMboxOps
Mbox Mailbox - Implements MxOps -.
Definition: mbox.c:1845
struct MxOps MxNotmuchOps
Notmuch Mailbox - Implements MxOps -.
Definition: notmuch.c:2490
struct MxOps MxPopOps
POP Mailbox - Implements MxOps -.
Definition: pop.c:1205
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2405
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:457
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
unsigned char cs_subset_enum(const struct ConfigSubset *sub, const char *name)
Get a enumeration config item by name.
Definition: helpers.c:97
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:679
char * mutt_find_hook(HookFlags type, const char *pat)
Find a matching hook.
Definition: hook.c:579
Parse and execute user-defined hooks.
#define MUTT_MBOX_HOOK
mbox-hook: move messages after reading them
Definition: hook.h:39
IMAP network mailbox.
int imap_copy_messages(struct Mailbox *m, struct EmailList *el, const char *dest, enum MessageSaveOpt save_opt)
Server COPY messages to another folder.
Definition: message.c:1649
int imap_mxcmp(const char *mx1, const char *mx2)
Compare mailbox names, giving priority to INBOX.
Definition: util.c:554
int imap_fast_trash(struct Mailbox *m, const char *dest)
Use server COPY command to copy deleted messages to trash.
Definition: imap.c:1426
enum MxStatus imap_sync_mailbox(struct Mailbox *m, bool expunge, bool close)
Sync all the changes to the server.
Definition: imap.c:1537
int imap_access(const char *path)
Check permissions on an IMAP mailbox with a new connection.
Definition: imap.c:474
struct Keymap * km_find_func(enum MenuType mtype, int func)
Find a function's mapping in a Menu.
Definition: keymap.c:938
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:910
Manage keymappings.
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
struct Mailbox * mailbox_new(void)
Create a new Mailbox.
Definition: mailbox.c:68
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:211
@ NT_MAILBOX_UNTAG
Clear the 'last-tagged' pointer.
Definition: mailbox.h:184
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition: mailbox.h:176
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:181
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:180
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition: mailbox.h:183
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:215
#define MB_HIDDEN
Definition: mailbox.h:38
#define MUTT_ACL_ALL
Definition: mailbox.h:76
MailboxType
Supported mailbox formats.
Definition: mailbox.h:44
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:49
@ MUTT_MAILBOX_ERROR
Error occurred examining Mailbox.
Definition: mailbox.h:46
@ MUTT_MH
'MH' Mailbox type
Definition: mailbox.h:50
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:52
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:53
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:48
@ MUTT_COMPRESSED
Compressed file Mailbox type.
Definition: mailbox.h:56
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:47
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:51
Maildir local mailbox type.
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:249
#define MMDF_SEP
Definition: lib.h:60
void mbox_reset_atime(struct Mailbox *m, struct stat *st)
Reset the access time on the mailbox file.
Definition: mbox.c:847
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define FREE(x)
Definition: memory.h:40
#define MAX(a, b)
Definition: memory.h:30
GUI present the user with a selectable list.
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:171
bool mutt_path_canon(char *buf, size_t buflen, const char *homedir, bool is_dir)
Create the canonical version of a path.
Definition: path.c:285
bool mutt_str_inline_replace(char *buf, size_t buflen, size_t xlen, const char *rstr)
Replace the beginning of a string.
Definition: string.c:857
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:727
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:715
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:475
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:560
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:257
Many unsorted constants and some structs.
@ MUTT_OLD
Old messages.
Definition: mutt.h:90
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:96
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:94
#define PATH_MAX
Definition: mutt.h:40
Hundreds of global variables to back the user variables.
char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:55
char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:54
char * Username
User's login name.
Definition: mutt_globals.h:52
void mutt_make_label_hash(struct Mailbox *m)
Create a Hash Table to store the labels.
Definition: mutt_header.c:369
Representation of the email's header.
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
NeoMutt Logging.
void mutt_mailbox_set_notified(struct Mailbox *m)
Note when the user was last notified of new mail.
Definition: mutt_mailbox.c:318
Mailbox helper functions.
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1462
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1361
Some miscellaneous functions.
int mx_tags_edit(struct Mailbox *m, const char *tags, struct Buffer *buf)
Start the tag editor of the mailbox.
Definition: mx.c:1279
static struct Mailbox * mx_mbox_find_by_name_ac(struct Account *a, const char *name)
Find a Mailbox with given name under an Account.
Definition: mx.c:1701
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1192
int mx_ac_remove(struct Mailbox *m, bool keep_account)
Remove a Mailbox from an Account and delete Account if empty.
Definition: mx.c:1782
int mx_access(const char *path, int flags)
Wrapper for access, checks permissions on a given mailbox.
Definition: mx.c:184
static enum MxStatus sync_mailbox(struct Mailbox *m)
Save changes to disk.
Definition: mx.c:472
static int trash_append(struct Mailbox *m)
Move deleted mails to the trash folder.
Definition: mx.c:503
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1549
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition: mx.c:430
struct EnumDef MboxTypeDef
Definition: mx.c:98
enum MxStatus mx_mbox_check_stats(struct Mailbox *m, uint8_t flags)
Check the statistics for a mailbox - Wrapper for MxOps::mbox_check_stats()
Definition: mx.c:1801
static struct Mailbox * mx_mbox_find_by_name(const char *name)
Find a Mailbox with given name.
Definition: mx.c:1722
int mx_path_canon(char *buf, size_t buflen, const char *folder, enum MailboxType *type)
Canonicalise a mailbox path - Wrapper for MxOps::path_canon()
Definition: mx.c:1372
int mx_path_is_empty(const char *path)
Is the mailbox empty.
Definition: mx.c:1257
static bool mutt_is_spool(const char *str)
Is this the spool_file?
Definition: mx.c:155
const struct MxOps * mx_get_ops(enum MailboxType type)
Get mailbox operations.
Definition: mx.c:141
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1146
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1649
bool mx_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Wrapper for MxOps::ac_add()
Definition: mx.c:1765
bool mx_tags_is_supported(struct Mailbox *m)
Return true if mailbox support tagging.
Definition: mx.c:1316
int mx_tags_commit(struct Mailbox *m, struct Email *e, const char *tags)
Save tags to the Mailbox - Wrapper for MxOps::tags_commit()
Definition: mx.c:1299
int mx_path_pretty(char *buf, size_t buflen, const char *folder)
Abbreviate a mailbox path - Wrapper for MxOps::path_pretty()
Definition: mx.c:1505
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1677
int mx_save_hcache(struct Mailbox *m, struct Email *e)
Save message to the header cache - Wrapper for MxOps::msg_save_hcache()
Definition: mx.c:1825
static const struct Mapping MboxTypeMap[]
Definition: mx.c:88
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:267
int mx_path_parent(char *buf, size_t buflen)
Find the parent of a mailbox path - Wrapper for MxOps::path_parent()
Definition: mx.c:1533
struct Mailbox * mx_mbox_find(struct Account *a, const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1587
void mx_alloc_memory(struct Mailbox *m)
Create storage for the emails.
Definition: mx.c:1218
enum MailboxType mx_type(struct Mailbox *m)
Return the type of the Mailbox.
Definition: mx.c:1838
struct Account * mx_ac_find(struct Mailbox *m)
Find the Account owning a Mailbox.
Definition: mx.c:1563
int mx_toggle_write(struct Mailbox *m)
Toggle the mailbox's readonly flag.
Definition: mx.c:1849
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1171
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1326
int mx_path_canon2(struct Mailbox *m, const char *folder)
Canonicalise the path to realpath.
Definition: mx.c:1477
enum MxStatus mx_mbox_check(struct Mailbox *m)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1125
enum MxStatus mx_mbox_sync(struct Mailbox *m)
Save changes to mailbox.
Definition: mx.c:922
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1060
static bool mx_open_mailbox_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox for appending.
Definition: mx.c:201
struct Mailbox * mx_resolve(const char *path_or_name)
Get a Mailbox from either a path or name.
Definition: mx.c:1747
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:616
API for mailboxes.
uint8_t MsgOpenFlags
Flags for mx_msg_open_new(), e.g. MUTT_ADD_FROM.
Definition: mx.h:40
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:42
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:43
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h:63
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mxapi.h:59
#define MUTT_NEWFOLDER
Create a new folder - same as MUTT_APPEND,.
Definition: mxapi.h:65
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:62
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:64
MxOpenReturns
Return values for mbox_open()
Definition: mxapi.h:89
@ MX_OPEN_ABORT
Open was aborted.
Definition: mxapi.h:92
@ MX_OPEN_OK
Open succeeded.
Definition: mxapi.h:90
#define MUTT_PEEK
Revert atime back after taking a look (if applicable)
Definition: mxapi.h:68
#define MUTT_NOSORT
Do not sort the mailbox after opening it.
Definition: mxapi.h:61
#define MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn't exist.
Definition: mxapi.h:69
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_snc(), and mbox_close()
Definition: mxapi.h:76
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:77
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:78
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:81
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:79
bool neomutt_account_add(struct NeoMutt *n, struct Account *a)
Add an Account to the global list.
Definition: neomutt.c:84
bool neomutt_account_remove(struct NeoMutt *n, struct Account *a)
Remove an Account from the global list.
Definition: neomutt.c:106
Nntp-specific Account data.
Usenet network mailbox type; talk to an NNTP server.
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition: newsrc.c:1309
Nntp-specific Mailbox data.
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:48
Notmuch virtual mailbox type.
All user-callable functions.
Handling of global boolean variables.
bool OptNeedRescore
(pseudo) set when the 'score' command is used
Definition: options.h:47
bool OptForceRefresh
(pseudo) refresh even during macros
Definition: options.h:42
bool OptSortSubthreads
(pseudo) used when $sort_aux changes
Definition: options.h:59
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
POP network mailbox.
Prototypes for many functions.
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:66
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition: quad.h:37
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
Ask the user a question.
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:349
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define STAILQ_EMPTY(head)
Definition: queue.h:348
#define TAILQ_EMPTY(head)
Definition: queue.h:721
#define NONULL(x)
Definition: string2.h:37
A group of associated Mailboxes.
Definition: account.h:37
enum MailboxType type
Type of Mailboxes this Account contains.
Definition: account.h:38
struct MailboxList mailboxes
List of Mailboxes.
Definition: account.h:41
An email address.
Definition: address.h:36
char * mailbox
Mailbox and host address.
Definition: address.h:38
String manipulation buffer.
Definition: buffer.h:34
The envelope/body of an email.
Definition: email.h:37
bool read
Email is read.
Definition: email.h:48
bool purge
Skip trash folder when deleting.
Definition: email.h:77
struct Envelope * env
Envelope information.
Definition: email.h:66
bool old
Email is seen, but unread.
Definition: email.h:47
bool flagged
Marked important?
Definition: email.h:45
bool replied
Email has been replied to.
Definition: email.h:49
bool deleted
Email is deleted.
Definition: email.h:76
bool tagged
Email is tagged.
Definition: email.h:107
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:59
An enumeration.
Definition: enum.h:30
struct AddressList return_path
Return path for the Email.
Definition: envelope.h:56
struct AddressList to
Email's 'To' list.
Definition: envelope.h:58
struct AddressList sender
Email's sender.
Definition: envelope.h:61
struct AddressList from
Email's 'From' list.
Definition: envelope.h:57
An Event that happened to a Mailbox.
Definition: mailbox.h:191
List of Mailboxes.
Definition: mailbox.h:157
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:158
A mailbox.
Definition: mailbox.h:82
int vcount
The number of virtual messages.
Definition: mailbox.h:102
bool changed
Mailbox has been modified.
Definition: mailbox.h:114
bool has_new
Mailbox has new mail.
Definition: mailbox.h:88
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:84
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:113
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
const struct MxOps * mx_ops
MXAPI callback functions.
Definition: mailbox.h:111
int msg_new
Number of new messages.
Definition: mailbox.h:95
int msg_count
Total number of messages.
Definition: mailbox.h:91
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:121
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
void * mdata
Driver specific data.
Definition: mailbox.h:136
struct HashTable * subj_hash
Hash Table by subject.
Definition: mailbox.h:128
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
char * name
A short name for the Mailbox.
Definition: mailbox.h:85
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition: mailbox.h:148
struct HashTable * id_hash
Hash Table by msg id.
Definition: mailbox.h:127
struct Buffer pathbuf
Path of the Mailbox.
Definition: mailbox.h:83
bool peekonly
Just taking a glance, revert atime.
Definition: mailbox.h:117
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:96
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:131
bool dontwrite
Don't write the mailbox on close.
Definition: mailbox.h:115
off_t size
Size of the Mailbox.
Definition: mailbox.h:87
struct HashTable * label_hash
Hash Table for x-labels.
Definition: mailbox.h:129
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:93
int opened
Number of times mailbox is opened.
Definition: mailbox.h:132
bool readonly
Don't allow changes to the mailbox.
Definition: mailbox.h:119
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:97
bool verbose
Display status messages?
Definition: mailbox.h:118
int msg_unread
Number of unread messages.
Definition: mailbox.h:92
uint8_t flags
e.g. MB_NORMAL
Definition: mailbox.h:134
Mapping between user-readable string and a constant.
Definition: mapping.h:32
A local copy of an email.
Definition: mxapi.h:42
FILE * fp
pointer to the message data
Definition: mxapi.h:43
char * path
path to temp file
Definition: mxapi.h:44
bool draft
Message has been read.
Definition: mxapi.h:52
bool replied
Message has been replied to.
Definition: mxapi.h:51
time_t received
Time at which this message was received.
Definition: mxapi.h:54
bool write
nonzero if message is open for writing
Definition: mxapi.h:46
bool flagged
Message is flagged.
Definition: mxapi.h:50
bool read
Message has been read.
Definition: mxapi.h:49
struct Message::@0 flags
Flags for the Message.
Definition: mxapi.h:104
int(* tags_commit)(struct Mailbox *m, struct Email *e, const char *buf)
Definition: mxapi.h:352
int(* path_pretty)(char *buf, size_t buflen, const char *folder)
Definition: mxapi.h:397
int(* msg_save_hcache)(struct Mailbox *m, struct Email *e)
Definition: mxapi.h:316
int(* path_is_empty)(const char *path)
Definition: mxapi.h:427
enum MailboxType type
Mailbox type, e.g. MUTT_IMAP.
Definition: mxapi.h:105
int(* msg_padding_size)(struct Mailbox *m)
Definition: mxapi.h:300
bool(* ac_owns_path)(struct Account *a, const char *path)
Definition: mxapi.h:123
int(* tags_edit)(struct Mailbox *m, const char *tags, struct Buffer *buf)
Definition: mxapi.h:334
int(* msg_commit)(struct Mailbox *m, struct Message *msg)
Definition: mxapi.h:271
bool(* ac_add)(struct Account *a, struct Mailbox *m)
Definition: mxapi.h:139
enum MxOpenReturns(* mbox_open)(struct Mailbox *m)
Definition: mxapi.h:152
int(* msg_close)(struct Mailbox *m, struct Message *msg)
Definition: mxapi.h:287
int(* path_canon)(char *buf, size_t buflen)
Definition: mxapi.h:381
bool(* msg_open_new)(struct Mailbox *m, struct Message *msg, const struct Email *e)
Definition: mxapi.h:255
enum MxStatus(* mbox_close)(struct Mailbox *m)
Definition: mxapi.h:220
enum MxStatus(* mbox_sync)(struct Mailbox *m)
Definition: mxapi.h:207
bool(* mbox_open_append)(struct Mailbox *m, OpenMailboxFlags flags)
Definition: mxapi.h:167
enum MxStatus(* mbox_check)(struct Mailbox *m)
Definition: mxapi.h:180
enum MxStatus(* mbox_check_stats)(struct Mailbox *m, uint8_t flags)
Definition: mxapi.h:194
bool(* msg_open)(struct Mailbox *m, struct Message *msg, int msgno)
Definition: mxapi.h:238
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:40
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
NNTP-specific Mailbox data -.
Definition: mdata.h:33
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:69
char * user
Username.
Definition: url.h:71
char * host
Host.
Definition: url.h:73
char * path
Path.
Definition: url.h:75
enum UrlScheme scheme
Scheme, e.g. U_SMTPS.
Definition: url.h:70
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:305
@ MENU_MAIN
Index panel (list of emails)
Definition: type.h:50
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:234
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:123