NeoMutt  2022-04-29-145-g9b6a0e
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 = ua && ub && (ua->scheme == ub->scheme) &&
165  mutt_istr_equal(ua->host, ub->host) &&
166  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->visible)
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  mailbox_free(&m_trash);
597 
598  return 0;
599 }
600 
615 enum MxStatus mx_mbox_close(struct Mailbox *m)
616 {
617  if (!m)
618  return MX_STATUS_ERROR;
619 
620  const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
621  if (c_mail_check_recent && !m->peekonly)
622  m->has_new = false;
623 
624  if (m->readonly || m->dontwrite || m->append || m->peekonly)
625  {
626  mx_fastclose_mailbox(m, false);
627  return 0;
628  }
629 
630  int i, read_msgs = 0;
631  enum MxStatus rc = MX_STATUS_ERROR;
632  enum QuadOption move_messages = MUTT_NO;
633  enum QuadOption purge = MUTT_YES;
634  struct Buffer *mbox = NULL;
635  struct Buffer *buf = mutt_buffer_pool_get();
636 
637 #ifdef USE_NNTP
638  if ((m->msg_unread != 0) && (m->type == MUTT_NNTP))
639  {
640  struct NntpMboxData *mdata = m->mdata;
641 
642  if (mdata && mdata->adata && mdata->group)
643  {
644  const enum QuadOption c_catchup_newsgroup = cs_subset_quad(NeoMutt->sub, "catchup_newsgroup");
645  enum QuadOption ans = query_quadoption(c_catchup_newsgroup,
646  _("Mark all articles read?"));
647  if (ans == MUTT_ABORT)
648  goto cleanup;
649  if (ans == MUTT_YES)
650  mutt_newsgroup_catchup(m, mdata->adata, mdata->group);
651  }
652  }
653 #endif
654 
655  const bool c_keep_flagged = cs_subset_bool(NeoMutt->sub, "keep_flagged");
656  for (i = 0; i < m->msg_count; i++)
657  {
658  struct Email *e = m->emails[i];
659  if (!e)
660  break;
661 
662  if (!e->deleted && e->read && !(e->flagged && c_keep_flagged))
663  read_msgs++;
664  }
665 
666 #ifdef USE_NNTP
667  /* don't need to move articles from newsgroup */
668  if (m->type == MUTT_NNTP)
669  read_msgs = 0;
670 #endif
671 
672  const enum QuadOption c_move = cs_subset_quad(NeoMutt->sub, "move");
673  if ((read_msgs != 0) && (c_move != MUTT_NO))
674  {
675  bool is_spool;
676  mbox = mutt_buffer_pool_get();
677 
679  if (p)
680  {
681  is_spool = true;
682  mutt_buffer_strcpy(mbox, p);
683  }
684  else
685  {
686  const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
687  mutt_buffer_strcpy(mbox, c_mbox);
688  is_spool = mutt_is_spool(mailbox_path(m)) &&
690  }
691 
692  if (is_spool && !mutt_buffer_is_empty(mbox))
693  {
695  mutt_buffer_printf(buf,
696  /* L10N: The first argument is the number of read messages to be
697  moved, the second argument is the target mailbox. */
698  ngettext("Move %d read message to %s?",
699  "Move %d read messages to %s?", read_msgs),
700  read_msgs, mutt_buffer_string(mbox));
701  move_messages = query_quadoption(c_move, mutt_buffer_string(buf));
702  if (move_messages == MUTT_ABORT)
703  goto cleanup;
704  }
705  }
706 
707  /* There is no point in asking whether or not to purge if we are
708  * just marking messages as "trash". */
709  const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
710  if ((m->msg_deleted != 0) && !((m->type == MUTT_MAILDIR) && c_maildir_trash))
711  {
712  mutt_buffer_printf(buf,
713  ngettext("Purge %d deleted message?",
714  "Purge %d deleted messages?", m->msg_deleted),
715  m->msg_deleted);
716  const enum QuadOption c_delete = cs_subset_quad(NeoMutt->sub, "delete");
717  purge = query_quadoption(c_delete, mutt_buffer_string(buf));
718  if (purge == MUTT_ABORT)
719  goto cleanup;
720  }
721 
722  const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
723  if (c_mark_old && !m->peekonly)
724  {
725  for (i = 0; i < m->msg_count; i++)
726  {
727  struct Email *e = m->emails[i];
728  if (!e)
729  break;
730  if (!e->deleted && !e->old && !e->read)
731  mutt_set_flag(m, e, MUTT_OLD, true);
732  }
733  }
734 
735  if (move_messages)
736  {
737  if (m->verbose)
738  mutt_message(_("Moving read messages to %s..."), mutt_buffer_string(mbox));
739 
740 #ifdef USE_IMAP
741  /* try to use server-side copy first */
742  i = 1;
743 
744  if ((m->type == MUTT_IMAP) && (imap_path_probe(mutt_buffer_string(mbox), NULL) == MUTT_IMAP))
745  {
746  /* add messages for moving, and clear old tags, if any */
747  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
748  for (i = 0; i < m->msg_count; i++)
749  {
750  struct Email *e = m->emails[i];
751  if (!e)
752  break;
753 
754  if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
755  {
756  e->tagged = true;
757  emaillist_add_email(&el, e);
758  }
759  else
760  e->tagged = false;
761  }
762 
763  i = imap_copy_messages(m, &el, mutt_buffer_string(mbox), SAVE_MOVE);
764  emaillist_clear(&el);
765  }
766 
767  if (i == 0) /* success */
769  else if (i == -1) /* horrible error, bail */
770  goto cleanup;
771  else /* use regular append-copy mode */
772 #endif
773  {
774  struct Mailbox *m_read = mx_path_resolve(mutt_buffer_string(mbox));
775  if (!mx_mbox_open(m_read, MUTT_APPEND))
776  {
777  mailbox_free(&m_read);
778  goto cleanup;
779  }
780 
781  for (i = 0; i < m->msg_count; i++)
782  {
783  struct Email *e = m->emails[i];
784  if (!e)
785  break;
786  if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
787  {
788  if (mutt_append_message(m_read, m, e, NULL, MUTT_CM_NO_FLAGS, CH_UPDATE_LEN) == 0)
789  {
790  mutt_set_flag(m, e, MUTT_DELETE, true);
791  mutt_set_flag(m, e, MUTT_PURGE, true);
792  }
793  else
794  {
795  mx_mbox_close(m_read);
796  goto cleanup;
797  }
798  }
799  }
800 
801  mx_mbox_close(m_read);
802  }
803  }
804  else if (!m->changed && (m->msg_deleted == 0))
805  {
806  if (m->verbose)
807  mutt_message(_("Mailbox is unchanged"));
808  if ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF))
809  mbox_reset_atime(m, NULL);
810  mx_fastclose_mailbox(m, false);
811  rc = MX_STATUS_OK;
812  goto cleanup;
813  }
814 
815  /* copy mails to the trash before expunging */
816  const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
817  const struct Mailbox *m_trash = mx_mbox_find(m->account, c_trash);
818  if (purge && (m->msg_deleted != 0) && (m != m_trash))
819  {
820  if (trash_append(m) != 0)
821  goto cleanup;
822  }
823 
824 #ifdef USE_IMAP
825  /* allow IMAP to preserve the deleted flag across sessions */
826  if (m->type == MUTT_IMAP)
827  {
828  const enum MxStatus check = imap_sync_mailbox(m, (purge != MUTT_NO), true);
829  if (check == MX_STATUS_ERROR)
830  {
831  rc = check;
832  goto cleanup;
833  }
834  }
835  else
836 #endif
837  {
838  if (purge == MUTT_NO)
839  {
840  for (i = 0; i < m->msg_count; i++)
841  {
842  struct Email *e = m->emails[i];
843  if (!e)
844  break;
845 
846  e->deleted = false;
847  e->purge = false;
848  }
849  m->msg_deleted = 0;
850  }
851 
852  if (m->changed || (m->msg_deleted != 0))
853  {
854  enum MxStatus check = sync_mailbox(m);
855  if (check != MX_STATUS_OK)
856  {
857  rc = check;
858  goto cleanup;
859  }
860  }
861  }
862 
863  if (m->verbose)
864  {
865  if (move_messages)
866  {
867  mutt_message(_("%d kept, %d moved, %d deleted"),
868  m->msg_count - m->msg_deleted, read_msgs, m->msg_deleted);
869  }
870  else
871  mutt_message(_("%d kept, %d deleted"), m->msg_count - m->msg_deleted, m->msg_deleted);
872  }
873 
874  const bool c_save_empty = cs_subset_bool(NeoMutt->sub, "save_empty");
875  if ((m->msg_count == m->msg_deleted) &&
876  ((m->type == MUTT_MMDF) || (m->type == MUTT_MBOX)) &&
877  !mutt_is_spool(mailbox_path(m)) && !c_save_empty)
878  {
880  }
881 
882 #ifdef USE_SIDEBAR
883  if ((purge == MUTT_YES) && (m->msg_deleted != 0))
884  {
885  for (i = 0; i < m->msg_count; i++)
886  {
887  struct Email *e = m->emails[i];
888  if (!e)
889  break;
890  if (e->deleted && !e->read)
891  {
892  m->msg_unread--;
893  if (!e->old)
894  m->msg_new--;
895  }
896  if (e->deleted && e->flagged)
897  m->msg_flagged--;
898  }
899  }
900 #endif
901 
902  mx_fastclose_mailbox(m, false);
903 
904  rc = MX_STATUS_OK;
905 
906 cleanup:
909  return rc;
910 }
911 
919 enum MxStatus mx_mbox_sync(struct Mailbox *m)
920 {
921  if (!m)
922  return MX_STATUS_ERROR;
923 
924  enum MxStatus rc = MX_STATUS_OK;
925  int purge = 1;
926  int msgcount, deleted;
927 
928  if (m->dontwrite)
929  {
930  char buf[256], tmp[256];
931  if (km_expand_key(buf, sizeof(buf), km_find_func(MENU_INDEX, OP_TOGGLE_WRITE)))
932  snprintf(tmp, sizeof(tmp), _(" Press '%s' to toggle write"), buf);
933  else
934  mutt_str_copy(tmp, _("Use 'toggle-write' to re-enable write"), sizeof(tmp));
935 
936  mutt_error(_("Mailbox is marked unwritable. %s"), tmp);
937  return MX_STATUS_ERROR;
938  }
939  else if (m->readonly)
940  {
941  mutt_error(_("Mailbox is read-only"));
942  return MX_STATUS_ERROR;
943  }
944 
945  if (!m->changed && (m->msg_deleted == 0))
946  {
947  if (m->verbose)
948  mutt_message(_("Mailbox is unchanged"));
949  return MX_STATUS_OK;
950  }
951 
952  if (m->msg_deleted != 0)
953  {
954  char buf[128];
955 
956  snprintf(buf, sizeof(buf),
957  ngettext("Purge %d deleted message?", "Purge %d deleted messages?", m->msg_deleted),
958  m->msg_deleted);
959  const enum QuadOption c_delete = cs_subset_quad(NeoMutt->sub, "delete");
960  purge = query_quadoption(c_delete, buf);
961  if (purge == MUTT_ABORT)
962  return MX_STATUS_ERROR;
963  if (purge == MUTT_NO)
964  {
965  if (!m->changed)
966  return MX_STATUS_OK; /* nothing to do! */
967  /* let IMAP servers hold on to D flags */
968  if (m->type != MUTT_IMAP)
969  {
970  for (int i = 0; i < m->msg_count; i++)
971  {
972  struct Email *e = m->emails[i];
973  if (!e)
974  break;
975  e->deleted = false;
976  e->purge = false;
977  }
978  m->msg_deleted = 0;
979  }
980  }
982  }
983 
984  /* really only for IMAP - imap_sync_mailbox results in a call to
985  * ctx_update_tables, so m->msg_deleted is 0 when it comes back */
986  msgcount = m->msg_count;
987  deleted = m->msg_deleted;
988 
989  const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
990  const struct Mailbox *m_trash = mx_mbox_find(m->account, c_trash);
991  if (purge && (m->msg_deleted != 0) && (m != m_trash))
992  {
993  if (trash_append(m) != 0)
994  return MX_STATUS_OK;
995  }
996 
997 #ifdef USE_IMAP
998  if (m->type == MUTT_IMAP)
999  rc = imap_sync_mailbox(m, purge, false);
1000  else
1001 #endif
1002  rc = sync_mailbox(m);
1003  if (rc != MX_STATUS_ERROR)
1004  {
1005 #ifdef USE_IMAP
1006  if ((m->type == MUTT_IMAP) && !purge)
1007  {
1008  if (m->verbose)
1009  mutt_message(_("Mailbox checkpointed"));
1010  }
1011  else
1012 #endif
1013  {
1014  if (m->verbose)
1015  mutt_message(_("%d kept, %d deleted"), msgcount - deleted, deleted);
1016  }
1017 
1018  mutt_sleep(0);
1019 
1020  const bool c_save_empty = cs_subset_bool(NeoMutt->sub, "save_empty");
1021  if ((m->msg_count == m->msg_deleted) &&
1022  ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) &&
1023  !mutt_is_spool(mailbox_path(m)) && !c_save_empty)
1024  {
1025  unlink(mailbox_path(m));
1026  mx_fastclose_mailbox(m, false);
1027  return MX_STATUS_OK;
1028  }
1029 
1030  /* if we haven't deleted any messages, we don't need to resort
1031  * ... except for certain folder formats which need "unsorted"
1032  * sort order in order to synchronize folders.
1033  *
1034  * MH and maildir are safe. mbox-style seems to need re-sorting,
1035  * at least with the new threading code. */
1036  if (purge || ((m->type != MUTT_MAILDIR) && (m->type != MUTT_MH)))
1037  {
1038  /* IMAP does this automatically after handling EXPUNGE */
1039  if (m->type != MUTT_IMAP)
1040  {
1043  }
1044  }
1045  }
1046 
1047  return rc;
1048 }
1049 
1057 struct Message *mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
1058 {
1059  if (!m)
1060  return NULL;
1061 
1062  struct Address *p = NULL;
1063  struct Message *msg = NULL;
1064 
1065  if (!m->mx_ops || !m->mx_ops->msg_open_new)
1066  {
1067  mutt_debug(LL_DEBUG1, "function unimplemented for mailbox type %d\n", m->type);
1068  return NULL;
1069  }
1070 
1071  msg = mutt_mem_calloc(1, sizeof(struct Message));
1072  msg->write = true;
1073 
1074  if (e)
1075  {
1076  msg->flags.flagged = e->flagged;
1077  msg->flags.replied = e->replied;
1078  msg->flags.read = e->read;
1079  msg->flags.draft = (flags & MUTT_SET_DRAFT);
1080  msg->received = e->received;
1081  }
1082 
1083  if (msg->received == 0)
1084  msg->received = mutt_date_epoch();
1085 
1086  if (m->mx_ops->msg_open_new(m, msg, e))
1087  {
1088  if (m->type == MUTT_MMDF)
1089  fputs(MMDF_SEP, msg->fp);
1090 
1091  if (((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) && (flags & MUTT_ADD_FROM))
1092  {
1093  if (e)
1094  {
1095  p = TAILQ_FIRST(&e->env->return_path);
1096  if (!p)
1097  p = TAILQ_FIRST(&e->env->sender);
1098  if (!p)
1099  p = TAILQ_FIRST(&e->env->from);
1100  }
1101 
1102  // Force a 'C' locale for the date, so that day/month names are in English
1103  char buf[64] = { 0 };
1104  struct tm tm = mutt_date_localtime(msg->received);
1105 #ifdef LC_TIME_MASK
1106  locale_t loc = newlocale(LC_TIME_MASK, "C", 0);
1107  strftime_l(buf, sizeof(buf), "%a %b %e %H:%M:%S %Y", &tm, loc);
1108  freelocale(loc);
1109 #else /* !LC_TIME_MASK */
1110  strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Y", &tm);
1111 #endif /* LC_TIME_MASK */
1112  fprintf(msg->fp, "From %s %s\n", p ? p->mailbox : NONULL(Username), buf);
1113  }
1114  }
1115  else
1116  FREE(&msg);
1117 
1118  return msg;
1119 }
1120 
1126 enum MxStatus mx_mbox_check(struct Mailbox *m)
1127 {
1128  if (!m || !m->mx_ops)
1129  return MX_STATUS_ERROR;
1130 
1131  enum MxStatus rc = m->mx_ops->mbox_check(m);
1132  if ((rc == MX_STATUS_NEW_MAIL) || (rc == MX_STATUS_REOPENED))
1133  {
1135  }
1136 
1137  return rc;
1138 }
1139 
1147 struct Message *mx_msg_open(struct Mailbox *m, int msgno)
1148 {
1149  if (!m || !m->emails || (msgno < 0) || (msgno >= m->msg_count))
1150  return NULL;
1151 
1152  if (!m->mx_ops || !m->mx_ops->msg_open)
1153  {
1154  mutt_debug(LL_DEBUG1, "function not implemented for mailbox type %d\n", m->type);
1155  return NULL;
1156  }
1157 
1158  struct Message *msg = mutt_mem_calloc(1, sizeof(struct Message));
1159  if (!m->mx_ops->msg_open(m, msg, msgno))
1160  FREE(&msg);
1161 
1162  return msg;
1163 }
1164 
1172 int mx_msg_commit(struct Mailbox *m, struct Message *msg)
1173 {
1174  if (!m || !m->mx_ops || !m->mx_ops->msg_commit || !msg)
1175  return -1;
1176 
1177  if (!(msg->write && m->append))
1178  {
1179  mutt_debug(LL_DEBUG1, "msg->write = %d, m->append = %d\n", msg->write, m->append);
1180  return -1;
1181  }
1182 
1183  return m->mx_ops->msg_commit(m, msg);
1184 }
1185 
1193 int mx_msg_close(struct Mailbox *m, struct Message **msg)
1194 {
1195  if (!m || !msg || !*msg)
1196  return 0;
1197 
1198  int rc = 0;
1199 
1200  if (m->mx_ops && m->mx_ops->msg_close)
1201  rc = m->mx_ops->msg_close(m, *msg);
1202 
1203  if ((*msg)->path)
1204  {
1205  mutt_debug(LL_DEBUG1, "unlinking %s\n", (*msg)->path);
1206  unlink((*msg)->path);
1207  FREE(&(*msg)->path);
1208  }
1209 
1210  FREE(&(*msg)->committed_path);
1211  FREE(msg);
1212  return rc;
1213 }
1214 
1219 void mx_alloc_memory(struct Mailbox *m)
1220 {
1221  const int grow = 25;
1222  size_t s = MAX(sizeof(struct Email *), sizeof(int));
1223 
1224  if (((m->email_max + grow) * s) < (m->email_max * s))
1225  {
1226  mutt_error(_("Out of memory"));
1227  mutt_exit(1);
1228  }
1229 
1230  m->email_max += grow;
1231  if (m->emails)
1232  {
1233  mutt_mem_realloc(&m->emails, m->email_max * sizeof(struct Email *));
1234  mutt_mem_realloc(&m->v2r, m->email_max * sizeof(int));
1235  }
1236  else
1237  {
1238  m->emails = mutt_mem_calloc(m->email_max, sizeof(struct Email *));
1239  m->v2r = mutt_mem_calloc(m->email_max, sizeof(int));
1240  }
1241  for (int i = m->email_max - grow; i < m->email_max; i++)
1242  {
1243  if (i < m->email_max)
1244  {
1245  m->emails[i] = NULL;
1246  m->v2r[i] = -1;
1247  }
1248  }
1249 }
1250 
1258 int mx_path_is_empty(const char *path)
1259 {
1260  if (!path || (*path == '\0'))
1261  return -1;
1262 
1263  enum MailboxType type = mx_path_probe(path);
1264  const struct MxOps *ops = mx_get_ops(type);
1265  if (!ops || !ops->path_is_empty)
1266  return -1;
1267 
1268  return ops->path_is_empty(path);
1269 }
1270 
1280 int mx_tags_edit(struct Mailbox *m, const char *tags, struct Buffer *buf)
1281 {
1282  if (!m || !buf)
1283  return -1;
1284 
1285  if (m->mx_ops->tags_edit)
1286  return m->mx_ops->tags_edit(m, tags, buf);
1287 
1288  mutt_message(_("Folder doesn't support tagging, aborting"));
1289  return -1;
1290 }
1291 
1300 int mx_tags_commit(struct Mailbox *m, struct Email *e, const char *tags)
1301 {
1302  if (!m || !e || !tags)
1303  return -1;
1304 
1305  if (m->mx_ops->tags_commit)
1306  return m->mx_ops->tags_commit(m, e, tags);
1307 
1308  mutt_message(_("Folder doesn't support tagging, aborting"));
1309  return -1;
1310 }
1311 
1318 {
1319  return m && m->mx_ops->tags_commit && m->mx_ops->tags_edit;
1320 }
1321 
1327 enum MailboxType mx_path_probe(const char *path)
1328 {
1329  if (!path)
1330  return MUTT_UNKNOWN;
1331 
1332  enum MailboxType rc = MUTT_UNKNOWN;
1333 
1334  // First, search the non-local Mailbox types (is_local == false)
1335  for (const struct MxOps **ops = MxOps; *ops; ops++)
1336  {
1337  if ((*ops)->is_local)
1338  continue;
1339  rc = (*ops)->path_probe(path, NULL);
1340  if (rc != MUTT_UNKNOWN)
1341  return rc;
1342  }
1343 
1344  struct stat st = { 0 };
1345  if (stat(path, &st) != 0)
1346  {
1347  mutt_debug(LL_DEBUG1, "unable to stat %s: %s (errno %d)\n", path, strerror(errno), errno);
1348  return MUTT_UNKNOWN;
1349  }
1350 
1351  if (S_ISFIFO(st.st_mode))
1352  {
1353  mutt_error(_("Can't open %s: it is a pipe"), path);
1354  return MUTT_UNKNOWN;
1355  }
1356 
1357  // Next, search the local Mailbox types (is_local == true)
1358  for (const struct MxOps **ops = MxOps; *ops; ops++)
1359  {
1360  if (!(*ops)->is_local)
1361  continue;
1362  rc = (*ops)->path_probe(path, &st);
1363  if (rc != MUTT_UNKNOWN)
1364  return rc;
1365  }
1366 
1367  return rc;
1368 }
1369 
1373 int mx_path_canon(char *buf, size_t buflen, const char *folder, enum MailboxType *type)
1374 {
1375  if (!buf)
1376  return -1;
1377 
1378  for (size_t i = 0; i < 3; i++)
1379  {
1380  /* Look for !! ! - < > or ^ followed by / or NUL */
1381  if ((buf[0] == '!') && (buf[1] == '!'))
1382  {
1383  if (((buf[2] == '/') || (buf[2] == '\0')))
1384  {
1385  mutt_str_inline_replace(buf, buflen, 2, LastFolder);
1386  }
1387  }
1388  else if ((buf[0] == '+') || (buf[0] == '='))
1389  {
1390  size_t folder_len = mutt_str_len(folder);
1391  if ((folder_len > 0) && (folder[folder_len - 1] != '/'))
1392  {
1393  buf[0] = '/';
1394  mutt_str_inline_replace(buf, buflen, 0, folder);
1395  }
1396  else
1397  {
1398  mutt_str_inline_replace(buf, buflen, 1, folder);
1399  }
1400  }
1401  else if ((buf[1] == '/') || (buf[1] == '\0'))
1402  {
1403  if (buf[0] == '!')
1404  {
1405  const char *const c_spool_file = 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  mutt_buffer_strcpy(&m->pathbuf, path);
1688  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1689  mx_path_canon2(m, c_folder);
1690 
1691  return m;
1692 }
1693 
1700 static struct Mailbox *mx_mbox_find_by_name_ac(struct Account *a, const char *name)
1701 {
1702  if (!a || !name)
1703  return NULL;
1704 
1705  struct MailboxNode *np = NULL;
1706 
1707  STAILQ_FOREACH(np, &a->mailboxes, entries)
1708  {
1709  if (mutt_str_equal(np->mailbox->name, name))
1710  return np->mailbox;
1711  }
1712 
1713  return NULL;
1714 }
1715 
1721 static struct Mailbox *mx_mbox_find_by_name(const char *name)
1722 {
1723  if (!name)
1724  return NULL;
1725 
1726  struct Account *np = NULL;
1727  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1728  {
1729  struct Mailbox *m = mx_mbox_find_by_name_ac(np, name);
1730  if (m)
1731  return m;
1732  }
1733 
1734  return NULL;
1735 }
1736 
1746 struct Mailbox *mx_resolve(const char *path_or_name)
1747 {
1748  if (!path_or_name)
1749  return NULL;
1750 
1751  // Order is name first because you can create a Mailbox from
1752  // a path, but can't from a name. So fallback behavior creates
1753  // a new Mailbox for us.
1754  struct Mailbox *m = mx_mbox_find_by_name(path_or_name);
1755  if (!m)
1756  m = mx_path_resolve(path_or_name);
1757 
1758  return m;
1759 }
1760 
1764 bool mx_ac_add(struct Account *a, struct Mailbox *m)
1765 {
1766  if (!a || !m || !m->mx_ops || !m->mx_ops->ac_add)
1767  return false;
1768 
1769  return m->mx_ops->ac_add(a, m) && account_mailbox_add(a, m);
1770 }
1771 
1781 int mx_ac_remove(struct Mailbox *m, bool keep_account)
1782 {
1783  if (!m || !m->account)
1784  return -1;
1785 
1786  struct Account *a = m->account;
1788  if (!keep_account && STAILQ_EMPTY(&a->mailboxes))
1789  {
1791  }
1792  return 0;
1793 }
1794 
1800 enum MxStatus mx_mbox_check_stats(struct Mailbox *m, uint8_t flags)
1801 {
1802  if (!m)
1803  return MX_STATUS_ERROR;
1804 
1805  enum MxStatus rc = m->mx_ops->mbox_check_stats(m, flags);
1806  if (rc != MX_STATUS_ERROR)
1807  {
1808  struct EventMailbox ev_m = { m };
1810  }
1811 
1812  return rc;
1813 }
1814 
1824 int mx_save_hcache(struct Mailbox *m, struct Email *e)
1825 {
1826  if (!m || !m->mx_ops || !m->mx_ops->msg_save_hcache || !e)
1827  return 0;
1828 
1829  return m->mx_ops->msg_save_hcache(m, e);
1830 }
1831 
1837 enum MailboxType mx_type(struct Mailbox *m)
1838 {
1839  return m ? m->type : MUTT_MAILBOX_ERROR;
1840 }
1841 
1848 int mx_toggle_write(struct Mailbox *m)
1849 {
1850  if (!m)
1851  return -1;
1852 
1853  if (m->readonly)
1854  {
1855  mutt_error(_("Can't toggle write on a readonly mailbox"));
1856  return -1;
1857  }
1858 
1859  if (m->dontwrite)
1860  {
1861  m->dontwrite = false;
1862  mutt_message(_("Changes to folder will be written on folder exit"));
1863  }
1864  else
1865  {
1866  m->dontwrite = true;
1867  mutt_message(_("Changes to folder will not be written"));
1868  }
1869 
1870  struct EventMailbox ev_m = { m };
1872  return 0;
1873 }
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:141
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:250
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:310
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:158
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:362
Compressed mbox local mailbox type.
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
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:939
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
Structs that make up an email.
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:43
void mutt_file_unlink_empty(const char *path)
Delete a file if it's empty.
Definition: file.c:1367
#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:1645
struct MxOps MxMhOps
MH Mailbox - Implements MxOps -.
Definition: mh.c:1254
struct MxOps MxCompOps
Compressed Mailbox - Implements MxOps -.
Definition: compress.c:937
struct MxOps MxMmdfOps
MMDF Mailbox - Implements MxOps -.
Definition: mbox.c:1874
struct MxOps MxNntpOps
NNTP Mailbox - Implements MxOps -.
Definition: nntp.c:2738
struct MxOps MxImapOps
IMAP Mailbox - Implements MxOps -.
Definition: imap.c:2486
struct MxOps MxMboxOps
Mbox Mailbox - Implements MxOps -.
Definition: mbox.c:1842
struct MxOps MxNotmuchOps
Notmuch Mailbox - Implements MxOps -.
Definition: notmuch.c:2469
struct MxOps MxPopOps
POP Mailbox - Implements MxOps -.
Definition: pop.c:1197
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2400
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:457
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:731
char * mutt_find_hook(HookFlags type, const char *pat)
Find a matching hook.
Definition: hook.c:631
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:1672
int imap_mxcmp(const char *mx1, const char *mx2)
Compare mailbox names, giving priority to INBOX.
Definition: util.c:553
int imap_fast_trash(struct Mailbox *m, const char *dest)
Use server COPY command to copy deleted messages to trash.
Definition: imap.c:1424
enum MxStatus imap_sync_mailbox(struct Mailbox *m, bool expunge, bool close)
Sync all the changes to the server.
Definition: imap.c:1534
int imap_access(const char *path)
Check permissions on an IMAP mailbox with a new connection.
Definition: imap.c:473
struct Keymap * km_find_func(enum MenuType mtype, int func)
Find a function's mapping in a Menu.
Definition: keymap.c:954
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:926
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:222
@ NT_MAILBOX_UNTAG
Clear the 'last-tagged' pointer.
Definition: mailbox.h:180
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition: mailbox.h:173
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:178
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:177
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition: mailbox.h:179
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:211
#define MUTT_ACL_ALL
Definition: mailbox.h:73
MailboxType
Supported mailbox formats.
Definition: mailbox.h:41
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:46
@ MUTT_MAILBOX_ERROR
Error occurred examining Mailbox.
Definition: mailbox.h:43
@ MUTT_MH
'MH' Mailbox type
Definition: mailbox.h:47
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:49
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:45
@ MUTT_COMPRESSED
Compressed file Mailbox type.
Definition: mailbox.h:53
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:44
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:48
Maildir local mailbox type.
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:248
#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:848
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:43
#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:926
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:796
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:784
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:544
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:629
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
Many unsorted constants and some structs.
@ MUTT_OLD
Old messages.
Definition: mutt.h:91
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:97
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:95
#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:371
Representation of the email's header.
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
NeoMutt Logging.
void mutt_mailbox_set_notified(struct Mailbox *m)
Note when the user was last notified of new mail.
Definition: mutt_mailbox.c:312
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:1455
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1356
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:1280
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:1700
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1193
int mx_ac_remove(struct Mailbox *m, bool keep_account)
Remove a Mailbox from an Account and delete Account if empty.
Definition: mx.c:1781
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:1800
static struct Mailbox * mx_mbox_find_by_name(const char *name)
Find a Mailbox with given name.
Definition: mx.c:1721
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:1373
int mx_path_is_empty(const char *path)
Is the mailbox empty.
Definition: mx.c:1258
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:1147
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:1764
bool mx_tags_is_supported(struct Mailbox *m)
Return true if mailbox support tagging.
Definition: mx.c:1317
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:1300
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:1824
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:1219
enum MailboxType mx_type(struct Mailbox *m)
Return the type of the Mailbox.
Definition: mx.c:1837
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:1848
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1172
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1327
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:1126
enum MxStatus mx_mbox_sync(struct Mailbox *m)
Save changes to mailbox.
Definition: mx.c:919
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1057
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:1746
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:615
API for mailboxes.
uint8_t MsgOpenFlags
Flags for mx_msg_open_new(), e.g. MUTT_ADD_FROM.
Definition: mx.h:41
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:43
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:44
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h:64
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mxapi.h:60
#define MUTT_NEWFOLDER
Create a new folder - same as MUTT_APPEND,.
Definition: mxapi.h:66
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:63
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:65
MxOpenReturns
Return values for mbox_open()
Definition: mxapi.h:97
@ MX_OPEN_ABORT
Open was aborted.
Definition: mxapi.h:100
@ MX_OPEN_OK
Open succeeded.
Definition: mxapi.h:98
#define MUTT_PEEK
Revert atime back after taking a look (if applicable)
Definition: mxapi.h:69
#define MUTT_NOSORT
Do not sort the mailbox after opening it.
Definition: mxapi.h:62
#define MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn't exist.
Definition: mxapi.h:70
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_snc(), and mbox_close()
Definition: mxapi.h:84
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:85
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:86
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:89
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:87
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:1321
Nntp-specific Mailbox data.
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:49
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:64
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:386
#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:58
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
struct AddressList sender
Email's sender.
Definition: envelope.h:63
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
An Event that happened to a Mailbox.
Definition: mailbox.h:187
List of Mailboxes.
Definition: mailbox.h:154
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:155
A mailbox.
Definition: mailbox.h:79
int vcount
The number of virtual messages.
Definition: mailbox.h:99
bool changed
Mailbox has been modified.
Definition: mailbox.h:111
bool has_new
Mailbox has new mail.
Definition: mailbox.h:85
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:81
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:110
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:98
const struct MxOps * mx_ops
MXAPI callback functions.
Definition: mailbox.h:108
int msg_new
Number of new messages.
Definition: mailbox.h:92
int msg_count
Total number of messages.
Definition: mailbox.h:88
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:118
int email_max
Number of pointers in emails.
Definition: mailbox.h:97
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
void * mdata
Driver specific data.
Definition: mailbox.h:133
struct HashTable * subj_hash
Hash Table by subject.
Definition: mailbox.h:125
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
char * name
A short name for the Mailbox.
Definition: mailbox.h:82
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition: mailbox.h:145
struct HashTable * id_hash
Hash Table by msg id.
Definition: mailbox.h:124
struct Buffer pathbuf
Path of the Mailbox.
Definition: mailbox.h:80
bool peekonly
Just taking a glance, revert atime.
Definition: mailbox.h:114
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:93
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:128
bool dontwrite
Don't write the mailbox on close.
Definition: mailbox.h:112
off_t size
Size of the Mailbox.
Definition: mailbox.h:84
struct HashTable * label_hash
Hash Table for x-labels.
Definition: mailbox.h:126
bool visible
True if a result of "mailboxes".
Definition: mailbox.h:131
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:90
int opened
Number of times mailbox is opened.
Definition: mailbox.h:129
bool readonly
Don't allow changes to the mailbox.
Definition: mailbox.h:116
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:94
bool verbose
Display status messages?
Definition: mailbox.h:115
int msg_unread
Number of unread messages.
Definition: mailbox.h:89
Mapping between user-readable string and a constant.
Definition: mapping.h:32
A local copy of an email.
Definition: mxapi.h:43
FILE * fp
pointer to the message data
Definition: mxapi.h:44
char * path
path to temp file
Definition: mxapi.h:45
bool draft
Message has been read.
Definition: mxapi.h:53
bool replied
Message has been replied to.
Definition: mxapi.h:52
time_t received
Time at which this message was received.
Definition: mxapi.h:55
bool write
nonzero if message is open for writing
Definition: mxapi.h:47
bool flagged
Message is flagged.
Definition: mxapi.h:51
bool read
Message has been read.
Definition: mxapi.h:50
struct Message::@0 flags
Flags for the Message.
Definition: mxapi.h:112
int(* tags_commit)(struct Mailbox *m, struct Email *e, const char *buf)
Definition: mxapi.h:360
int(* path_pretty)(char *buf, size_t buflen, const char *folder)
Definition: mxapi.h:405
int(* msg_save_hcache)(struct Mailbox *m, struct Email *e)
Definition: mxapi.h:324
int(* path_is_empty)(const char *path)
Definition: mxapi.h:435
enum MailboxType type
Mailbox type, e.g. MUTT_IMAP.
Definition: mxapi.h:113
int(* msg_padding_size)(struct Mailbox *m)
Definition: mxapi.h:308
bool(* ac_owns_path)(struct Account *a, const char *path)
Definition: mxapi.h:131
int(* tags_edit)(struct Mailbox *m, const char *tags, struct Buffer *buf)
Definition: mxapi.h:342
int(* msg_commit)(struct Mailbox *m, struct Message *msg)
Definition: mxapi.h:279
enum MxStatus(* mbox_check_stats)(struct Mailbox *m, CheckStatsFlags flags)
Definition: mxapi.h:202
bool(* ac_add)(struct Account *a, struct Mailbox *m)
Definition: mxapi.h:147
enum MxOpenReturns(* mbox_open)(struct Mailbox *m)
Definition: mxapi.h:160
int(* msg_close)(struct Mailbox *m, struct Message *msg)
Definition: mxapi.h:295
int(* path_canon)(char *buf, size_t buflen)
Definition: mxapi.h:389
bool(* msg_open_new)(struct Mailbox *m, struct Message *msg, const struct Email *e)
Definition: mxapi.h:263
enum MxStatus(* mbox_close)(struct Mailbox *m)
Definition: mxapi.h:228
enum MxStatus(* mbox_sync)(struct Mailbox *m)
Definition: mxapi.h:215
bool(* mbox_open_append)(struct Mailbox *m, OpenMailboxFlags flags)
Definition: mxapi.h:175
enum MxStatus(* mbox_check)(struct Mailbox *m)
Definition: mxapi.h:188
bool(* msg_open)(struct Mailbox *m, struct Message *msg, int msgno)
Definition: mxapi.h:246
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_INDEX
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