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