NeoMutt  2018-07-16 +2481-68dcde
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 <stdbool.h>
36 #include <string.h>
37 #include <sys/stat.h>
38 #include <time.h>
39 #include <unistd.h>
40 #include "mutt/mutt.h"
41 #include "address/lib.h"
42 #include "email/lib.h"
43 #include "core/lib.h"
44 #include "mutt.h"
45 #include "mx.h"
46 #include "alias.h"
47 #include "context.h"
48 #include "copy.h"
49 #include "globals.h"
50 #include "hook.h"
51 #include "keymap.h"
52 #include "maildir/lib.h"
53 #include "mbox/mbox.h"
54 #include "mutt_header.h"
55 #include "mutt_logging.h"
56 #include "mutt_mailbox.h"
57 #include "muttlib.h"
58 #include "opcodes.h"
59 #include "options.h"
60 #include "protos.h"
61 #include "sort.h"
62 #ifdef USE_COMPRESSED
63 #include "compress.h"
64 #endif
65 #ifdef USE_IMAP
66 #include "imap/imap.h"
67 #endif
68 #ifdef USE_POP
69 #include "pop/pop.h"
70 #endif
71 #ifdef USE_NNTP
72 #include "nntp/nntp.h"
73 #endif
74 #ifdef USE_NOTMUCH
75 #include "notmuch/mutt_notmuch.h"
76 #endif
77 #ifdef ENABLE_NLS
78 #include <libintl.h>
79 #endif
80 
81 /* These Config Variables are only used in mx.c */
82 unsigned char C_CatchupNewsgroup;
84 unsigned char C_MboxType;
85 unsigned char C_Move;
86 char *C_Trash;
87 
88 // clang-format off
89 static struct Mapping MagicMap[] = {
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 MagicDef = {
99  "mbox_type",
100  4,
101  (struct Mapping *) &MagicMap,
102 };
103 
107 static 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_COMPRESSED
130  &MxCompOps,
131 #endif
132  NULL,
133 };
134 
141 const struct MxOps *mx_get_ops(enum MailboxType magic)
142 {
143  for (const struct MxOps **ops = mx_ops; *ops; ops++)
144  if ((*ops)->magic == magic)
145  return *ops;
146 
147  return NULL;
148 }
149 
155 static bool mutt_is_spool(const char *str)
156 {
157  return mutt_str_strcmp(C_Spoolfile, str) == 0;
158 }
159 
170 int mx_access(const char *path, int flags)
171 {
172 #ifdef USE_IMAP
173  if (imap_path_probe(path, NULL) == MUTT_IMAP)
174  return imap_access(path);
175 #endif
176 
177  return access(path, flags);
178 }
179 
187 static int mx_open_mailbox_append(struct Mailbox *m, OpenMailboxFlags flags)
188 {
189  if (!m)
190  return -1;
191 
192  struct stat sb;
193 
194  m->append = true;
195  if ((m->magic == MUTT_UNKNOWN) || (m->magic == MUTT_MAILBOX_ERROR))
196  {
197  m->magic = mx_path_probe(mailbox_path(m), NULL);
198 
199  if (m->magic == MUTT_UNKNOWN)
200  {
201  if (flags & (MUTT_APPEND | MUTT_NEWFOLDER))
202  {
204  }
205  else
206  {
207  mutt_error(_("%s is not a mailbox"), mailbox_path(m));
208  return -1;
209  }
210  }
211 
212  if (m->magic == MUTT_MAILBOX_ERROR)
213  {
214  if (stat(mailbox_path(m), &sb) == -1)
215  {
216  if (errno == ENOENT)
217  {
218 #ifdef USE_COMPRESSED
219  if (mutt_comp_can_append(m))
220  m->magic = MUTT_COMPRESSED;
221  else
222 #endif
223  m->magic = C_MboxType;
224  flags |= MUTT_APPENDNEW;
225  }
226  else
227  {
229  return -1;
230  }
231  }
232  else
233  return -1;
234  }
235 
236  m->mx_ops = mx_get_ops(m->magic);
237  }
238 
239  if (!m->mx_ops || !m->mx_ops->mbox_open_append)
240  return -1;
241 
242  int rc = m->mx_ops->mbox_open_append(m, flags);
243  m->opened++;
244  return rc;
245 }
246 
254 struct Context *mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
255 {
256  if (!m)
257  return NULL;
258 
259  struct Context *ctx = ctx_new();
260  ctx->mailbox = m;
261 
262  struct EventContext ev_ctx = { ctx };
263  notify_send(ctx->notify, NT_CONTEXT, NT_CONTEXT_OPEN, IP & ev_ctx);
264 
265  // If the Mailbox is closed, Context->mailbox must be set to NULL
267 
268  if ((m->magic == MUTT_UNKNOWN) && (flags & (MUTT_NEWFOLDER | MUTT_APPEND)))
269  {
270  m->magic = C_MboxType;
271  m->mx_ops = mx_get_ops(m->magic);
272  }
273 
274  if (!m->account)
275  {
276  struct Account *a = mx_ac_find(m);
277  bool new_account = false;
278  if (!a)
279  {
280  a = account_new(NULL, NeoMutt->sub);
281  a->magic = m->magic;
282  new_account = true;
283  }
284  if (mx_ac_add(a, m) < 0)
285  {
286  ctx_free(&ctx);
287  if (new_account)
288  {
289  FREE(&a);
290  }
291  return NULL;
292  }
293  if (new_account)
294  {
296  }
297  }
298 
299  ctx->msg_not_read_yet = -1;
300  ctx->collapsed = false;
301 
302  m->size = 0;
303  m->msg_unread = 0;
304  m->msg_flagged = 0;
305  m->rights = MUTT_ACL_ALL;
306 
307  if (flags & MUTT_QUIET)
308  m->quiet = true;
309  if (flags & MUTT_READONLY)
310  m->readonly = true;
311  if (flags & MUTT_PEEK)
312  m->peekonly = true;
313 
314  if (flags & (MUTT_APPEND | MUTT_NEWFOLDER))
315  {
316  if (mx_open_mailbox_append(ctx->mailbox, flags) != 0)
317  {
319  ctx_free(&ctx);
320  return NULL;
321  }
322  return ctx;
323  }
324 
325  if (m->magic == MUTT_UNKNOWN)
326  {
327  m->magic = mx_path_probe(mailbox_path(m), NULL);
328  m->mx_ops = mx_get_ops(m->magic);
329  }
330 
331  if ((m->magic == MUTT_UNKNOWN) || (m->magic == MUTT_MAILBOX_ERROR) || !m->mx_ops)
332  {
333  if (m->magic == MUTT_MAILBOX_ERROR)
335  else if ((m->magic == MUTT_UNKNOWN) || !m->mx_ops)
336  mutt_error(_("%s is not a mailbox"), mailbox_path(m));
337 
339  ctx_free(&ctx);
340  return NULL;
341  }
342 
344 
345  /* if the user has a 'push' command in their .neomuttrc, or in a folder-hook,
346  * it will cause the progress messages not to be displayed because
347  * mutt_refresh() will think we are in the middle of a macro. so set a
348  * flag to indicate that we should really refresh the screen. */
349  OptForceRefresh = true;
350 
351  if (!m->quiet)
352  mutt_message(_("Reading %s..."), mailbox_path(m));
353 
354  int rc = m->mx_ops->mbox_open(ctx->mailbox);
355  m->opened++;
356  if (rc == 0)
357  ctx_update(ctx);
358 
359  if ((rc == 0) || (rc == -2))
360  {
361  if ((flags & MUTT_NOSORT) == 0)
362  {
363  /* avoid unnecessary work since the mailbox is completely unthreaded
364  * to begin with */
365  OptSortSubthreads = false;
366  OptNeedRescore = false;
367  }
368  if (!m->quiet)
370  if (rc == -2)
371  {
372  mutt_error(_("Reading from %s interrupted..."), mailbox_path(m));
373  mutt_sort_headers(ctx, true);
374  }
375  }
376  else
377  {
379  ctx_free(&ctx);
380  return NULL;
381  }
382 
383  OptForceRefresh = false;
384 
385  return ctx;
386 }
387 
393 {
394  if (!m)
395  return;
396 
397  m->opened--;
398  if (m->opened != 0)
399  return;
400 
401  /* never announce that a mailbox we've just left has new mail. #3290
402  * TODO: really belongs in mx_mbox_close, but this is a nice hook point */
403  if (!m->peekonly)
405 
406  if (m->mx_ops)
407  m->mx_ops->mbox_close(m);
408 
410 
412  mutt_hash_free(&m->id_hash);
414 
415  if (m->emails)
416  {
417  for (int i = 0; i < m->msg_count; i++)
418  email_free(&m->emails[i]);
419  FREE(&m->emails);
420  }
421  FREE(&m->v2r);
422 }
423 
431 static int sync_mailbox(struct Mailbox *m, int *index_hint)
432 {
433  if (!m || !m->mx_ops || !m->mx_ops->mbox_sync)
434  return -1;
435 
436  if (!m->quiet)
437  {
438  /* L10N: Displayed before/as a mailbox is being synced */
439  mutt_message(_("Writing %s..."), mailbox_path(m));
440  }
441 
442  int rc = m->mx_ops->mbox_sync(m, index_hint);
443  if ((rc != 0) && !m->quiet)
444  {
445  /* L10N: Displayed if a mailbox sync fails */
446  mutt_error(_("Unable to write %s"), mailbox_path(m));
447  }
448 
449  return rc;
450 }
451 
458 static int trash_append(struct Mailbox *m)
459 {
460  if (!m)
461  return -1;
462 
463  struct stat st, stc;
464  int opt_confappend, rc;
465 
466  if (!C_Trash || (m->msg_deleted == 0) || ((m->magic == MUTT_MAILDIR) && C_MaildirTrash))
467  {
468  return 0;
469  }
470 
471  int delmsgcount = 0;
472  int first_del = -1;
473  for (int i = 0; i < m->msg_count; i++)
474  {
475  if (m->emails[i]->deleted && (!m->emails[i]->purge))
476  {
477  if (first_del < 0)
478  first_del = i;
479  delmsgcount++;
480  }
481  }
482 
483  if (delmsgcount == 0)
484  return 0; /* nothing to be done */
485 
486  /* avoid the "append messages" prompt */
487  opt_confappend = C_Confirmappend;
488  if (opt_confappend)
489  C_Confirmappend = false;
490  rc = mutt_save_confirm(C_Trash, &st);
491  if (opt_confappend)
492  C_Confirmappend = true;
493  if (rc != 0)
494  {
495  /* L10N: Although we know the precise number of messages, we do not show it to the user.
496  So feel free to use a "generic plural" as plural translation if your language has one. */
497  mutt_error(ngettext("message not deleted", "messages not deleted", delmsgcount));
498  return -1;
499  }
500 
501  if ((lstat(mailbox_path(m), &stc) == 0) && (stc.st_ino == st.st_ino) &&
502  (stc.st_dev == st.st_dev) && (stc.st_rdev == st.st_rdev))
503  {
504  return 0; /* we are in the trash folder: simple sync */
505  }
506 
507 #ifdef USE_IMAP
508  if ((m->magic == MUTT_IMAP) && (imap_path_probe(C_Trash, NULL) == MUTT_IMAP))
509  {
510  if (imap_fast_trash(m, C_Trash) == 0)
511  return 0;
512  }
513 #endif
514 
515  struct Mailbox *m_trash = mx_path_resolve(C_Trash);
516  struct Context *ctx_trash = mx_mbox_open(m_trash, MUTT_OPEN_NO_FLAGS);
517  if (ctx_trash)
518  {
519  bool old_append = m_trash->append;
520  m_trash->append = true;
521 
522  /* continue from initial scan above */
523  for (int i = first_del; i < m->msg_count; i++)
524  {
525  if (m->emails[i]->deleted && (!m->emails[i]->purge))
526  {
527  if (mutt_append_message(ctx_trash->mailbox, m, m->emails[i],
529  {
530  m_trash->append = old_append;
531  mx_mbox_close(&ctx_trash);
532  return -1;
533  }
534  }
535  }
536 
537  m_trash->append = old_append;
538  mx_mbox_close(&ctx_trash);
539  }
540  else
541  {
542  mutt_error(_("Can't open trash folder"));
543  mailbox_free(&m_trash);
544  return -1;
545  }
546 
547  return 0;
548 }
549 
558 int mx_mbox_close(struct Context **ptr)
559 {
560  if (!ptr || !*ptr)
561  return 0;
562 
563  struct Context *ctx = *ptr;
564  if (!ctx || !ctx->mailbox)
565  return -1;
566 
567  struct Mailbox *m = ctx->mailbox;
568 
569  int i, read_msgs = 0;
570  enum QuadOption move_messages = MUTT_NO;
571  enum QuadOption purge = MUTT_YES;
572  char mbox[PATH_MAX];
573  char buf[PATH_MAX + 64];
574 
575  if (m->readonly || m->dontwrite || m->append)
576  {
578  ctx_free(ptr);
579  return 0;
580  }
581 
582 #ifdef USE_NNTP
583  if ((m->msg_unread != 0) && (m->magic == MUTT_NNTP))
584  {
585  struct NntpMboxData *mdata = m->mdata;
586 
587  if (mdata && mdata->adata && mdata->group)
588  {
589  enum QuadOption ans =
590  query_quadoption(C_CatchupNewsgroup, _("Mark all articles read?"));
591  if (ans == MUTT_ABORT)
592  return -1;
593  else if (ans == MUTT_YES)
594  mutt_newsgroup_catchup(m, mdata->adata, mdata->group);
595  }
596  }
597 #endif
598 
599  for (i = 0; i < m->msg_count; i++)
600  {
601  if (!m->emails[i])
602  break;
603  if (!m->emails[i]->deleted && m->emails[i]->read && !(m->emails[i]->flagged && C_KeepFlagged))
604  {
605  read_msgs++;
606  }
607  }
608 
609 #ifdef USE_NNTP
610  /* don't need to move articles from newsgroup */
611  if (m->magic == MUTT_NNTP)
612  read_msgs = 0;
613 #endif
614 
615  if ((read_msgs != 0) && (C_Move != MUTT_NO))
616  {
617  bool is_spool;
619  if (p)
620  {
621  is_spool = true;
622  mutt_str_strfcpy(mbox, p, sizeof(mbox));
623  }
624  else
625  {
626  mutt_str_strfcpy(mbox, C_Mbox, sizeof(mbox));
627  is_spool = mutt_is_spool(mailbox_path(m)) && !mutt_is_spool(mbox);
628  }
629 
630  if (is_spool && (mbox[0] != '\0'))
631  {
632  mutt_expand_path(mbox, sizeof(mbox));
633  snprintf(buf, sizeof(buf),
634  /* L10N: The first argument is the number of read messages to be
635  moved, the second argument is the target mailbox. */
636  ngettext("Move %d read message to %s?", "Move %d read messages to %s?", read_msgs),
637  read_msgs, mbox);
638  move_messages = query_quadoption(C_Move, buf);
639  if (move_messages == MUTT_ABORT)
640  return -1;
641  }
642  }
643 
644  /* There is no point in asking whether or not to purge if we are
645  * just marking messages as "trash". */
646  if ((m->msg_deleted != 0) && !((m->magic == MUTT_MAILDIR) && C_MaildirTrash))
647  {
648  snprintf(buf, sizeof(buf),
649  ngettext("Purge %d deleted message?", "Purge %d deleted messages?", m->msg_deleted),
650  m->msg_deleted);
651  purge = query_quadoption(C_Delete, buf);
652  if (purge == MUTT_ABORT)
653  return -1;
654  }
655 
656  if (C_MarkOld)
657  {
658  for (i = 0; i < m->msg_count; i++)
659  {
660  if (!m->emails[i]->deleted && !m->emails[i]->old && !m->emails[i]->read)
661  mutt_set_flag(m, m->emails[i], MUTT_OLD, true);
662  }
663  }
664 
665  if (move_messages)
666  {
667  if (!m->quiet)
668  mutt_message(_("Moving read messages to %s..."), mbox);
669 
670 #ifdef USE_IMAP
671  /* try to use server-side copy first */
672  i = 1;
673 
674  if ((m->magic == MUTT_IMAP) && (imap_path_probe(mbox, NULL) == MUTT_IMAP))
675  {
676  /* tag messages for moving, and clear old tags, if any */
677  for (i = 0; i < m->msg_count; i++)
678  {
679  if (m->emails[i]->read && !m->emails[i]->deleted &&
680  !(m->emails[i]->flagged && C_KeepFlagged))
681  {
682  m->emails[i]->tagged = true;
683  }
684  else
685  {
686  m->emails[i]->tagged = false;
687  }
688  }
689 
690  i = imap_copy_messages(ctx->mailbox, NULL, mbox, true);
691  }
692 
693  if (i == 0) /* success */
695  else if (i == -1) /* horrible error, bail */
696  return -1;
697  else /* use regular append-copy mode */
698 #endif
699  {
700  struct Mailbox *m_read = mx_path_resolve(mbox);
701  struct Context *ctx_read = mx_mbox_open(m_read, MUTT_APPEND);
702  if (!ctx_read)
703  {
704  mailbox_free(&m_read);
705  return -1;
706  }
707 
708  for (i = 0; i < m->msg_count; i++)
709  {
710  if (m->emails[i]->read && !m->emails[i]->deleted &&
711  !(m->emails[i]->flagged && C_KeepFlagged))
712  {
713  if (mutt_append_message(ctx_read->mailbox, ctx->mailbox, m->emails[i],
715  {
716  mutt_set_flag(m, m->emails[i], MUTT_DELETE, true);
717  mutt_set_flag(m, m->emails[i], MUTT_PURGE, true);
718  }
719  else
720  {
721  mx_mbox_close(&ctx_read);
722  return -1;
723  }
724  }
725  }
726 
727  mx_mbox_close(&ctx_read);
728  }
729  }
730  else if (!m->changed && (m->msg_deleted == 0))
731  {
732  if (!m->quiet)
733  mutt_message(_("Mailbox is unchanged"));
734  if ((m->magic == MUTT_MBOX) || (m->magic == MUTT_MMDF))
735  mbox_reset_atime(m, NULL);
737  ctx_free(ptr);
738  return 0;
739  }
740 
741  /* copy mails to the trash before expunging */
742  if (purge && (m->msg_deleted != 0) && (mutt_str_strcmp(mailbox_path(m), C_Trash) != 0))
743  {
744  if (trash_append(ctx->mailbox) != 0)
745  return -1;
746  }
747 
748 #ifdef USE_IMAP
749  /* allow IMAP to preserve the deleted flag across sessions */
750  if (m->magic == MUTT_IMAP)
751  {
752  int check = imap_sync_mailbox(ctx->mailbox, (purge != MUTT_NO), true);
753  if (check != 0)
754  return check;
755  }
756  else
757 #endif
758  {
759  if (purge == MUTT_NO)
760  {
761  for (i = 0; i < m->msg_count; i++)
762  {
763  m->emails[i]->deleted = false;
764  m->emails[i]->purge = false;
765  }
766  m->msg_deleted = 0;
767  }
768 
769  if (m->changed || (m->msg_deleted != 0))
770  {
771  int check = sync_mailbox(ctx->mailbox, NULL);
772  if (check != 0)
773  return check;
774  }
775  }
776 
777  if (!m->quiet)
778  {
779  if (move_messages)
780  {
781  mutt_message(_("%d kept, %d moved, %d deleted"),
782  m->msg_count - m->msg_deleted, read_msgs, m->msg_deleted);
783  }
784  else
785  mutt_message(_("%d kept, %d deleted"), m->msg_count - m->msg_deleted, m->msg_deleted);
786  }
787 
788  if ((m->msg_count == m->msg_deleted) &&
789  ((m->magic == MUTT_MMDF) || (m->magic == MUTT_MBOX)) &&
791  {
793  }
794 
795 #ifdef USE_SIDEBAR
796  if ((purge == MUTT_YES) && (m->msg_deleted != 0))
797  {
798  for (i = 0; i < m->msg_count; i++)
799  {
800  if (m->emails[i]->deleted && !m->emails[i]->read)
801  {
802  m->msg_unread--;
803  if (!m->emails[i]->old)
804  m->msg_new--;
805  }
806  if (m->emails[i]->deleted && m->emails[i]->flagged)
807  m->msg_flagged--;
808  }
809  }
810 #endif
811 
813  FREE(ptr);
814 
815  return 0;
816 }
817 
825 int mx_mbox_sync(struct Mailbox *m, int *index_hint)
826 {
827  if (!m)
828  return -1;
829 
830  int rc;
831  int purge = 1;
832  int msgcount, deleted;
833 
834  if (m->dontwrite)
835  {
836  char buf[256], tmp[256];
837  if (km_expand_key(buf, sizeof(buf), km_find_func(MENU_MAIN, OP_TOGGLE_WRITE)))
838  snprintf(tmp, sizeof(tmp), _(" Press '%s' to toggle write"), buf);
839  else
840  mutt_str_strfcpy(tmp, _("Use 'toggle-write' to re-enable write"), sizeof(tmp));
841 
842  mutt_error(_("Mailbox is marked unwritable. %s"), tmp);
843  return -1;
844  }
845  else if (m->readonly)
846  {
847  mutt_error(_("Mailbox is read-only"));
848  return -1;
849  }
850 
851  if (!m->changed && (m->msg_deleted == 0))
852  {
853  if (!m->quiet)
854  mutt_message(_("Mailbox is unchanged"));
855  return 0;
856  }
857 
858  if (m->msg_deleted != 0)
859  {
860  char buf[128];
861 
862  snprintf(buf, sizeof(buf),
863  ngettext("Purge %d deleted message?", "Purge %d deleted messages?", m->msg_deleted),
864  m->msg_deleted);
865  purge = query_quadoption(C_Delete, buf);
866  if (purge == MUTT_ABORT)
867  return -1;
868  else if (purge == MUTT_NO)
869  {
870  if (!m->changed)
871  return 0; /* nothing to do! */
872  /* let IMAP servers hold on to D flags */
873  if (m->magic != MUTT_IMAP)
874  {
875  for (int i = 0; i < m->msg_count; i++)
876  {
877  m->emails[i]->deleted = false;
878  m->emails[i]->purge = false;
879  }
880  m->msg_deleted = 0;
881  }
882  }
884  }
885 
886  /* really only for IMAP - imap_sync_mailbox results in a call to
887  * ctx_update_tables, so m->msg_deleted is 0 when it comes back */
888  msgcount = m->msg_count;
889  deleted = m->msg_deleted;
890 
891  if (purge && (m->msg_deleted != 0) && (mutt_str_strcmp(mailbox_path(m), C_Trash) != 0))
892  {
893  if (trash_append(m) != 0)
894  return -1;
895  }
896 
897 #ifdef USE_IMAP
898  if (m->magic == MUTT_IMAP)
899  rc = imap_sync_mailbox(m, purge, false);
900  else
901 #endif
902  rc = sync_mailbox(m, index_hint);
903  if (rc == 0)
904  {
905 #ifdef USE_IMAP
906  if ((m->magic == MUTT_IMAP) && !purge)
907  {
908  if (!m->quiet)
909  mutt_message(_("Mailbox checkpointed"));
910  }
911  else
912 #endif
913  {
914  if (!m->quiet)
915  mutt_message(_("%d kept, %d deleted"), msgcount - deleted, deleted);
916  }
917 
918  mutt_sleep(0);
919 
920  if ((m->msg_count == m->msg_deleted) &&
921  ((m->magic == MUTT_MBOX) || (m->magic == MUTT_MMDF)) &&
923  {
924  unlink(mailbox_path(m));
926  return 0;
927  }
928 
929  /* if we haven't deleted any messages, we don't need to resort */
930  /* ... except for certain folder formats which need "unsorted"
931  * sort order in order to synchronize folders.
932  *
933  * MH and maildir are safe. mbox-style seems to need re-sorting,
934  * at least with the new threading code. */
935  if (purge || ((m->magic != MUTT_MAILDIR) && (m->magic != MUTT_MH)))
936  {
937  /* IMAP does this automatically after handling EXPUNGE */
938  if (m->magic != MUTT_IMAP)
939  {
942  }
943  }
944  }
945 
946  return rc;
947 }
948 
956 struct Message *mx_msg_open_new(struct Mailbox *m, struct Email *e, MsgOpenFlags flags)
957 {
958  if (!m)
959  return NULL;
960 
961  struct Address *p = NULL;
962  struct Message *msg = NULL;
963 
964  if (!m->mx_ops || !m->mx_ops->msg_open_new)
965  {
966  mutt_debug(LL_DEBUG1, "function unimplemented for mailbox type %d\n", m->magic);
967  return NULL;
968  }
969 
970  msg = mutt_mem_calloc(1, sizeof(struct Message));
971  msg->write = true;
972 
973  if (e)
974  {
975  msg->flags.flagged = e->flagged;
976  msg->flags.replied = e->replied;
977  msg->flags.read = e->read;
978  msg->flags.draft = (flags & MUTT_SET_DRAFT);
979  msg->received = e->received;
980  }
981 
982  if (msg->received == 0)
983  msg->received = mutt_date_epoch();
984 
985  if (m->mx_ops->msg_open_new(m, msg, e) == 0)
986  {
987  if (m->magic == MUTT_MMDF)
988  fputs(MMDF_SEP, msg->fp);
989 
990  if (((m->magic == MUTT_MBOX) || (m->magic == MUTT_MMDF)) && flags & MUTT_ADD_FROM)
991  {
992  if (e)
993  {
994  p = TAILQ_FIRST(&e->env->return_path);
995  if (!p)
996  p = TAILQ_FIRST(&e->env->sender);
997  if (!p)
998  p = TAILQ_FIRST(&e->env->from);
999  }
1000 
1001  char buf[64] = { 0 };
1002  mutt_date_localtime_format(buf, sizeof(buf), "%a %b %e %H:%M:%S %Y\n", msg->received);
1003  fprintf(msg->fp, "From %s %s", p ? p->mailbox : NONULL(Username), buf);
1004  }
1005  }
1006  else
1007  FREE(&msg);
1008 
1009  return msg;
1010 }
1011 
1020 int mx_mbox_check(struct Mailbox *m, int *index_hint)
1021 {
1022  if (!m || !m->mx_ops)
1023  return -1;
1024 
1025  int rc = m->mx_ops->mbox_check(m, index_hint);
1026  if ((rc == MUTT_NEW_MAIL) || (rc == MUTT_REOPENED))
1028 
1029  return rc;
1030 }
1031 
1039 struct Message *mx_msg_open(struct Mailbox *m, int msgno)
1040 {
1041  if (!m)
1042  return NULL;
1043 
1044  struct Message *msg = NULL;
1045 
1046  if (!m->mx_ops || !m->mx_ops->msg_open)
1047  {
1048  mutt_debug(LL_DEBUG1, "function not implemented for mailbox type %d\n", m->magic);
1049  return NULL;
1050  }
1051 
1052  msg = mutt_mem_calloc(1, sizeof(struct Message));
1053  if (m->mx_ops->msg_open(m, msg, msgno) < 0)
1054  FREE(&msg);
1055 
1056  return msg;
1057 }
1058 
1066 int mx_msg_commit(struct Mailbox *m, struct Message *msg)
1067 {
1068  if (!m || !m->mx_ops || !m->mx_ops->msg_commit)
1069  return -1;
1070 
1071  if (!(msg->write && m->append))
1072  {
1073  mutt_debug(LL_DEBUG1, "msg->write = %d, m->append = %d\n", msg->write, m->append);
1074  return -1;
1075  }
1076 
1077  return m->mx_ops->msg_commit(m, msg);
1078 }
1079 
1087 int mx_msg_close(struct Mailbox *m, struct Message **msg)
1088 {
1089  if (!m || !msg || !*msg)
1090  return 0;
1091 
1092  int rc = 0;
1093 
1094  if (m->mx_ops && m->mx_ops->msg_close)
1095  rc = m->mx_ops->msg_close(m, *msg);
1096 
1097  if ((*msg)->path)
1098  {
1099  mutt_debug(LL_DEBUG1, "unlinking %s\n", (*msg)->path);
1100  unlink((*msg)->path);
1101  FREE(&(*msg)->path);
1102  }
1103 
1104  FREE(&(*msg)->committed_path);
1105  FREE(msg);
1106  return rc;
1107 }
1108 
1113 void mx_alloc_memory(struct Mailbox *m)
1114 {
1115  size_t s = MAX(sizeof(struct Email *), sizeof(int));
1116 
1117  if ((m->email_max + 25) * s < m->email_max * s)
1118  {
1119  mutt_error(_("Out of memory"));
1120  mutt_exit(1);
1121  }
1122 
1123  m->email_max += 25;
1124  if (m->emails)
1125  {
1126  mutt_mem_realloc(&m->emails, sizeof(struct Email *) * m->email_max);
1127  mutt_mem_realloc(&m->v2r, sizeof(int) * m->email_max);
1128  }
1129  else
1130  {
1131  m->emails = mutt_mem_calloc(m->email_max, sizeof(struct Email *));
1132  m->v2r = mutt_mem_calloc(m->email_max, sizeof(int));
1133  }
1134  for (int i = m->msg_count; i < m->email_max; i++)
1135  {
1136  m->emails[i] = NULL;
1137  m->v2r[i] = -1;
1138  }
1139 }
1140 
1148 int mx_check_empty(const char *path)
1149 {
1150  switch (mx_path_probe(path, NULL))
1151  {
1152  case MUTT_MBOX:
1153  case MUTT_MMDF:
1154  return mutt_file_check_empty(path);
1155  case MUTT_MH:
1156  return mh_check_empty(path);
1157  case MUTT_MAILDIR:
1158  return maildir_check_empty(path);
1159 #ifdef USE_IMAP
1160  case MUTT_IMAP:
1161  {
1162  int rc = imap_path_status(path, false);
1163  if (rc < 0)
1164  return -1;
1165  else if (rc == 0)
1166  return 1;
1167  else
1168  return 0;
1169  }
1170 #endif
1171  default:
1172  errno = EINVAL;
1173  return -1;
1174  }
1175  /* not reached */
1176 }
1177 
1188 int mx_tags_edit(struct Mailbox *m, const char *tags, char *buf, size_t buflen)
1189 {
1190  if (!m)
1191  return -1;
1192 
1193  if (m->mx_ops->tags_edit)
1194  return m->mx_ops->tags_edit(m, tags, buf, buflen);
1195 
1196  mutt_message(_("Folder doesn't support tagging, aborting"));
1197  return -1;
1198 }
1199 
1208 int mx_tags_commit(struct Mailbox *m, struct Email *e, char *tags)
1209 {
1210  if (!m)
1211  return -1;
1212 
1213  if (m->mx_ops->tags_commit)
1214  return m->mx_ops->tags_commit(m, e, tags);
1215 
1216  mutt_message(_("Folder doesn't support tagging, aborting"));
1217  return -1;
1218 }
1219 
1226 {
1227  return m && m->mx_ops->tags_commit && m->mx_ops->tags_edit;
1228 }
1229 
1236 enum MailboxType mx_path_probe(const char *path, struct stat *st)
1237 {
1238  if (!path)
1239  return MUTT_UNKNOWN;
1240 
1241  static const struct MxOps *no_stat[] = {
1242 #ifdef USE_IMAP
1243  &MxImapOps,
1244 #endif
1245 #ifdef USE_NOTMUCH
1246  &MxNotmuchOps,
1247 #endif
1248 #ifdef USE_POP
1249  &MxPopOps,
1250 #endif
1251 #ifdef USE_NNTP
1252  &MxNntpOps,
1253 #endif
1254  };
1255 
1256  static const struct MxOps *with_stat[] = {
1258 #ifdef USE_COMPRESSED
1259  &MxCompOps,
1260 #endif
1261  };
1262 
1263  enum MailboxType rc;
1264 
1265  for (size_t i = 0; i < mutt_array_size(no_stat); i++)
1266  {
1267  rc = no_stat[i]->path_probe(path, NULL);
1268  if (rc != MUTT_UNKNOWN)
1269  return rc;
1270  }
1271 
1272  struct stat st2 = { 0 };
1273  if (!st)
1274  st = &st2;
1275 
1276  if (stat(path, st) != 0)
1277  {
1278  mutt_debug(LL_DEBUG1, "unable to stat %s: %s (errno %d)\n", path, strerror(errno), errno);
1279  return MUTT_UNKNOWN;
1280  }
1281 
1282  for (size_t i = 0; i < mutt_array_size(with_stat); i++)
1283  {
1284  rc = with_stat[i]->path_probe(path, st);
1285  if (rc != MUTT_UNKNOWN)
1286  return rc;
1287  }
1288 
1289  return rc;
1290 }
1291 
1295 int mx_path_canon(char *buf, size_t buflen, const char *folder, enum MailboxType *magic)
1296 {
1297  if (!buf)
1298  return -1;
1299 
1300  for (size_t i = 0; i < 3; i++)
1301  {
1302  /* Look for !! ! - < > or ^ followed by / or NUL */
1303  if ((buf[0] == '!') && (buf[1] == '!'))
1304  {
1305  if (((buf[2] == '/') || (buf[2] == '\0')))
1306  {
1307  mutt_str_inline_replace(buf, buflen, 2, LastFolder);
1308  }
1309  }
1310  else if ((buf[0] == '+') || (buf[0] == '='))
1311  {
1312  size_t folder_len = mutt_str_strlen(folder);
1313  if ((folder_len > 0) && (folder[folder_len - 1] != '/'))
1314  {
1315  buf[0] = '/';
1316  mutt_str_inline_replace(buf, buflen, 0, folder);
1317  }
1318  else
1319  {
1320  mutt_str_inline_replace(buf, buflen, 1, folder);
1321  }
1322  }
1323  else if ((buf[1] == '/') || (buf[1] == '\0'))
1324  {
1325  if (buf[0] == '!')
1326  {
1327  mutt_str_inline_replace(buf, buflen, 1, C_Spoolfile);
1328  }
1329  else if (buf[0] == '-')
1330  {
1331  mutt_str_inline_replace(buf, buflen, 1, LastFolder);
1332  }
1333  else if (buf[0] == '<')
1334  {
1335  mutt_str_inline_replace(buf, buflen, 1, C_Record);
1336  }
1337  else if (buf[0] == '>')
1338  {
1339  mutt_str_inline_replace(buf, buflen, 1, C_Mbox);
1340  }
1341  else if (buf[0] == '^')
1342  {
1343  mutt_str_inline_replace(buf, buflen, 1, CurrentFolder);
1344  }
1345  else if (buf[0] == '~')
1346  {
1347  mutt_str_inline_replace(buf, buflen, 1, HomeDir);
1348  }
1349  }
1350  else if (buf[0] == '@')
1351  {
1352  /* elm compatibility, @ expands alias to user name */
1353  struct AddressList *al = mutt_alias_lookup(buf + 1);
1354  if (TAILQ_EMPTY(al))
1355  break;
1356 
1357  struct Email *e = email_new();
1358  e->env = mutt_env_new();
1359  mutt_addrlist_copy(&e->env->from, al, false);
1360  mutt_addrlist_copy(&e->env->to, al, false);
1361  mutt_default_save(buf, buflen, e);
1362  email_free(&e);
1363  break;
1364  }
1365  else
1366  {
1367  break;
1368  }
1369  }
1370 
1371  // if (!folder) //XXX - use inherited version, or pass NULL to backend?
1372  // return -1;
1373 
1374  enum MailboxType magic2 = mx_path_probe(buf, NULL);
1375  if (magic)
1376  *magic = magic2;
1377  const struct MxOps *ops = mx_get_ops(magic2);
1378  if (!ops || !ops->path_canon)
1379  return -1;
1380 
1381  if (ops->path_canon(buf, buflen) < 0)
1382  {
1383  mutt_path_canon(buf, buflen, HomeDir);
1384  }
1385 
1386  return 0;
1387 }
1388 
1393 int mx_path_canon2(struct Mailbox *m, const char *folder)
1394 {
1395  if (!m)
1396  return -1;
1397 
1398  char buf[PATH_MAX];
1399 
1400  if (m->realpath)
1401  mutt_str_strfcpy(buf, m->realpath, sizeof(buf));
1402  else
1403  mutt_str_strfcpy(buf, mailbox_path(m), sizeof(buf));
1404 
1405  int rc = mx_path_canon(buf, sizeof(buf), folder, &m->magic);
1406 
1407  mutt_str_replace(&m->realpath, buf);
1408 
1409  if (rc >= 0)
1410  {
1411  m->mx_ops = mx_get_ops(m->magic);
1413  }
1414 
1415  return rc;
1416 }
1417 
1421 int mx_path_pretty(char *buf, size_t buflen, const char *folder)
1422 {
1423  enum MailboxType magic = mx_path_probe(buf, NULL);
1424  const struct MxOps *ops = mx_get_ops(magic);
1425  if (!ops)
1426  return -1;
1427 
1428  if (!ops->path_canon)
1429  return -1;
1430 
1431  if (ops->path_canon(buf, buflen) < 0)
1432  return -1;
1433 
1434  if (!ops->path_pretty)
1435  return -1;
1436 
1437  if (ops->path_pretty(buf, buflen, folder) < 0)
1438  return -1;
1439 
1440  return 0;
1441 }
1442 
1446 int mx_path_parent(char *buf, size_t buflen)
1447 {
1448  if (!buf)
1449  return -1;
1450 
1451  return 0;
1452 }
1453 
1463 {
1464  if (!m || !m->mx_ops || !m->mx_ops->msg_padding_size)
1465  return 0;
1466 
1467  return m->mx_ops->msg_padding_size(m);
1468 }
1469 
1473 struct Account *mx_ac_find(struct Mailbox *m)
1474 {
1475  if (!m || !m->mx_ops)
1476  return NULL;
1477 
1478  struct Account *np = NULL;
1479  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1480  {
1481  if (np->magic != m->magic)
1482  continue;
1483 
1484  if (m->mx_ops->ac_find(np, m->realpath))
1485  return np;
1486  }
1487 
1488  return NULL;
1489 }
1490 
1496 struct Mailbox *mx_mbox_find(struct Account *a, const char *path)
1497 {
1498  if (!a || !path)
1499  return NULL;
1500 
1501  struct MailboxNode *np = NULL;
1502  STAILQ_FOREACH(np, &a->mailboxes, entries)
1503  {
1504  if (mutt_str_strcmp(np->mailbox->realpath, path) == 0)
1505  return np->mailbox;
1506  }
1507 
1508  return NULL;
1509 }
1510 
1516 struct Mailbox *mx_mbox_find2(const char *path)
1517 {
1518  if (!path)
1519  return NULL;
1520 
1521  char buf[PATH_MAX];
1522  mutt_str_strfcpy(buf, path, sizeof(buf));
1523  mx_path_canon(buf, sizeof(buf), C_Folder, NULL);
1524 
1525  struct Account *np = NULL;
1526  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1527  {
1528  struct Mailbox *m = mx_mbox_find(np, buf);
1529  if (m)
1530  return m;
1531  }
1532 
1533  return NULL;
1534 }
1535 
1539 struct Mailbox *mx_path_resolve(const char *path)
1540 {
1541  if (!path)
1542  return NULL;
1543 
1544  struct Mailbox *m = mx_mbox_find2(path);
1545  if (m)
1546  return m;
1547 
1548  m = mailbox_new();
1549  m->flags = MB_HIDDEN;
1550  mutt_buffer_strcpy(&m->pathbuf, path);
1552 
1553  return m;
1554 }
1555 
1559 int mx_ac_add(struct Account *a, struct Mailbox *m)
1560 {
1561  if (!a || !m || !m->mx_ops || !m->mx_ops->ac_add)
1562  return -1;
1563 
1564  if (m->mx_ops->ac_add(a, m) < 0)
1565  return -1;
1566 
1567  account_mailbox_add(a, m);
1568  return 0;
1569 }
1570 
1575 int mx_ac_remove(struct Mailbox *m)
1576 {
1577  if (!m || !m->account)
1578  return -1;
1579 
1581  if (STAILQ_EMPTY(&m->account->mailboxes))
1582  {
1584  }
1585  return 0;
1586 }
1587 
1591 int mx_mbox_check_stats(struct Mailbox *m, int flags)
1592 {
1593  if (!m)
1594  return -1;
1595 
1596  return m->mx_ops->mbox_check_stats(m, flags);
1597 }
1598 
1608 int mx_save_hcache(struct Mailbox *m, struct Email *e)
1609 {
1610  if (!m->mx_ops || !m->mx_ops->msg_save_hcache)
1611  return 0;
1612 
1613  return m->mx_ops->msg_save_hcache(m, e);
1614 }
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mx.h:52
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mx.h:50
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:410
WHERE char * Username
User&#39;s login name.
Definition: globals.h:52
The "current" mailbox.
Definition: context.h:36
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:194
#define MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn&#39;t exist.
Definition: mx.h:59
An enumeration.
Definition: enum.h:31
int ctx_mailbox_observer(struct NotifyCallback *nc)
Watch for changes affecting the Context - Implements observer_t.
Definition: context.c:285
Notmuch virtual mailbox type.
int(* msg_commit)(struct Mailbox *m, struct Message *msg)
Save changes to an email.
Definition: mx.h:196
Manage keymappings.
#define MUTT_ACL_ALL
Definition: mailbox.h:87
#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:102
struct AddressList * mutt_alias_lookup(const char *s)
Find an Alias.
Definition: alias.c:286
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:69
off_t size
Size of the Mailbox.
Definition: mailbox.h:98
Representation of the email&#39;s header.
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:773
The envelope/body of an email.
Definition: email.h:39
#define TAILQ_FIRST(head)
Definition: queue.h:717
int imap_path_status(const char *path, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1309
#define mutt_perror(...)
Definition: logging.h:85
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition: newsrc.c:1263
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe()
Definition: imap.c:2425
int mx_mbox_check(struct Mailbox *m, int *index_hint)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1020
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:107
int msg_unread
Number of unread messages.
Definition: mailbox.h:103
int mx_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Wrapper for MxOps::ac_add.
Definition: mx.c:1559
int mx_path_canon2(struct Mailbox *m, const char *folder)
XXX canonicalise the path to realpath.
Definition: mx.c:1393
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:51
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:558
Structs that make up an email.
The "currently-open" mailbox.
struct MxOps MxMhOps
MH Mailbox - Implements MxOps.
Definition: mh.c:805
int(* mbox_check_stats)(struct Mailbox *m, int flags)
Check the Mailbox statistics.
Definition: mx.h:155
Mbox local mailbox type.
void mailbox_changed(struct Mailbox *m, enum MailboxNotification action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:160
int(* mbox_sync)(struct Mailbox *m, int *index_hint)
Save changes to the Mailbox.
Definition: mx.h:163
bool replied
Definition: mx.h:91
int mx_path_pretty(char *buf, size_t buflen, const char *folder)
Abbreviate a mailbox path - Wrapper for MxOps::path_pretty.
Definition: mx.c:1421
int mx_path_parent(char *buf, size_t buflen)
Find the parent of a mailbox path - Wrapper for MxOps::path_parent.
Definition: mx.c:1446
User aborted the question (with Ctrl-G)
Definition: quad.h:37
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: init.c:3331
#define mutt_message(...)
Definition: logging.h:83
WHERE bool C_Confirmappend
Config: Confirm before appending emails to a mailbox.
Definition: globals.h:214
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:104
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:39
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
static int trash_append(struct Mailbox *m)
move deleted mails to the trash folder
Definition: mx.c:458
bool peekonly
Just taking a glance, revert atime.
Definition: mailbox.h:128
enum MailboxType(* path_probe)(const char *path, const struct stat *st)
Does this Mailbox type recognise this path?
Definition: mx.h:245
int mx_path_canon(char *buf, size_t buflen, const char *folder, enum MailboxType *magic)
Canonicalise a mailbox path - Wrapper for MxOps::path_canon.
Definition: mx.c:1295
struct NntpAccountData * adata
Definition: nntp.h:153
unsigned char C_Move
Config: Move emails from C_Spoolfile to C_Mbox when read.
Definition: mx.c:85
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:95
NeoMutt Logging.
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:727
struct MailboxList mailboxes
List of Mailboxes.
Definition: account.h:41
Compressed mbox local mailbox type.
A group of associated Mailboxes.
Definition: account.h:36
WHERE unsigned char C_Delete
Config: Really delete messages, when the mailbox is closed.
Definition: globals.h:187
struct MxOps MxMaildirOps
Maildir Mailbox - Implements MxOps.
Definition: maildir.c:694
WHERE bool C_SaveEmpty
Config: (mbox,mmdf) Preserve empty mailboxes.
Definition: globals.h:256
void mx_alloc_memory(struct Mailbox *m)
Create storage for the emails.
Definition: mx.c:1113
#define _(a)
Definition: message.h:28
Mailbox wasn&#39;t recognised.
Definition: mailbox.h:46
Error occurred examining Mailbox.
Definition: mailbox.h:45
An email address.
Definition: address.h:34
struct Mailbox * mx_mbox_find(struct Account *a, const char *path)
XXX.
Definition: mx.c:1496
struct MxOps MxPopOps
POP Mailbox - Implements MxOps.
Definition: pop.c:1278
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:254
Mailbox was closed.
Definition: mailbox.h:63
WHERE char * LastFolder
Previously selected mailbox.
Definition: globals.h:55
char * mailbox
Mailbox and host address.
Definition: address.h:37
Messages to be purged (bypass trash)
Definition: mutt.h:106
int(* ac_add)(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account.
Definition: mx.h:123
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
Index panel (list of emails)
Definition: keymap.h:68
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mx.h:49
struct MxOps MxMboxOps
Mbox Mailbox - Implements MxOps.
Definition: mbox.c:1791
WHERE char * C_Record
Config: Folder to save &#39;sent&#39; messages.
Definition: globals.h:136
#define MUTT_READONLY
Open in read-only mode.
Definition: mx.h:53
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:1608
struct Mailbox * mx_mbox_find2(const char *path)
XXX.
Definition: mx.c:1516
WHERE bool OptNeedRescore
(pseudo) set when the &#39;score&#39; command is used
Definition: options.h:40
struct Account * mx_ac_find(struct Mailbox *m)
XXX.
Definition: mx.c:1473
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:662
All user-callable functions.
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:34
Container for Accounts, Notifications.
Definition: neomutt.h:35
Representation of a single alias to an email address.
struct Context * ctx_new(void)
Create a new Context.
Definition: context.c:70
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1415
Update internal tables.
Definition: mailbox.h:66
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:65
Hundreds of global variables to back the user variables.
int imap_sync_mailbox(struct Mailbox *m, bool expunge, bool close)
Sync all the changes to the server.
Definition: imap.c:1625
Email Address Handling.
int(* msg_open_new)(struct Mailbox *m, struct Message *msg, struct Email *e)
Open a new message in a Mailbox.
Definition: mx.h:188
Assorted sorting methods.
int(* mbox_open)(struct Mailbox *m)
Open a Mailbox.
Definition: mx.h:131
int(* mbox_open_append)(struct Mailbox *m, OpenMailboxFlags flags)
Open a Mailbox for appending.
Definition: mx.h:139
Some miscellaneous functions.
#define MAX(a, b)
Definition: memory.h:30
char * C_Trash
Config: Folder to put deleted emails.
Definition: mx.c:86
#define mutt_array_size(x)
Definition: memory.h:33
int(* path_canon)(char *buf, size_t buflen)
Canonicalise a Mailbox path.
Definition: mx.h:253
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1087
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:128
bool tagged
Email is tagged.
Definition: email.h:46
struct MxOps MxCompOps
Compressed Mailbox - Implements MxOps.
Definition: compress.c:966
bool read
Email is read.
Definition: email.h:53
bool notify_observer_add(struct Notify *notify, enum NotifyType type, int subtype, observer_t callback, intptr_t data)
Add an observer to an object.
Definition: notify.c:159
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1509
int mx_check_empty(const char *path)
Is the mailbox empty.
Definition: mx.c:1148
struct Mailbox * mailbox
Definition: context.h:50
Parse and execute user-defined hooks.
API for mailboxes.
bool old
Email is seen, but unread.
Definition: email.h:52
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:55
#define MUTT_PEEK
Revert atime back after taking a look (if applicable)
Definition: mx.h:58
void mutt_file_unlink_empty(const char *path)
Delete a file if it&#39;s empty.
Definition: file.c:1296
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:116
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:130
The Context has been opened.
Definition: context.h:67
WHERE char * C_Mbox
Config: Folder that receives read emails (see Move)
Definition: globals.h:122
IMAP network mailbox.
struct Envelope * env
Envelope information.
Definition: email.h:91
enum MailboxType magic
Mailbox type, e.g. MUTT_IMAP.
Definition: mx.h:105
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:1208
POP network mailbox.
WHERE char * HomeDir
User&#39;s home directory.
Definition: globals.h:49
struct Notify * notify
Notifications handler.
Definition: context.h:51
void mx_fastclose_mailbox(struct Mailbox *m)
free up memory associated with the Mailbox
Definition: mx.c:392
struct MxOps MxImapOps
IMAP Mailbox - Implements MxOps.
Definition: imap.c:2505
char * group
Definition: nntp.h:140
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: globals.h:54
int opened
Number of times mailbox is opened.
Definition: mailbox.h:143
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:109
struct Message * mx_msg_open_new(struct Mailbox *m, struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:956
int(* msg_padding_size)(struct Mailbox *m)
Bytes of padding between messages.
Definition: mx.h:210
void * mdata
Driver specific data.
Definition: mailbox.h:147
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
struct Account * account_new(const char *name, struct ConfigSubset *sub)
Create a new Account.
Definition: account.c:42
#define MUTT_MBOX_HOOK
mbox-hook: move messages after reading them
Definition: hook.h:46
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:50
int flags
e.g. MB_NORMAL
Definition: mailbox.h:145
struct MxOps MxNntpOps
NNTP Mailbox - Implements MxOps.
Definition: nntp.c:2872
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:808
Old messages.
Definition: mutt.h:100
unsigned char C_CatchupNewsgroup
Config: (nntp) Mark all articles as read when leaving a newsgroup.
Definition: mx.c:82
WHERE bool OptForceRefresh
(pseudo) refresh even during macros
Definition: options.h:35
Prototypes for many functions.
bool mutt_path_canon(char *buf, size_t buflen, const char *homedir)
Create the canonical version of a path.
Definition: path.c:221
#define MB_HIDDEN
Definition: mailbox.h:37
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:310
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:362
int(* tags_edit)(struct Mailbox *m, const char *tags, char *buf, size_t buflen)
Prompt and validate new messages tags.
Definition: mx.h:229
bool flagged
Definition: mx.h:90
A local copy of an email.
Definition: mx.h:81
int email_max
Number of pointers in emails.
Definition: mailbox.h:111
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: globals.h:124
void ctx_update(struct Context *ctx)
Update the Context&#39;s message counts.
Definition: context.c:102
struct Message::@0 flags
int imap_access(const char *path)
Check permissions on an IMAP mailbox with a new connection.
Definition: imap.c:599
Messages to be deleted.
Definition: mutt.h:104
A mailbox.
Definition: mailbox.h:92
Clear the &#39;last-tagged&#39; pointer.
Definition: mailbox.h:67
#define PATH_MAX
Definition: mutt.h:52
char * mutt_find_hook(HookFlags type, const char *pat)
Find a matching hook.
Definition: hook.c:558
enum MailboxType magic
Type of Mailboxes this Account contains.
Definition: account.h:38
#define MUTT_NOSORT
Do not sort the mailbox after opening it.
Definition: mx.h:51
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:50
WHERE bool C_MaildirTrash
Config: Use the maildir &#39;trashed&#39; flag, rather than deleting.
Definition: globals.h:247
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:780
Email list needs resorting.
Definition: mailbox.h:65
bool dontwrite
Don&#39;t write the mailbox on close.
Definition: mailbox.h:126
int(* msg_save_hcache)(struct Mailbox *m, struct Email *e)
Save message to the header cache.
Definition: mx.h:218
&#39;mmdf&#39; Mailbox type
Definition: mailbox.h:48
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
int(* msg_open)(struct Mailbox *m, struct Message *msg, int msgno)
Open an email message in a Mailbox.
Definition: mx.h:179
int(* mbox_check)(struct Mailbox *m, int *index_hint)
Check for new mail.
Definition: mx.h:147
bool account_mailbox_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account.
Definition: account.c:60
Compressed file Mailbox type.
Definition: mailbox.h:55
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:124
&#39;MH&#39; Mailbox type
Definition: mailbox.h:49
const struct MxOps * mx_ops
MXAPI callback functions.
Definition: mailbox.h:122
bool quiet
Inhibit status messages?
Definition: mailbox.h:129
int imap_copy_messages(struct Mailbox *m, struct EmailList *el, const char *dest, bool delete_original)
Server COPY messages to another folder.
Definition: message.c:1576
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
bool purge
Skip trash folder when deleting.
Definition: email.h:48
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:1188
unsigned char C_MboxType
Config: Default type for creating new mailboxes.
Definition: mx.c:84
bool draft
Definition: mx.h:92
#define MUTT_QUIET
Do not print any messages.
Definition: mx.h:54
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:132
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
uint8_t MsgOpenFlags
Flags for mx_msg_open_new(), e.g. MUTT_ADD_FROM.
Definition: mx.h:62
NNTP-specific Mailbox data -.
Definition: nntp.h:138
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
Maildir local mailbox type.
bool mutt_comp_can_append(struct Mailbox *m)
Can we append to this path?
Definition: compress.c:369
&#39;mbox&#39; Mailbox type
Definition: mailbox.h:47
struct MxOps MxMmdfOps
MMDF Mailbox - Implements MxOps.
Definition: mbox.c:1819
bool write
nonzero if message is open for writing
Definition: mx.h:86
int maildir_check_empty(const char *path)
Is the mailbox empty.
Definition: shared.c:1564
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:210
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:112
void mutt_make_label_hash(struct Mailbox *m)
Create a Hash Table to store the labels.
Definition: mutt_header.c:358
struct Mailbox * mailbox_new(void)
Create a new Mailbox.
Definition: mailbox.c:41
bool C_MarkOld
Config: Mark new emails as old when leaving the mailbox.
Definition: email_globals.c:36
Context has changed.
Definition: notify_type.h:38
Email list was changed.
Definition: mailbox.h:64
Duplicate the structure of an entire email.
MailboxType
Supported mailbox formats.
Definition: mailbox.h:42
struct AddressList return_path
Return path for the Email.
Definition: envelope.h:56
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:142
Log at debug level 1.
Definition: logging.h:56
static int sync_mailbox(struct Mailbox *m, int *index_hint)
save changes to disk
Definition: mx.c:431
WHERE char * C_Spoolfile
Config: Inbox.
Definition: globals.h:149
bool flagged
Marked important?
Definition: email.h:45
int mx_mbox_sync(struct Mailbox *m, int *index_hint)
Save changes to mailbox.
Definition: mx.c:825
int(* mbox_close)(struct Mailbox *m)
Close a Mailbox.
Definition: mx.h:170
static int mx_open_mailbox_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox for appending.
Definition: mx.c:187
int msg_new
Number of new messages.
Definition: mailbox.h:106
struct Hash * subj_hash
Hash table by subject.
Definition: mailbox.h:139
int mx_mbox_check_stats(struct Mailbox *m, int flags)
Check the statistics for a mailbox - Wrapper for MxOps::mbox_check_stats.
Definition: mx.c:1591
const struct MxOps * mx_get_ops(enum MailboxType magic)
Get mailbox operations.
Definition: mx.c:141
bool deleted
Email is deleted.
Definition: email.h:47
int(* path_pretty)(char *buf, size_t buflen, const char *folder)
Abbreviate a Mailbox path.
Definition: mx.h:262
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:83
#define mutt_error(...)
Definition: logging.h:84
bool replied
Email has been replied to.
Definition: email.h:56
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1066
void mbox_reset_atime(struct Mailbox *m, struct stat *st)
Reset the access time on the mailbox file.
Definition: mbox.c:849
int mutt_file_check_empty(const char *path)
Is the mailbox empty.
Definition: file.c:1397
int mutt_append_message(struct Mailbox *dest, struct Mailbox *src, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
Append a message.
Definition: copy.c:876
FILE * fp
pointer to the message data
Definition: mx.h:83
#define IP
Definition: set.h:144
#define FREE(x)
Definition: memory.h:40
int(* msg_close)(struct Mailbox *m, struct Message *msg)
Close an email.
Definition: mx.h:204
struct Mailbox * mx_path_resolve(const char *path)
XXX.
Definition: mx.c:1539
Mailbox has changed.
Definition: notify_type.h:35
Mapping between user-readable string and a constant.
Definition: mapping.h:29
int mx_access(const char *path, int flags)
Wrapper for access, checks permissions on a given mailbox.
Definition: mx.c:170
#define STAILQ_EMPTY(head)
Definition: queue.h:346
time_t received
the time at which this message was received
Definition: mx.h:94
bool neomutt_account_remove(struct NeoMutt *n, struct Account *a)
Remove an Account from the global list.
Definition: neomutt.c:104
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:52
struct Email * email_new(void)
Create a new Email.
Definition: email.c:68
List of Mailboxes.
Definition: mailbox.h:156
bool changed
Mailbox has been modified.
Definition: mailbox.h:125
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:48
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:270
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:38
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size.
Definition: mx.c:1462
New mail received in Mailbox.
Definition: mx.h:72
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:1071
bool mx_tags_is_supported(struct Mailbox *m)
return true if mailbox support tagging
Definition: mx.c:1225
struct Notify * notify
Notifications handler.
Definition: mailbox.h:150
bool C_KeepFlagged
Config: Don&#39;t move flagged messages from C_Spoolfile to C_Mbox.
Definition: mx.c:83
An Event that happened to an Context.
Definition: context.h:57
struct Account *(* ac_find)(struct Account *a, const char *path)
Find an Account that matches a Mailbox path.
Definition: mx.h:115
#define TAILQ_EMPTY(head)
Definition: queue.h:715
#define MUTT_NEWFOLDER
Create a new folder - same as MUTT_APPEND,.
Definition: mx.h:55
bool neomutt_account_add(struct NeoMutt *n, struct Account *a)
Add an Account to the global list.
Definition: neomutt.c:83
int mx_ac_remove(struct Mailbox *m)
Remove a Mailbox from an Account and delete Account if empty.
Definition: mx.c:1575
struct Buffer pathbuf
Definition: mailbox.h:94
void mutt_hash_free(struct Hash **ptr)
free_hdata a hash table
Definition: hash.c:472
bool read
Definition: mx.h:89
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:64
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:41
enum MailboxType mx_path_probe(const char *path, struct stat *st)
Find a mailbox that understands a path.
Definition: mx.c:1236
Mailbox was reopened.
Definition: mx.h:74
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:52
bool notify_send(struct Notify *notify, int type, int subtype, intptr_t data)
Send out a notification message.
Definition: notify.c:145
int imap_fast_trash(struct Mailbox *m, char *dest)
Use server COPY command to copy deleted messages to trash.
Definition: imap.c:1519
Convenience wrapper for the library headers.
struct Hash * label_hash
Hash table for x-labels.
Definition: mailbox.h:140
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
static bool mutt_is_spool(const char *str)
Is this the spoolfile?
Definition: mx.c:155
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1039
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
struct Hash * id_hash
Hash table by msg id.
Definition: mailbox.h:138
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:84
char * path
path to temp file
Definition: mx.h:84
Usenet network mailbox type; talk to an NNTP server.
The Mailbox API.
Definition: mx.h:103
struct MxOps MxNotmuchOps
Notmuch Mailbox - Implements MxOps.
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:158
#define MMDF_SEP
Definition: mbox.h:60
int(* tags_commit)(struct Mailbox *m, struct Email *e, char *buf)
Save the tags to a message.
Definition: mx.h:238
int mh_check_empty(const char *path)
Is mailbox empty.
Definition: shared.c:1604