NeoMutt  2021-02-05-666-ge300cd
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 // clang-format off
89 static const struct Mapping MboxTypeMap[] = {
90  { "mbox", MUTT_MBOX, },
91  { "MMDF", MUTT_MMDF, },
92  { "MH", MUTT_MH, },
93  { "Maildir", MUTT_MAILDIR, },
94  { NULL, 0, },
95 };
96 // clang-format on
97 
98 struct EnumDef MboxTypeDef = {
99  "mbox_type",
100  4,
101  (struct Mapping *) &MboxTypeMap,
102 };
103 
107 const struct MxOps *mx_ops[] = {
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 = mx_ops; *ops; ops++)
144  if ((*ops)->type == type)
145  return *ops;
146 
147  return NULL;
148 }
149 
155 static bool mutt_is_spool(const char *str)
156 {
157  const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
158  if (mutt_str_equal(str, c_spool_file))
159  return true;
160 
161  struct Url *ua = url_parse(str);
162  struct Url *ub = url_parse(c_spool_file);
163 
164  const bool is_spool =
165  ua && ub && (ua->scheme == ub->scheme) &&
166  mutt_istr_equal(ua->host, ub->host) && mutt_istr_equal(ua->path, ub->path) &&
167  (!ua->user || !ub->user || mutt_str_equal(ua->user, ub->user));
168 
169  url_free(&ua);
170  url_free(&ub);
171  return is_spool;
172 }
173 
184 int mx_access(const char *path, int flags)
185 {
186 #ifdef USE_IMAP
187  if (imap_path_probe(path, NULL) == MUTT_IMAP)
188  return imap_access(path);
189 #endif
190 
191  return access(path, flags);
192 }
193 
201 static bool mx_open_mailbox_append(struct Mailbox *m, OpenMailboxFlags flags)
202 {
203  if (!m)
204  return false;
205 
206  struct stat sb;
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), &sb) == -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  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:
420  if (newly_linked_account)
422  return false;
423 }
424 
430 {
431  if (!m)
432  return;
433 
434  m->opened--;
435  if (m->opened != 0)
436  return;
437 
438  /* never announce that a mailbox we've just left has new mail.
439  * TODO: really belongs in mx_mbox_close, but this is a nice hook point */
440  if (!m->peekonly)
442 
443  if (m->mx_ops)
444  m->mx_ops->mbox_close(m);
445 
447  mutt_hash_free(&m->id_hash);
449 
450  if (m->emails)
451  {
452  for (int i = 0; i < m->msg_count; i++)
453  {
454  if (!m->emails[i])
455  break;
456  email_free(&m->emails[i]);
457  }
458  }
459 
460  if (m->flags & MB_HIDDEN)
461  {
462  mx_ac_remove(m);
463  }
464 }
465 
471 static enum MxStatus sync_mailbox(struct Mailbox *m)
472 {
473  if (!m || !m->mx_ops || !m->mx_ops->mbox_sync)
474  return MX_STATUS_ERROR;
475 
476  if (m->verbose)
477  {
478  /* L10N: Displayed before/as a mailbox is being synced */
479  mutt_message(_("Writing %s..."), mailbox_path(m));
480  }
481 
482  enum MxStatus rc = m->mx_ops->mbox_sync(m);
483  if (rc != MX_STATUS_OK)
484  {
485  mutt_debug(LL_DEBUG2, "mbox_sync returned: %d\n", rc);
486  if ((rc == MX_STATUS_ERROR) && m->verbose)
487  {
488  /* L10N: Displayed if a mailbox sync fails */
489  mutt_error(_("Unable to write %s"), mailbox_path(m));
490  }
491  }
492 
493  return rc;
494 }
495 
502 static int trash_append(struct Mailbox *m)
503 {
504  if (!m)
505  return -1;
506 
507  struct stat st, stc;
508  int rc;
509 
510  const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
511  const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
512  if (!c_trash || (m->msg_deleted == 0) || ((m->type == MUTT_MAILDIR) && c_maildir_trash))
513  {
514  return 0;
515  }
516 
517  int delmsgcount = 0;
518  int first_del = -1;
519  for (int i = 0; i < m->msg_count; i++)
520  {
521  struct Email *e = m->emails[i];
522  if (!e)
523  break;
524 
525  if (e->deleted && !e->purge)
526  {
527  if (first_del < 0)
528  first_del = i;
529  delmsgcount++;
530  }
531  }
532 
533  if (delmsgcount == 0)
534  return 0; /* nothing to be done */
535 
536  /* avoid the "append messages" prompt */
537  const bool c_confirm_append = cs_subset_bool(NeoMutt->sub, "confirm_append");
538  cs_subset_str_native_set(NeoMutt->sub, "confirm_append", false, NULL);
539  rc = mutt_save_confirm(c_trash, &st);
540  cs_subset_str_native_set(NeoMutt->sub, "confirm_append", c_confirm_append, NULL);
541  if (rc != 0)
542  {
543  /* L10N: Although we know the precise number of messages, we do not show it to the user.
544  So feel free to use a "generic plural" as plural translation if your language has one. */
545  mutt_error(ngettext("message not deleted", "messages not deleted", delmsgcount));
546  return -1;
547  }
548 
549  if ((lstat(mailbox_path(m), &stc) == 0) && (stc.st_ino == st.st_ino) &&
550  (stc.st_dev == st.st_dev) && (stc.st_rdev == st.st_rdev))
551  {
552  return 0; /* we are in the trash folder: simple sync */
553  }
554 
555 #ifdef USE_IMAP
556  if ((m->type == MUTT_IMAP) && (imap_path_probe(c_trash, NULL) == MUTT_IMAP))
557  {
558  if (imap_fast_trash(m, c_trash) == 0)
559  return 0;
560  }
561 #endif
562 
563  struct Mailbox *m_trash = mx_path_resolve(c_trash);
564  const bool old_append = m_trash->append;
565  if (!mx_mbox_open(m_trash, MUTT_APPEND))
566  {
567  mutt_error(_("Can't open trash folder"));
568  mailbox_free(&m_trash);
569  return -1;
570  }
571 
572  /* continue from initial scan above */
573  for (int i = first_del; i < m->msg_count; i++)
574  {
575  struct Email *e = m->emails[i];
576  if (!e)
577  break;
578 
579  if (e->deleted && !e->purge)
580  {
581  if (mutt_append_message(m_trash, m, e, NULL, MUTT_CM_NO_FLAGS, CH_NO_FLAGS) == -1)
582  {
583  mx_mbox_close(m_trash);
584  m_trash->append = old_append;
585  return -1;
586  }
587  }
588  }
589 
590  mx_mbox_close(m_trash);
591  m_trash->append = old_append;
592 
593  return 0;
594 }
595 
611 {
612  if (!m)
613  return MX_STATUS_ERROR;
614 
615  const bool c_mail_check_recent =
616  cs_subset_bool(NeoMutt->sub, "mail_check_recent");
617  if (c_mail_check_recent && !m->peekonly)
618  m->has_new = false;
619 
620  if (m->readonly || m->dontwrite || m->append || m->peekonly)
621  {
623  return 0;
624  }
625 
626  int i, read_msgs = 0;
627  enum MxStatus rc = MX_STATUS_ERROR;
628  enum QuadOption move_messages = MUTT_NO;
629  enum QuadOption purge = MUTT_YES;
630  struct Buffer *mbox = NULL;
631  struct Buffer *buf = mutt_buffer_pool_get();
632 
633 #ifdef USE_NNTP
634  if ((m->msg_unread != 0) && (m->type == MUTT_NNTP))
635  {
636  struct NntpMboxData *mdata = m->mdata;
637 
638  if (mdata && mdata->adata && mdata->group)
639  {
640  const enum QuadOption c_catchup_newsgroup =
641  cs_subset_quad(NeoMutt->sub, "catchup_newsgroup");
642  enum QuadOption ans =
643  query_quadoption(c_catchup_newsgroup, _("Mark all articles read?"));
644  if (ans == MUTT_ABORT)
645  goto cleanup;
646  if (ans == MUTT_YES)
647  mutt_newsgroup_catchup(m, mdata->adata, mdata->group);
648  }
649  }
650 #endif
651 
652  const bool c_keep_flagged = cs_subset_bool(NeoMutt->sub, "keep_flagged");
653  for (i = 0; i < m->msg_count; i++)
654  {
655  struct Email *e = m->emails[i];
656  if (!e)
657  break;
658 
659  if (!e->deleted && e->read && !(e->flagged && c_keep_flagged))
660  read_msgs++;
661  }
662 
663 #ifdef USE_NNTP
664  /* don't need to move articles from newsgroup */
665  if (m->type == MUTT_NNTP)
666  read_msgs = 0;
667 #endif
668 
669  const enum QuadOption c_move = cs_subset_quad(NeoMutt->sub, "move");
670  if ((read_msgs != 0) && (c_move != MUTT_NO))
671  {
672  bool is_spool;
673  mbox = mutt_buffer_pool_get();
674 
676  if (p)
677  {
678  is_spool = true;
679  mutt_buffer_strcpy(mbox, p);
680  }
681  else
682  {
683  const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
684  mutt_buffer_strcpy(mbox, c_mbox);
685  is_spool = mutt_is_spool(mailbox_path(m)) &&
687  }
688 
689  if (is_spool && !mutt_buffer_is_empty(mbox))
690  {
692  mutt_buffer_printf(buf,
693  /* L10N: The first argument is the number of read messages to be
694  moved, the second argument is the target mailbox. */
695  ngettext("Move %d read message to %s?",
696  "Move %d read messages to %s?", read_msgs),
697  read_msgs, mutt_buffer_string(mbox));
698  move_messages = query_quadoption(c_move, mutt_buffer_string(buf));
699  if (move_messages == MUTT_ABORT)
700  goto cleanup;
701  }
702  }
703 
704  /* There is no point in asking whether or not to purge if we are
705  * just marking messages as "trash". */
706  const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
707  if ((m->msg_deleted != 0) && !((m->type == MUTT_MAILDIR) && c_maildir_trash))
708  {
709  mutt_buffer_printf(buf,
710  ngettext("Purge %d deleted message?",
711  "Purge %d deleted messages?", m->msg_deleted),
712  m->msg_deleted);
713  const enum QuadOption c_delete = cs_subset_quad(NeoMutt->sub, "delete");
714  purge = query_quadoption(c_delete, mutt_buffer_string(buf));
715  if (purge == MUTT_ABORT)
716  goto cleanup;
717  }
718 
719  const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
720  if (c_mark_old && !m->peekonly)
721  {
722  for (i = 0; i < m->msg_count; i++)
723  {
724  struct Email *e = m->emails[i];
725  if (!e)
726  break;
727  if (!e->deleted && !e->old && !e->read)
728  mutt_set_flag(m, e, MUTT_OLD, true);
729  }
730  }
731 
732  if (move_messages)
733  {
734  if (m->verbose)
735  mutt_message(_("Moving read messages to %s..."), mutt_buffer_string(mbox));
736 
737 #ifdef USE_IMAP
738  /* try to use server-side copy first */
739  i = 1;
740 
741  if ((m->type == MUTT_IMAP) && (imap_path_probe(mutt_buffer_string(mbox), NULL) == MUTT_IMAP))
742  {
743  /* add messages for moving, and clear old tags, if any */
744  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
745  for (i = 0; i < m->msg_count; i++)
746  {
747  struct Email *e = m->emails[i];
748  if (!e)
749  break;
750 
751  if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
752  {
753  e->tagged = true;
754  emaillist_add_email(&el, e);
755  }
756  else
757  e->tagged = false;
758  }
759 
760  i = imap_copy_messages(m, &el, mutt_buffer_string(mbox), SAVE_MOVE);
761  emaillist_clear(&el);
762  }
763 
764  if (i == 0) /* success */
766  else if (i == -1) /* horrible error, bail */
767  goto cleanup;
768  else /* use regular append-copy mode */
769 #endif
770  {
771  struct Mailbox *m_read = mx_path_resolve(mutt_buffer_string(mbox));
772  if (!mx_mbox_open(m_read, MUTT_APPEND))
773  {
774  mailbox_free(&m_read);
775  goto cleanup;
776  }
777 
778  for (i = 0; i < m->msg_count; i++)
779  {
780  struct Email *e = m->emails[i];
781  if (!e)
782  break;
783  if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
784  {
785  if (mutt_append_message(m_read, m, e, NULL, MUTT_CM_NO_FLAGS, CH_UPDATE_LEN) == 0)
786  {
787  mutt_set_flag(m, e, MUTT_DELETE, true);
788  mutt_set_flag(m, e, MUTT_PURGE, true);
789  }
790  else
791  {
792  mx_mbox_close(m_read);
793  goto cleanup;
794  }
795  }
796  }
797 
798  mx_mbox_close(m_read);
799  }
800  }
801  else if (!m->changed && (m->msg_deleted == 0))
802  {
803  if (m->verbose)
804  mutt_message(_("Mailbox is unchanged"));
805  if ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF))
806  mbox_reset_atime(m, NULL);
808  rc = MX_STATUS_OK;
809  goto cleanup;
810  }
811 
812  /* copy mails to the trash before expunging */
813  const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
814  const struct Mailbox *m_trash = mx_mbox_find(m->account, c_trash);
815  if (purge && (m->msg_deleted != 0) && (m != m_trash))
816  {
817  if (trash_append(m) != 0)
818  goto cleanup;
819  }
820 
821 #ifdef USE_IMAP
822  /* allow IMAP to preserve the deleted flag across sessions */
823  if (m->type == MUTT_IMAP)
824  {
825  const enum MxStatus check = imap_sync_mailbox(m, (purge != MUTT_NO), true);
826  if (check == MX_STATUS_ERROR)
827  {
828  rc = check;
829  goto cleanup;
830  }
831  }
832  else
833 #endif
834  {
835  if (purge == MUTT_NO)
836  {
837  for (i = 0; i < m->msg_count; i++)
838  {
839  struct Email *e = m->emails[i];
840  if (!e)
841  break;
842 
843  e->deleted = false;
844  e->purge = false;
845  }
846  m->msg_deleted = 0;
847  }
848 
849  if (m->changed || (m->msg_deleted != 0))
850  {
851  enum MxStatus check = sync_mailbox(m);
852  if (check != MX_STATUS_OK)
853  {
854  rc = check;
855  goto cleanup;
856  }
857  }
858  }
859 
860  if (m->verbose)
861  {
862  if (move_messages)
863  {
864  mutt_message(_("%d kept, %d moved, %d deleted"),
865  m->msg_count - m->msg_deleted, read_msgs, m->msg_deleted);
866  }
867  else
868  mutt_message(_("%d kept, %d deleted"), m->msg_count - m->msg_deleted, m->msg_deleted);
869  }
870 
871  const bool c_save_empty = cs_subset_bool(NeoMutt->sub, "save_empty");
872  if ((m->msg_count == m->msg_deleted) &&
873  ((m->type == MUTT_MMDF) || (m->type == MUTT_MBOX)) &&
874  !mutt_is_spool(mailbox_path(m)) && !c_save_empty)
875  {
877  }
878 
879 #ifdef USE_SIDEBAR
880  if ((purge == MUTT_YES) && (m->msg_deleted != 0))
881  {
882  for (i = 0; i < m->msg_count; i++)
883  {
884  struct Email *e = m->emails[i];
885  if (!e)
886  break;
887  if (e->deleted && !e->read)
888  {
889  m->msg_unread--;
890  if (!e->old)
891  m->msg_new--;
892  }
893  if (e->deleted && e->flagged)
894  m->msg_flagged--;
895  }
896  }
897 #endif
898 
900 
901  rc = MX_STATUS_OK;
902 
903 cleanup:
906  return rc;
907 }
908 
917 {
918  if (!m)
919  return MX_STATUS_ERROR;
920 
921  enum MxStatus rc = MX_STATUS_OK;
922  int purge = 1;
923  int msgcount, deleted;
924 
925  if (m->dontwrite)
926  {
927  char buf[256], tmp[256];
928  if (km_expand_key(buf, sizeof(buf), km_find_func(MENU_MAIN, OP_TOGGLE_WRITE)))
929  snprintf(tmp, sizeof(tmp), _(" Press '%s' to toggle write"), buf);
930  else
931  mutt_str_copy(tmp, _("Use 'toggle-write' to re-enable write"), sizeof(tmp));
932 
933  mutt_error(_("Mailbox is marked unwritable. %s"), tmp);
934  return MX_STATUS_ERROR;
935  }
936  else if (m->readonly)
937  {
938  mutt_error(_("Mailbox is read-only"));
939  return MX_STATUS_ERROR;
940  }
941 
942  if (!m->changed && (m->msg_deleted == 0))
943  {
944  if (m->verbose)
945  mutt_message(_("Mailbox is unchanged"));
946  return MX_STATUS_OK;
947  }
948 
949  if (m->msg_deleted != 0)
950  {
951  char buf[128];
952 
953  snprintf(buf, sizeof(buf),
954  ngettext("Purge %d deleted message?", "Purge %d deleted messages?", m->msg_deleted),
955  m->msg_deleted);
956  const enum QuadOption c_delete = cs_subset_quad(NeoMutt->sub, "delete");
957  purge = query_quadoption(c_delete, buf);
958  if (purge == MUTT_ABORT)
959  return MX_STATUS_ERROR;
960  if (purge == MUTT_NO)
961  {
962  if (!m->changed)
963  return MX_STATUS_OK; /* nothing to do! */
964  /* let IMAP servers hold on to D flags */
965  if (m->type != MUTT_IMAP)
966  {
967  for (int i = 0; i < m->msg_count; i++)
968  {
969  struct Email *e = m->emails[i];
970  if (!e)
971  break;
972  e->deleted = false;
973  e->purge = false;
974  }
975  m->msg_deleted = 0;
976  }
977  }
979  }
980 
981  /* really only for IMAP - imap_sync_mailbox results in a call to
982  * ctx_update_tables, so m->msg_deleted is 0 when it comes back */
983  msgcount = m->msg_count;
984  deleted = m->msg_deleted;
985 
986  const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
987  const struct Mailbox *m_trash = mx_mbox_find(m->account, c_trash);
988  if (purge && (m->msg_deleted != 0) && (m != m_trash))
989  {
990  if (trash_append(m) != 0)
991  return MX_STATUS_OK;
992  }
993 
994 #ifdef USE_IMAP
995  if (m->type == MUTT_IMAP)
996  rc = imap_sync_mailbox(m, purge, false);
997  else
998 #endif
999  rc = sync_mailbox(m);
1000  if (rc != MX_STATUS_ERROR)
1001  {
1002 #ifdef USE_IMAP
1003  if ((m->type == MUTT_IMAP) && !purge)
1004  {
1005  if (m->verbose)
1006  mutt_message(_("Mailbox checkpointed"));
1007  }
1008  else
1009 #endif
1010  {
1011  if (m->verbose)
1012  mutt_message(_("%d kept, %d deleted"), msgcount - deleted, deleted);
1013  }
1014 
1015  mutt_sleep(0);
1016 
1017  const bool c_save_empty = cs_subset_bool(NeoMutt->sub, "save_empty");
1018  if ((m->msg_count == m->msg_deleted) &&
1019  ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) &&
1020  !mutt_is_spool(mailbox_path(m)) && !c_save_empty)
1021  {
1022  unlink(mailbox_path(m));
1024  return MX_STATUS_OK;
1025  }
1026 
1027  /* if we haven't deleted any messages, we don't need to resort
1028  * ... except for certain folder formats which need "unsorted"
1029  * sort order in order to synchronize folders.
1030  *
1031  * MH and maildir are safe. mbox-style seems to need re-sorting,
1032  * at least with the new threading code. */
1033  if (purge || ((m->type != MUTT_MAILDIR) && (m->type != MUTT_MH)))
1034  {
1035  /* IMAP does this automatically after handling EXPUNGE */
1036  if (m->type != MUTT_IMAP)
1037  {
1040  }
1041  }
1042  }
1043 
1044  return rc;
1045 }
1046 
1054 struct Message *mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
1055 {
1056  if (!m)
1057  return NULL;
1058 
1059  struct Address *p = NULL;
1060  struct Message *msg = NULL;
1061 
1062  if (!m->mx_ops || !m->mx_ops->msg_open_new)
1063  {
1064  mutt_debug(LL_DEBUG1, "function unimplemented for mailbox type %d\n", m->type);
1065  return NULL;
1066  }
1067 
1068  msg = mutt_mem_calloc(1, sizeof(struct Message));
1069  msg->write = true;
1070 
1071  if (e)
1072  {
1073  msg->flags.flagged = e->flagged;
1074  msg->flags.replied = e->replied;
1075  msg->flags.read = e->read;
1076  msg->flags.draft = (flags & MUTT_SET_DRAFT);
1077  msg->received = e->received;
1078  }
1079 
1080  if (msg->received == 0)
1081  msg->received = mutt_date_epoch();
1082 
1083  if (m->mx_ops->msg_open_new(m, msg, e))
1084  {
1085  if (m->type == MUTT_MMDF)
1086  fputs(MMDF_SEP, msg->fp);
1087 
1088  if (((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) && (flags & MUTT_ADD_FROM))
1089  {
1090  if (e)
1091  {
1092  p = TAILQ_FIRST(&e->env->return_path);
1093  if (!p)
1094  p = TAILQ_FIRST(&e->env->sender);
1095  if (!p)
1096  p = TAILQ_FIRST(&e->env->from);
1097  }
1098 
1099  // Force a 'C' locale for the date, so that day/month names are in English
1100  locale_t loc = newlocale(LC_TIME_MASK, "C", 0);
1101  char buf[64] = { 0 };
1102  struct tm tm = mutt_date_localtime(msg->received);
1103  strftime_l(buf, sizeof(buf), "%a %b %e %H:%M:%S %Y", &tm, loc);
1104  freelocale(loc);
1105  fprintf(msg->fp, "From %s %s\n", p ? p->mailbox : NONULL(Username), buf);
1106  }
1107  }
1108  else
1109  FREE(&msg);
1110 
1111  return msg;
1112 }
1113 
1120 {
1121  if (!m || !m->mx_ops)
1122  return MX_STATUS_ERROR;
1123 
1124  enum MxStatus rc = m->mx_ops->mbox_check(m);
1125  if ((rc == MX_STATUS_NEW_MAIL) || (rc == MX_STATUS_REOPENED))
1126  {
1128  }
1129 
1130  return rc;
1131 }
1132 
1140 struct Message *mx_msg_open(struct Mailbox *m, int msgno)
1141 {
1142  if (!m || !m->emails || (msgno < 0) || (msgno >= m->msg_count))
1143  return NULL;
1144 
1145  if (!m->mx_ops || !m->mx_ops->msg_open)
1146  {
1147  mutt_debug(LL_DEBUG1, "function not implemented for mailbox type %d\n", m->type);
1148  return NULL;
1149  }
1150 
1151  struct Message *msg = mutt_mem_calloc(1, sizeof(struct Message));
1152  if (!m->mx_ops->msg_open(m, msg, msgno))
1153  FREE(&msg);
1154 
1155  return msg;
1156 }
1157 
1165 int mx_msg_commit(struct Mailbox *m, struct Message *msg)
1166 {
1167  if (!m || !m->mx_ops || !m->mx_ops->msg_commit || !msg)
1168  return -1;
1169 
1170  if (!(msg->write && m->append))
1171  {
1172  mutt_debug(LL_DEBUG1, "msg->write = %d, m->append = %d\n", msg->write, m->append);
1173  return -1;
1174  }
1175 
1176  return m->mx_ops->msg_commit(m, msg);
1177 }
1178 
1186 int mx_msg_close(struct Mailbox *m, struct Message **msg)
1187 {
1188  if (!m || !msg || !*msg)
1189  return 0;
1190 
1191  int rc = 0;
1192 
1193  if (m->mx_ops && m->mx_ops->msg_close)
1194  rc = m->mx_ops->msg_close(m, *msg);
1195 
1196  if ((*msg)->path)
1197  {
1198  mutt_debug(LL_DEBUG1, "unlinking %s\n", (*msg)->path);
1199  unlink((*msg)->path);
1200  FREE(&(*msg)->path);
1201  }
1202 
1203  FREE(&(*msg)->committed_path);
1204  FREE(msg);
1205  return rc;
1206 }
1207 
1212 void mx_alloc_memory(struct Mailbox *m)
1213 {
1214  size_t s = MAX(sizeof(struct Email *), sizeof(int));
1215 
1216  if ((m->email_max + 25) * s < m->email_max * s)
1217  {
1218  mutt_error(_("Out of memory"));
1219  mutt_exit(1);
1220  }
1221 
1222  m->email_max += 25;
1223  if (m->emails)
1224  {
1225  mutt_mem_realloc(&m->emails, sizeof(struct Email *) * m->email_max);
1226  mutt_mem_realloc(&m->v2r, sizeof(int) * m->email_max);
1227  }
1228  else
1229  {
1230  m->emails = mutt_mem_calloc(m->email_max, sizeof(struct Email *));
1231  m->v2r = mutt_mem_calloc(m->email_max, sizeof(int));
1232  }
1233  for (int i = m->email_max - 25; i < m->email_max; i++)
1234  {
1235  m->emails[i] = NULL;
1236  m->v2r[i] = -1;
1237  }
1238 }
1239 
1247 int mx_path_is_empty(const char *path)
1248 {
1249  if (!path || (*path == '\0'))
1250  return -1;
1251 
1252  enum MailboxType type = mx_path_probe(path);
1253  const struct MxOps *ops = mx_get_ops(type);
1254  if (!ops || !ops->path_is_empty)
1255  return -1;
1256 
1257  return ops->path_is_empty(path);
1258 }
1259 
1270 int mx_tags_edit(struct Mailbox *m, const char *tags, char *buf, size_t buflen)
1271 {
1272  if (!m || !buf)
1273  return -1;
1274 
1275  if (m->mx_ops->tags_edit)
1276  return m->mx_ops->tags_edit(m, tags, buf, buflen);
1277 
1278  mutt_message(_("Folder doesn't support tagging, aborting"));
1279  return -1;
1280 }
1281 
1290 int mx_tags_commit(struct Mailbox *m, struct Email *e, char *tags)
1291 {
1292  if (!m || !e || !tags)
1293  return -1;
1294 
1295  if (m->mx_ops->tags_commit)
1296  return m->mx_ops->tags_commit(m, e, tags);
1297 
1298  mutt_message(_("Folder doesn't support tagging, aborting"));
1299  return -1;
1300 }
1301 
1308 {
1309  return m && m->mx_ops->tags_commit && m->mx_ops->tags_edit;
1310 }
1311 
1317 enum MailboxType mx_path_probe(const char *path)
1318 {
1319  if (!path)
1320  return MUTT_UNKNOWN;
1321 
1322  enum MailboxType rc = MUTT_UNKNOWN;
1323 
1324  // First, search the non-local Mailbox types (is_local == false)
1325  for (const struct MxOps **ops = mx_ops; *ops; ops++)
1326  {
1327  if ((*ops)->is_local)
1328  continue;
1329  rc = (*ops)->path_probe(path, NULL);
1330  if (rc != MUTT_UNKNOWN)
1331  return rc;
1332  }
1333 
1334  struct stat st = { 0 };
1335  if (stat(path, &st) != 0)
1336  {
1337  mutt_debug(LL_DEBUG1, "unable to stat %s: %s (errno %d)\n", path, strerror(errno), errno);
1338  return MUTT_UNKNOWN;
1339  }
1340 
1341  if (S_ISFIFO(st.st_mode))
1342  {
1343  mutt_error(_("Can't open %s: it is a pipe"), path);
1344  return MUTT_UNKNOWN;
1345  }
1346 
1347  // Next, search the local Mailbox types (is_local == true)
1348  for (const struct MxOps **ops = mx_ops; *ops; ops++)
1349  {
1350  if (!(*ops)->is_local)
1351  continue;
1352  rc = (*ops)->path_probe(path, &st);
1353  if (rc != MUTT_UNKNOWN)
1354  return rc;
1355  }
1356 
1357  return rc;
1358 }
1359 
1363 int mx_path_canon(char *buf, size_t buflen, const char *folder, enum MailboxType *type)
1364 {
1365  if (!buf)
1366  return -1;
1367 
1368  for (size_t i = 0; i < 3; i++)
1369  {
1370  /* Look for !! ! - < > or ^ followed by / or NUL */
1371  if ((buf[0] == '!') && (buf[1] == '!'))
1372  {
1373  if (((buf[2] == '/') || (buf[2] == '\0')))
1374  {
1375  mutt_str_inline_replace(buf, buflen, 2, LastFolder);
1376  }
1377  }
1378  else if ((buf[0] == '+') || (buf[0] == '='))
1379  {
1380  size_t folder_len = mutt_str_len(folder);
1381  if ((folder_len > 0) && (folder[folder_len - 1] != '/'))
1382  {
1383  buf[0] = '/';
1384  mutt_str_inline_replace(buf, buflen, 0, folder);
1385  }
1386  else
1387  {
1388  mutt_str_inline_replace(buf, buflen, 1, folder);
1389  }
1390  }
1391  else if ((buf[1] == '/') || (buf[1] == '\0'))
1392  {
1393  if (buf[0] == '!')
1394  {
1395  const char *const c_spool_file =
1396  cs_subset_string(NeoMutt->sub, "spool_file");
1397  mutt_str_inline_replace(buf, buflen, 1, c_spool_file);
1398  }
1399  else if (buf[0] == '-')
1400  {
1401  mutt_str_inline_replace(buf, buflen, 1, LastFolder);
1402  }
1403  else if (buf[0] == '<')
1404  {
1405  const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
1406  mutt_str_inline_replace(buf, buflen, 1, c_record);
1407  }
1408  else if (buf[0] == '>')
1409  {
1410  const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
1411  mutt_str_inline_replace(buf, buflen, 1, c_mbox);
1412  }
1413  else if (buf[0] == '^')
1414  {
1415  mutt_str_inline_replace(buf, buflen, 1, CurrentFolder);
1416  }
1417  else if (buf[0] == '~')
1418  {
1419  mutt_str_inline_replace(buf, buflen, 1, HomeDir);
1420  }
1421  }
1422  else if (buf[0] == '@')
1423  {
1424  /* elm compatibility, @ expands alias to user name */
1425  struct AddressList *al = alias_lookup(buf + 1);
1426  if (!al || TAILQ_EMPTY(al))
1427  break;
1428 
1429  struct Email *e = email_new();
1430  e->env = mutt_env_new();
1431  mutt_addrlist_copy(&e->env->from, al, false);
1432  mutt_addrlist_copy(&e->env->to, al, false);
1433  mutt_default_save(buf, buflen, e);
1434  email_free(&e);
1435  break;
1436  }
1437  else
1438  {
1439  break;
1440  }
1441  }
1442 
1443  // if (!folder) //XXX - use inherited version, or pass NULL to backend?
1444  // return -1;
1445 
1446  enum MailboxType type2 = mx_path_probe(buf);
1447  if (type)
1448  *type = type2;
1449  const struct MxOps *ops = mx_get_ops(type2);
1450  if (!ops || !ops->path_canon)
1451  return -1;
1452 
1453  if (ops->path_canon(buf, buflen) < 0)
1454  {
1455  mutt_path_canon(buf, buflen, HomeDir, true);
1456  }
1457 
1458  return 0;
1459 }
1460 
1468 int mx_path_canon2(struct Mailbox *m, const char *folder)
1469 {
1470  if (!m)
1471  return -1;
1472 
1473  char buf[PATH_MAX];
1474 
1475  if (m->realpath)
1476  mutt_str_copy(buf, m->realpath, sizeof(buf));
1477  else
1478  mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
1479 
1480  int rc = mx_path_canon(buf, sizeof(buf), folder, &m->type);
1481 
1482  mutt_str_replace(&m->realpath, buf);
1483 
1484  if (rc >= 0)
1485  {
1486  m->mx_ops = mx_get_ops(m->type);
1488  }
1489 
1490  return rc;
1491 }
1492 
1496 int mx_path_pretty(char *buf, size_t buflen, const char *folder)
1497 {
1498  if (!buf)
1499  return -1;
1500 
1501  enum MailboxType type = mx_path_probe(buf);
1502  const struct MxOps *ops = mx_get_ops(type);
1503  if (!ops)
1504  return -1;
1505 
1506  if (!ops->path_canon)
1507  return -1;
1508 
1509  if (ops->path_canon(buf, buflen) < 0)
1510  return -1;
1511 
1512  if (!ops->path_pretty)
1513  return -1;
1514 
1515  if (ops->path_pretty(buf, buflen, folder) < 0)
1516  return -1;
1517 
1518  return 0;
1519 }
1520 
1524 int mx_path_parent(char *buf, size_t buflen)
1525 {
1526  if (!buf)
1527  return -1;
1528 
1529  return 0;
1530 }
1531 
1541 {
1542  if (!m || !m->mx_ops || !m->mx_ops->msg_padding_size)
1543  return 0;
1544 
1545  return m->mx_ops->msg_padding_size(m);
1546 }
1547 
1554 struct Account *mx_ac_find(struct Mailbox *m)
1555 {
1556  if (!m || !m->mx_ops || !m->realpath)
1557  return NULL;
1558 
1559  struct Account *np = NULL;
1560  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1561  {
1562  if (np->type != m->type)
1563  continue;
1564 
1565  if (m->mx_ops->ac_owns_path(np, m->realpath))
1566  return np;
1567  }
1568 
1569  return NULL;
1570 }
1571 
1578 struct Mailbox *mx_mbox_find(struct Account *a, const char *path)
1579 {
1580  if (!a || !path)
1581  return NULL;
1582 
1583  struct MailboxNode *np = NULL;
1584  struct Url *url_p = NULL;
1585  struct Url *url_a = NULL;
1586 
1587  const bool use_url = (a->type == MUTT_IMAP);
1588  if (use_url)
1589  {
1590  url_p = url_parse(path);
1591  if (!url_p)
1592  goto done;
1593  }
1594 
1595  STAILQ_FOREACH(np, &a->mailboxes, entries)
1596  {
1597  if (!use_url)
1598  {
1599  if (mutt_str_equal(np->mailbox->realpath, path))
1600  return np->mailbox;
1601  continue;
1602  }
1603 
1604  url_free(&url_a);
1605  url_a = url_parse(np->mailbox->realpath);
1606  if (!url_a)
1607  continue;
1608 
1609  if (!mutt_istr_equal(url_a->host, url_p->host))
1610  continue;
1611  if (url_p->user && !mutt_istr_equal(url_a->user, url_p->user))
1612  continue;
1613  if (a->type == MUTT_IMAP)
1614  {
1615  if (imap_mxcmp(url_a->path, url_p->path) == 0)
1616  break;
1617  }
1618  else
1619  {
1620  if (mutt_str_equal(url_a->path, url_p->path))
1621  break;
1622  }
1623  }
1624 
1625 done:
1626  url_free(&url_p);
1627  url_free(&url_a);
1628 
1629  if (!np)
1630  return NULL;
1631  return np->mailbox;
1632 }
1633 
1640 struct Mailbox *mx_mbox_find2(const char *path)
1641 {
1642  if (!path)
1643  return NULL;
1644 
1645  char buf[PATH_MAX];
1646  mutt_str_copy(buf, path, sizeof(buf));
1647  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1648  mx_path_canon(buf, sizeof(buf), c_folder, NULL);
1649 
1650  struct Account *np = NULL;
1651  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1652  {
1653  struct Mailbox *m = mx_mbox_find(np, buf);
1654  if (m)
1655  return m;
1656  }
1657 
1658  return NULL;
1659 }
1660 
1668 struct Mailbox *mx_path_resolve(const char *path)
1669 {
1670  if (!path)
1671  return NULL;
1672 
1673  struct Mailbox *m = mx_mbox_find2(path);
1674  if (m)
1675  return m;
1676 
1677  m = mailbox_new();
1678  m->flags = MB_HIDDEN;
1679  mutt_buffer_strcpy(&m->pathbuf, path);
1680  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1681  mx_path_canon2(m, c_folder);
1682 
1683  return m;
1684 }
1685 
1692 static struct Mailbox *mx_mbox_find_by_name_ac(struct Account *a, const char *name)
1693 {
1694  if (!a || !name)
1695  return NULL;
1696 
1697  struct MailboxNode *np = NULL;
1698 
1699  STAILQ_FOREACH(np, &a->mailboxes, entries)
1700  {
1701  if (mutt_str_equal(np->mailbox->name, name))
1702  return np->mailbox;
1703  }
1704 
1705  return NULL;
1706 }
1707 
1713 static struct Mailbox *mx_mbox_find_by_name(const char *name)
1714 {
1715  if (!name)
1716  return NULL;
1717 
1718  struct Account *np = NULL;
1719  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1720  {
1721  struct Mailbox *m = mx_mbox_find_by_name_ac(np, name);
1722  if (m)
1723  return m;
1724  }
1725 
1726  return NULL;
1727 }
1728 
1738 struct Mailbox *mx_resolve(const char *path_or_name)
1739 {
1740  if (!path_or_name)
1741  return NULL;
1742 
1743  // Order is name first because you can create a Mailbox from
1744  // a path, but can't from a name. So fallback behavior creates
1745  // a new Mailbox for us.
1746  struct Mailbox *m = mx_mbox_find_by_name(path_or_name);
1747  if (!m)
1748  m = mx_path_resolve(path_or_name);
1749 
1750  return m;
1751 }
1752 
1756 bool mx_ac_add(struct Account *a, struct Mailbox *m)
1757 {
1758  if (!a || !m || !m->mx_ops || !m->mx_ops->ac_add)
1759  return false;
1760 
1761  return m->mx_ops->ac_add(a, m) && account_mailbox_add(a, m);
1762 }
1763 
1772 int mx_ac_remove(struct Mailbox *m)
1773 {
1774  if (!m || !m->account)
1775  return -1;
1776 
1777  struct Account *a = m->account;
1779  if (STAILQ_EMPTY(&a->mailboxes))
1780  {
1782  }
1783  return 0;
1784 }
1785 
1789 enum MxStatus mx_mbox_check_stats(struct Mailbox *m, uint8_t flags)
1790 {
1791  if (!m)
1792  return MX_STATUS_ERROR;
1793 
1794  return m->mx_ops->mbox_check_stats(m, flags);
1795 }
1796 
1806 int mx_save_hcache(struct Mailbox *m, struct Email *e)
1807 {
1808  if (!m || !m->mx_ops || !m->mx_ops->msg_save_hcache || !e)
1809  return 0;
1810 
1811  return m->mx_ops->msg_save_hcache(m, e);
1812 }
1813 
1819 enum MailboxType mx_type(struct Mailbox *m)
1820 {
1821  return m ? m->type : MUTT_MAILBOX_ERROR;
1822 }
1823 
1830 int mx_toggle_write(struct Mailbox *m)
1831 {
1832  if (!m)
1833  return -1;
1834 
1835  if (m->readonly)
1836  {
1837  mutt_error(_("Can't toggle write on a readonly mailbox"));
1838  return -1;
1839  }
1840 
1841  if (m->dontwrite)
1842  {
1843  m->dontwrite = false;
1844  mutt_message(_("Changes to folder will be written on folder exit"));
1845  }
1846  else
1847  {
1848  m->dontwrite = true;
1849  mutt_message(_("Changes to folder will not be written"));
1850  }
1851 
1852  return 0;
1853 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
int mx_path_is_empty(const char *path)
Is the mailbox empty.
Definition: mx.c:1247
struct MxOps MxPopOps
POP Mailbox - Implements MxOps -.
Definition: pop.c:1206
struct Keymap * km_find_func(enum MenuType mtype, int func)
Find a function&#39;s mapping in a Menu.
Definition: keymap.c:946
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
An enumeration.
Definition: enum.h:29
int(* msg_commit)(struct Mailbox *m, struct Message *msg)
Definition: mxapi.h:271
const struct MxOps * mx_get_ops(enum MailboxType type)
Get mailbox operations.
Definition: mx.c:141
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:73
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:304
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)
Definition: mxapi.h:238
#define TAILQ_FIRST(head)
Definition: queue.h:723
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
Clear the &#39;last-tagged&#39; pointer.
Definition: mailbox.h:184
struct MxOps MxNntpOps
NNTP Mailbox - Implements MxOps -.
Definition: nntp.c:2750
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
Update internal tables.
Definition: mailbox.h:183
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:1468
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:52
Structs that make up an email.
#define mutt_error(...)
Definition: logging.h:88
void mbox_reset_atime(struct Mailbox *m, struct stat *st)
Reset the access time on the mailbox file.
Definition: mbox.c:842
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
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:1496
struct HashTable * label_hash
Hash Table for x-labels.
Definition: mailbox.h:129
int mx_path_parent(char *buf, size_t buflen)
Find the parent of a mailbox path - Wrapper for MxOps::path_parent()
Definition: mx.c:1524
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:449
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:1713
static int trash_append(struct Mailbox *m)
move deleted mails to the trash folder
Definition: mx.c:502
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:1534
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:923
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 MxOps MxMhOps
MH Mailbox - Implements MxOps -.
Definition: mh.c:1248
struct MailboxList mailboxes
List of Mailboxes.
Definition: account.h:41
A group of associated Mailboxes.
Definition: account.h:36
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:1789
void mx_alloc_memory(struct Mailbox *m)
Create storage for the emails.
Definition: mx.c:1212
#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:916
An email address.
Definition: address.h:35
struct Mailbox * mx_mbox_find(struct Account *a, const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1578
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:1692
struct MxOps MxCompOps
Compressed Mailbox - Implements MxOps -Compress only uses open, close and check.
Definition: compress.c:932
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)
Definition: mxapi.h:123
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:62
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:138
int(* path_is_empty)(const char *path)
Definition: mxapi.h:428
#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:180
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:610
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:1806
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1640
WHERE bool OptNeedRescore
(pseudo) set when the &#39;score&#39; command is used
Definition: options.h:41
struct Account * mx_ac_find(struct Mailbox *m)
Find the Account owning a Mailbox.
Definition: mx.c:1554
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
#define mutt_perror(...)
Definition: logging.h:89
Container for Accounts, Notifications.
Definition: neomutt.h:36
struct MxOps MxMmdfOps
MMDF Mailbox - Implements MxOps -.
Definition: mbox.c:1861
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:1423
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:1643
Email Address Handling.
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
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:305
enum MxStatus mx_mbox_check(struct Mailbox *m)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1119
int(* path_canon)(char *buf, size_t buflen)
Definition: mxapi.h:382
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1186
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:1054
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:471
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:87
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:282
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:1738
struct Envelope * env
Envelope information.
Definition: email.h:90
Convenience wrapper for the core headers.
struct MxOps MxImapOps
IMAP Mailbox - Implements MxOps -.
Definition: imap.c:2489
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:1290
void mx_fastclose_mailbox(struct Mailbox *m)
free up memory associated with the Mailbox
Definition: mx.c:429
char * group
Definition: mdata.h:34
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2402
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:347
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)
Definition: mxapi.h:300
void * mdata
Driver specific data.
Definition: mailbox.h:136
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:105
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:916
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
Old messages.
Definition: mutt.h:90
Email list needs resorting.
Definition: mailbox.h:181
WHERE bool OptForceRefresh
(pseudo) refresh even during macros
Definition: options.h:36
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)
Definition: mxapi.h:335
bool flagged
Definition: mxapi.h:50
enum MxOpenReturns(* mbox_open)(struct Mailbox *m)
Definition: mxapi.h:152
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:474
Messages to be deleted.
Definition: mutt.h:94
A mailbox.
Definition: mailbox.h:81
enum MxStatus(* mbox_sync)(struct Mailbox *m)
Definition: mxapi.h:207
#define PATH_MAX
Definition: mutt.h:40
enum MxStatus(* mbox_check)(struct Mailbox *m)
Definition: mxapi.h:180
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:918
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)
Definition: mxapi.h:316
#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:317
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
Ask the user a question.
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)
Definition: mxapi.h:194
#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:1270
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:64
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:97
Index panel (list of emails)
Definition: type.h:50
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:352
struct Account * account_new(const char *name, struct ConfigSubset *sub)
Create a new Account.
Definition: account.c:42
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
int emaillist_add_email(struct EmailList *el, struct Email *e)
Add an Email to a list.
Definition: email.c:159
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:218
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
struct MxOps MxMaildirOps
Maildir Mailbox - Implements MxOps -.
Definition: maildir.c:1648
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:279
bool mx_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Wrapper for MxOps::ac_add()
Definition: mx.c:1756
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
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
struct Mailbox * mailbox_new(void)
Create a new Mailbox.
Definition: mailbox.c:68
struct MxOps MxNotmuchOps
Notmuch Mailbox - Implements MxOps -.
Definition: notmuch.c:2496
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1317
bool(* msg_open_new)(struct Mailbox *m, struct Message *msg, const struct Email *e)
Definition: mxapi.h:255
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:322
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:749
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)
Definition: mxapi.h:398
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:1165
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)
Definition: mxapi.h:167
bool account_mailbox_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account.
Definition: account.c:65
#define mutt_message(...)
Definition: logging.h:87
unsigned char cs_subset_enum(const struct ConfigSubset *sub, const char *name)
Get a enumeration config item by name.
Definition: helpers.c:97
#define FREE(x)
Definition: memory.h:40
int(* msg_close)(struct Mailbox *m, struct Message *msg)
Definition: mxapi.h:287
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:95
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1668
enum MxStatus(* mbox_close)(struct Mailbox *m)
Definition: mxapi.h:220
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:184
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:267
enum MailboxType mx_type(struct Mailbox *m)
Return the type of the Mailbox.
Definition: mx.c:1819
#define STAILQ_EMPTY(head)
Definition: queue.h:348
time_t received
the time at which this message was received
Definition: mxapi.h:54
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
bool(* ac_add)(struct Account *a, struct Mailbox *m)
Definition: mxapi.h:139
bool neomutt_account_remove(struct NeoMutt *n, struct Account *a)
Remove an Account from the global list.
Definition: neomutt.c:106
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:53
List of Mailboxes.
Definition: mailbox.h:156
bool changed
Mailbox has been modified.
Definition: mailbox.h:114
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
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:1540
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:1046
bool mx_tags_is_supported(struct Mailbox *m)
return true if mailbox support tagging
Definition: mx.c:1307
#define TAILQ_EMPTY(head)
Definition: queue.h:721
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:1772
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition: newsrc.c:1308
int mx_toggle_write(struct Mailbox *m)
Toggle the mailbox&#39;s readonly flag.
Definition: mx.c:1830
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:201
#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:1363
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:208
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:155
Mailbox helper functions.
struct MxOps MxMboxOps
Mbox Mailbox - Implements MxOps -.
Definition: mbox.c:1831
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1140
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:359
Definition: mxapi.h:103
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:158
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)
Definition: mxapi.h:353