NeoMutt  2020-11-20
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 <unistd.h>
40 #include "mutt/lib.h"
41 #include "address/lib.h"
42 #include "email/lib.h"
43 #include "core/lib.h"
44 #include "alias/lib.h"
45 #include "gui/lib.h"
46 #include "mutt.h"
47 #include "mx.h"
48 #include "maildir/lib.h"
49 #include "mbox/lib.h"
50 #include "context.h"
51 #include "copy.h"
52 #include "hook.h"
53 #include "keymap.h"
54 #include "mutt_globals.h"
55 #include "mutt_header.h"
56 #include "mutt_logging.h"
57 #include "mutt_mailbox.h"
58 #include "muttlib.h"
59 #include "opcodes.h"
60 #include "options.h"
61 #include "protos.h"
62 #include "sort.h"
63 #ifdef USE_COMP_MBOX
64 #include "compmbox/lib.h"
65 #endif
66 #ifdef USE_IMAP
67 #include "imap/lib.h"
68 #endif
69 #ifdef USE_POP
70 #include "pop/lib.h"
71 #endif
72 #ifdef USE_NNTP
73 #include "nntp/lib.h"
74 #endif
75 #ifdef USE_NOTMUCH
76 #include "notmuch/lib.h"
77 #endif
78 #ifdef ENABLE_NLS
79 #include <libintl.h>
80 #endif
81 
82 /* These Config Variables are only used in mx.c */
84 unsigned char C_MboxType;
85 unsigned char C_Move;
86 char *C_Trash;
87 
88 // clang-format off
89 static 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  if (mutt_str_equal(str, C_Spoolfile))
158  return true;
159 
160  struct Url *ua = url_parse(str);
161  struct Url *ub = url_parse(C_Spoolfile);
162 
163  const bool is_spool =
164  ua && ub && (ua->scheme == ub->scheme) &&
165  mutt_istr_equal(ua->host, ub->host) && mutt_istr_equal(ua->path, ub->path) &&
166  (!ua->user || !ub->user || mutt_str_equal(ua->user, ub->user));
167 
168  url_free(&ua);
169  url_free(&ub);
170  return is_spool;
171 }
172 
183 int mx_access(const char *path, int flags)
184 {
185 #ifdef USE_IMAP
186  if (imap_path_probe(path, NULL) == MUTT_IMAP)
187  return imap_access(path);
188 #endif
189 
190  return access(path, flags);
191 }
192 
200 static int mx_open_mailbox_append(struct Mailbox *m, OpenMailboxFlags flags)
201 {
202  if (!m)
203  return -1;
204 
205  struct stat sb;
206 
207  m->append = true;
208  if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR))
209  {
211 
212  if (m->type == MUTT_UNKNOWN)
213  {
214  if (flags & (MUTT_APPEND | MUTT_NEWFOLDER))
215  {
217  }
218  else
219  {
220  mutt_error(_("%s is not a mailbox"), mailbox_path(m));
221  return -1;
222  }
223  }
224 
225  if (m->type == MUTT_MAILBOX_ERROR)
226  {
227  if (stat(mailbox_path(m), &sb) == -1)
228  {
229  if (errno == ENOENT)
230  {
231 #ifdef USE_COMP_MBOX
232  if (mutt_comp_can_append(m))
233  m->type = MUTT_COMPRESSED;
234  else
235 #endif
236  m->type = C_MboxType;
237  flags |= MUTT_APPENDNEW;
238  }
239  else
240  {
242  return -1;
243  }
244  }
245  else
246  return -1;
247  }
248 
249  m->mx_ops = mx_get_ops(m->type);
250  }
251 
252  if (!m->mx_ops || !m->mx_ops->mbox_open_append)
253  return -1;
254 
255  int rc = m->mx_ops->mbox_open_append(m, flags);
256  m->opened++;
257  return rc;
258 }
259 
266 bool mx_mbox_ac_link(struct Mailbox *m)
267 {
268  if (!m)
269  return false;
270 
271  if (m->account)
272  return true;
273 
274  struct Account *a = mx_ac_find(m);
275  const bool new_account = !a;
276  if (new_account)
277  {
278  a = account_new(NULL, NeoMutt->sub);
279  a->type = m->type;
280  }
281  if (mx_ac_add(a, m) < 0)
282  {
283  if (new_account)
284  {
285  FREE(&a);
286  }
287  return false;
288  }
289  if (new_account)
290  {
292  }
293  return true;
294 }
295 
303 struct Context *mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
304 {
305  if (!m)
306  return NULL;
307 
308  struct Context *ctx = ctx_new(m);
309 
310  struct EventContext ev_ctx = { ctx };
311  notify_send(ctx->notify, NT_CONTEXT, NT_CONTEXT_OPEN, &ev_ctx);
312 
313  // If the Mailbox is closed, Context->mailbox must be set to NULL
315 
316  if ((m->type == MUTT_UNKNOWN) && (flags & (MUTT_NEWFOLDER | MUTT_APPEND)))
317  {
318  m->type = C_MboxType;
319  m->mx_ops = mx_get_ops(m->type);
320  }
321 
322  const bool newly_linked_account = !m->account;
323  if (newly_linked_account)
324  {
325  if (!mx_mbox_ac_link(m))
326  {
327  ctx_free(&ctx);
328  return NULL;
329  }
330  }
331 
332  ctx->msg_in_pager = -1;
333  ctx->collapsed = false;
334 
335  m->verbose = !(flags & MUTT_QUIET);
336  if (flags & MUTT_READONLY)
337  m->readonly = true;
338  m->peekonly = (flags & MUTT_PEEK);
339 
340  if (flags & (MUTT_APPEND | MUTT_NEWFOLDER))
341  {
342  if (mx_open_mailbox_append(ctx->mailbox, flags) != 0)
343  {
344  goto error;
345  }
346  return ctx;
347  }
348 
349  if (m->opened > 0)
350  {
351  m->opened++;
352  return ctx;
353  }
354 
355  m->size = 0;
356  m->msg_unread = 0;
357  m->msg_flagged = 0;
358  m->rights = MUTT_ACL_ALL;
359 
360  if (m->type == MUTT_UNKNOWN)
361  {
363  m->mx_ops = mx_get_ops(m->type);
364  }
365 
366  if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR) || !m->mx_ops)
367  {
368  if (m->type == MUTT_MAILBOX_ERROR)
370  else if ((m->type == MUTT_UNKNOWN) || !m->mx_ops)
371  mutt_error(_("%s is not a mailbox"), mailbox_path(m));
372  goto error;
373  }
374 
376 
377  /* if the user has a 'push' command in their .neomuttrc, or in a folder-hook,
378  * it will cause the progress messages not to be displayed because
379  * mutt_refresh() will think we are in the middle of a macro. so set a
380  * flag to indicate that we should really refresh the screen. */
381  OptForceRefresh = true;
382 
383  if (m->verbose)
384  mutt_message(_("Reading %s..."), mailbox_path(m));
385 
386  // Clear out any existing emails
387  for (int i = 0; i < m->email_max; i++)
388  {
389  email_free(&m->emails[i]);
390  }
391 
392  m->msg_count = 0;
393  m->msg_unread = 0;
394  m->msg_flagged = 0;
395  m->msg_new = 0;
396  m->msg_deleted = 0;
397  m->msg_tagged = 0;
398  m->vcount = 0;
399 
400  int rc = m->mx_ops->mbox_open(ctx->mailbox);
401  m->opened++;
402  if (rc == 0)
403  ctx_update(ctx);
404 
405  if ((rc == 0) || (rc == -2))
406  {
407  if ((flags & MUTT_NOSORT) == 0)
408  {
409  /* avoid unnecessary work since the mailbox is completely unthreaded
410  * to begin with */
411  OptSortSubthreads = false;
412  OptNeedRescore = false;
413  }
414  if (m->verbose)
416  if (rc == -2)
417  {
418  mutt_error(_("Reading from %s interrupted..."), mailbox_path(m));
419  mutt_sort_headers(ctx->mailbox, ctx->threads, true, &ctx->vsize);
420  }
421  }
422  else
423  {
424  goto error;
425  }
426 
427  if (!m->peekonly)
428  m->has_new = false;
429  OptForceRefresh = false;
430 
431  return ctx;
432 
433 error:
435  if (newly_linked_account)
437  ctx_free(&ctx);
438  return NULL;
439 }
440 
446 {
447  if (!m)
448  return;
449 
450  m->opened--;
451  if (m->opened != 0)
452  return;
453 
454  /* never announce that a mailbox we've just left has new mail.
455  * TODO: really belongs in mx_mbox_close, but this is a nice hook point */
456  if (!m->peekonly)
458 
459  if (m->mx_ops)
460  m->mx_ops->mbox_close(m);
461 
463  mutt_hash_free(&m->id_hash);
465 
466  if (m->emails)
467  {
468  for (int i = 0; i < m->msg_count; i++)
469  {
470  if (!m->emails[i])
471  break;
472  email_free(&m->emails[i]);
473  }
474  }
475 }
476 
483 static int sync_mailbox(struct Mailbox *m)
484 {
485  if (!m || !m->mx_ops || !m->mx_ops->mbox_sync)
486  return -1;
487 
488  if (m->verbose)
489  {
490  /* L10N: Displayed before/as a mailbox is being synced */
491  mutt_message(_("Writing %s..."), mailbox_path(m));
492  }
493 
494  int rc = m->mx_ops->mbox_sync(m);
495  if (rc != 0)
496  {
497  mutt_debug(LL_DEBUG2, "mbox_sync returned: %d\n", rc);
498  if ((rc < 0) && m->verbose)
499  {
500  /* L10N: Displayed if a mailbox sync fails */
501  mutt_error(_("Unable to write %s"), mailbox_path(m));
502  }
503  }
504 
505  return rc;
506 }
507 
514 static int trash_append(struct Mailbox *m)
515 {
516  if (!m)
517  return -1;
518 
519  struct stat st, stc;
520  int opt_confappend, rc;
521 
522  if (!C_Trash || (m->msg_deleted == 0) || ((m->type == MUTT_MAILDIR) && C_MaildirTrash))
523  {
524  return 0;
525  }
526 
527  int delmsgcount = 0;
528  int first_del = -1;
529  for (int i = 0; i < m->msg_count; i++)
530  {
531  struct Email *e = m->emails[i];
532  if (!e)
533  break;
534 
535  if (e->deleted && !e->purge)
536  {
537  if (first_del < 0)
538  first_del = i;
539  delmsgcount++;
540  }
541  }
542 
543  if (delmsgcount == 0)
544  return 0; /* nothing to be done */
545 
546  /* avoid the "append messages" prompt */
547  opt_confappend = C_Confirmappend;
548  if (opt_confappend)
549  C_Confirmappend = false;
550  rc = mutt_save_confirm(C_Trash, &st);
551  if (opt_confappend)
552  C_Confirmappend = true;
553  if (rc != 0)
554  {
555  /* L10N: Although we know the precise number of messages, we do not show it to the user.
556  So feel free to use a "generic plural" as plural translation if your language has one. */
557  mutt_error(ngettext("message not deleted", "messages not deleted", delmsgcount));
558  return -1;
559  }
560 
561  if ((lstat(mailbox_path(m), &stc) == 0) && (stc.st_ino == st.st_ino) &&
562  (stc.st_dev == st.st_dev) && (stc.st_rdev == st.st_rdev))
563  {
564  return 0; /* we are in the trash folder: simple sync */
565  }
566 
567 #ifdef USE_IMAP
568  if ((m->type == MUTT_IMAP) && (imap_path_probe(C_Trash, NULL) == MUTT_IMAP))
569  {
570  if (imap_fast_trash(m, C_Trash) == 0)
571  return 0;
572  }
573 #endif
574 
575  struct Mailbox *m_trash = mx_path_resolve(C_Trash);
576  const bool old_append = m_trash->append;
577  struct Context *ctx_trash = mx_mbox_open(m_trash, MUTT_APPEND);
578  if (ctx_trash)
579  {
580  /* continue from initial scan above */
581  for (int i = first_del; i < m->msg_count; i++)
582  {
583  struct Email *e = m->emails[i];
584  if (!e)
585  break;
586 
587  if (e->deleted && !e->purge)
588  {
589  if (mutt_append_message(ctx_trash->mailbox, m, e, MUTT_CM_NO_FLAGS, CH_NO_FLAGS) == -1)
590  {
591  mx_mbox_close(&ctx_trash);
592  m_trash->append = old_append;
593  return -1;
594  }
595  }
596  }
597 
598  mx_mbox_close(&ctx_trash);
599  m_trash->append = old_append;
600  }
601  else
602  {
603  mutt_error(_("Can't open trash folder"));
604  mailbox_free(&m_trash);
605  return -1;
606  }
607 
608  return 0;
609 }
610 
630 int mx_mbox_close(struct Context **ptr)
631 {
632  if (!ptr || !*ptr)
633  return 0;
634 
635  struct Context *ctx = *ptr;
636  if (!ctx || !ctx->mailbox)
637  return -1;
638 
639  struct Mailbox *m = ctx->mailbox;
640 
641  if (C_MailCheckRecent && !m->peekonly)
642  m->has_new = false;
643 
644  if (m->readonly || m->dontwrite || m->append || m->peekonly)
645  {
647  ctx_free(ptr);
648  return 0;
649  }
650 
651  int i, read_msgs = 0;
652  int rc = -1;
653  enum QuadOption move_messages = MUTT_NO;
654  enum QuadOption purge = MUTT_YES;
655  struct Buffer *mbox = NULL;
656  struct Buffer *buf = mutt_buffer_pool_get();
657 
658 #ifdef USE_NNTP
659  if ((m->msg_unread != 0) && (m->type == MUTT_NNTP))
660  {
661  struct NntpMboxData *mdata = m->mdata;
662 
663  if (mdata && mdata->adata && mdata->group)
664  {
665  enum QuadOption ans =
666  query_quadoption(C_CatchupNewsgroup, _("Mark all articles read?"));
667  if (ans == MUTT_ABORT)
668  goto cleanup;
669  if (ans == MUTT_YES)
670  mutt_newsgroup_catchup(m, mdata->adata, mdata->group);
671  }
672  }
673 #endif
674 
675  for (i = 0; i < m->msg_count; i++)
676  {
677  struct Email *e = m->emails[i];
678  if (!e)
679  break;
680 
681  if (!e->deleted && e->read && !(e->flagged && C_KeepFlagged))
682  read_msgs++;
683  }
684 
685 #ifdef USE_NNTP
686  /* don't need to move articles from newsgroup */
687  if (m->type == MUTT_NNTP)
688  read_msgs = 0;
689 #endif
690 
691  if ((read_msgs != 0) && (C_Move != MUTT_NO))
692  {
693  bool is_spool;
694  mbox = mutt_buffer_pool_get();
695 
697  if (p)
698  {
699  is_spool = true;
700  mutt_buffer_strcpy(mbox, p);
701  }
702  else
703  {
704  mutt_buffer_strcpy(mbox, C_Mbox);
705  is_spool = mutt_is_spool(mailbox_path(m)) && !mutt_is_spool(mutt_b2s(mbox));
706  }
707 
708  if (is_spool && !mutt_buffer_is_empty(mbox))
709  {
711  mutt_buffer_printf(buf,
712  /* L10N: The first argument is the number of read messages to be
713  moved, the second argument is the target mailbox. */
714  ngettext("Move %d read message to %s?",
715  "Move %d read messages to %s?", read_msgs),
716  read_msgs, mutt_b2s(mbox));
717  move_messages = query_quadoption(C_Move, mutt_b2s(buf));
718  if (move_messages == MUTT_ABORT)
719  goto cleanup;
720  }
721  }
722 
723  /* There is no point in asking whether or not to purge if we are
724  * just marking messages as "trash". */
725  if ((m->msg_deleted != 0) && !((m->type == MUTT_MAILDIR) && C_MaildirTrash))
726  {
727  mutt_buffer_printf(buf,
728  ngettext("Purge %d deleted message?",
729  "Purge %d deleted messages?", m->msg_deleted),
730  m->msg_deleted);
731  purge = query_quadoption(C_Delete, mutt_b2s(buf));
732  if (purge == MUTT_ABORT)
733  goto cleanup;
734  }
735 
736  if (C_MarkOld && !m->peekonly)
737  {
738  for (i = 0; i < m->msg_count; i++)
739  {
740  struct Email *e = m->emails[i];
741  if (!e)
742  break;
743  if (!e->deleted && !e->old && !e->read)
744  mutt_set_flag(m, e, MUTT_OLD, true);
745  }
746  }
747 
748  if (move_messages)
749  {
750  if (m->verbose)
751  mutt_message(_("Moving read messages to %s..."), mutt_b2s(mbox));
752 
753 #ifdef USE_IMAP
754  /* try to use server-side copy first */
755  i = 1;
756 
757  if ((m->type == MUTT_IMAP) && (imap_path_probe(mutt_b2s(mbox), NULL) == MUTT_IMAP))
758  {
759  /* add messages for moving, and clear old tags, if any */
760  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
761  for (i = 0; i < m->msg_count; i++)
762  {
763  struct Email *e = m->emails[i];
764  if (!e)
765  break;
766 
767  if (e->read && !e->deleted && !(e->flagged && C_KeepFlagged))
768  {
769  e->tagged = true;
770  emaillist_add_email(&el, e);
771  }
772  else
773  e->tagged = false;
774  }
775 
776  i = imap_copy_messages(ctx->mailbox, &el, mutt_b2s(mbox), true);
777  emaillist_clear(&el);
778  }
779 
780  if (i == 0) /* success */
782  else if (i == -1) /* horrible error, bail */
783  goto cleanup;
784  else /* use regular append-copy mode */
785 #endif
786  {
787  struct Mailbox *m_read = mx_path_resolve(mutt_b2s(mbox));
788  struct Context *ctx_read = mx_mbox_open(m_read, MUTT_APPEND);
789  if (!ctx_read)
790  {
791  mailbox_free(&m_read);
792  goto cleanup;
793  }
794 
795  for (i = 0; i < m->msg_count; i++)
796  {
797  struct Email *e = m->emails[i];
798  if (!e)
799  break;
800  if (e->read && !e->deleted && !(e->flagged && C_KeepFlagged))
801  {
802  if (mutt_append_message(ctx_read->mailbox, ctx->mailbox, e,
804  {
805  mutt_set_flag(m, e, MUTT_DELETE, true);
806  mutt_set_flag(m, e, MUTT_PURGE, true);
807  }
808  else
809  {
810  mx_mbox_close(&ctx_read);
811  goto cleanup;
812  }
813  }
814  }
815 
816  mx_mbox_close(&ctx_read);
817  }
818  }
819  else if (!m->changed && (m->msg_deleted == 0))
820  {
821  if (m->verbose)
822  mutt_message(_("Mailbox is unchanged"));
823  if ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF))
824  mbox_reset_atime(m, NULL);
826  ctx_free(ptr);
827  rc = 0;
828  goto cleanup;
829  }
830 
831  /* copy mails to the trash before expunging */
832  const struct Mailbox *m_trash = mx_mbox_find(m->account, C_Trash);
833  if (purge && (m->msg_deleted != 0) && (m != m_trash))
834  {
835  if (trash_append(ctx->mailbox) != 0)
836  goto cleanup;
837  }
838 
839 #ifdef USE_IMAP
840  /* allow IMAP to preserve the deleted flag across sessions */
841  if (m->type == MUTT_IMAP)
842  {
843  int check = imap_sync_mailbox(ctx->mailbox, (purge != MUTT_NO), true);
844  if (check < 0)
845  {
846  rc = check;
847  goto cleanup;
848  }
849  }
850  else
851 #endif
852  {
853  if (purge == MUTT_NO)
854  {
855  for (i = 0; i < m->msg_count; i++)
856  {
857  struct Email *e = m->emails[i];
858  if (!e)
859  break;
860 
861  e->deleted = false;
862  e->purge = false;
863  }
864  m->msg_deleted = 0;
865  }
866 
867  if (m->changed || (m->msg_deleted != 0))
868  {
869  int check = sync_mailbox(ctx->mailbox);
870  if (check != 0)
871  {
872  rc = check;
873  goto cleanup;
874  }
875  }
876  }
877 
878  if (m->verbose)
879  {
880  if (move_messages)
881  {
882  mutt_message(_("%d kept, %d moved, %d deleted"),
883  m->msg_count - m->msg_deleted, read_msgs, m->msg_deleted);
884  }
885  else
886  mutt_message(_("%d kept, %d deleted"), m->msg_count - m->msg_deleted, m->msg_deleted);
887  }
888 
889  if ((m->msg_count == m->msg_deleted) &&
890  ((m->type == MUTT_MMDF) || (m->type == MUTT_MBOX)) &&
892  {
894  }
895 
896 #ifdef USE_SIDEBAR
897  if ((purge == MUTT_YES) && (m->msg_deleted != 0))
898  {
899  for (i = 0; i < m->msg_count; i++)
900  {
901  struct Email *e = m->emails[i];
902  if (!e)
903  break;
904  if (e->deleted && !e->read)
905  {
906  m->msg_unread--;
907  if (!e->old)
908  m->msg_new--;
909  }
910  if (e->deleted && e->flagged)
911  m->msg_flagged--;
912  }
913  }
914 #endif
915 
917  ctx_free(ptr);
918 
919  rc = 0;
920 
921 cleanup:
924  return rc;
925 }
926 
937 int mx_mbox_sync(struct Mailbox *m)
938 {
939  if (!m)
940  return -1;
941 
942  int rc;
943  int purge = 1;
944  int msgcount, deleted;
945 
946  if (m->dontwrite)
947  {
948  char buf[256], tmp[256];
949  if (km_expand_key(buf, sizeof(buf), km_find_func(MENU_MAIN, OP_TOGGLE_WRITE)))
950  snprintf(tmp, sizeof(tmp), _(" Press '%s' to toggle write"), buf);
951  else
952  mutt_str_copy(tmp, _("Use 'toggle-write' to re-enable write"), sizeof(tmp));
953 
954  mutt_error(_("Mailbox is marked unwritable. %s"), tmp);
955  return -1;
956  }
957  else if (m->readonly)
958  {
959  mutt_error(_("Mailbox is read-only"));
960  return -1;
961  }
962 
963  if (!m->changed && (m->msg_deleted == 0))
964  {
965  if (m->verbose)
966  mutt_message(_("Mailbox is unchanged"));
967  return 0;
968  }
969 
970  if (m->msg_deleted != 0)
971  {
972  char buf[128];
973 
974  snprintf(buf, sizeof(buf),
975  ngettext("Purge %d deleted message?", "Purge %d deleted messages?", m->msg_deleted),
976  m->msg_deleted);
977  purge = query_quadoption(C_Delete, buf);
978  if (purge == MUTT_ABORT)
979  return -1;
980  if (purge == MUTT_NO)
981  {
982  if (!m->changed)
983  return 0; /* nothing to do! */
984  /* let IMAP servers hold on to D flags */
985  if (m->type != MUTT_IMAP)
986  {
987  for (int i = 0; i < m->msg_count; i++)
988  {
989  struct Email *e = m->emails[i];
990  if (!e)
991  break;
992  e->deleted = false;
993  e->purge = false;
994  }
995  m->msg_deleted = 0;
996  }
997  }
999  }
1000 
1001  /* really only for IMAP - imap_sync_mailbox results in a call to
1002  * ctx_update_tables, so m->msg_deleted is 0 when it comes back */
1003  msgcount = m->msg_count;
1004  deleted = m->msg_deleted;
1005 
1006  const struct Mailbox *m_trash = mx_mbox_find(m->account, C_Trash);
1007  if (purge && (m->msg_deleted != 0) && (m != m_trash))
1008  {
1009  if (trash_append(m) != 0)
1010  return -1;
1011  }
1012 
1013 #ifdef USE_IMAP
1014  if (m->type == MUTT_IMAP)
1015  rc = imap_sync_mailbox(m, purge, false);
1016  else
1017 #endif
1018  rc = sync_mailbox(m);
1019  if (rc >= 0)
1020  {
1021 #ifdef USE_IMAP
1022  if ((m->type == MUTT_IMAP) && !purge)
1023  {
1024  if (m->verbose)
1025  mutt_message(_("Mailbox checkpointed"));
1026  }
1027  else
1028 #endif
1029  {
1030  if (m->verbose)
1031  mutt_message(_("%d kept, %d deleted"), msgcount - deleted, deleted);
1032  }
1033 
1034  mutt_sleep(0);
1035 
1036  if ((m->msg_count == m->msg_deleted) &&
1037  ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) &&
1039  {
1040  unlink(mailbox_path(m));
1042  return 0;
1043  }
1044 
1045  /* if we haven't deleted any messages, we don't need to resort */
1046  /* ... except for certain folder formats which need "unsorted"
1047  * sort order in order to synchronize folders.
1048  *
1049  * MH and maildir are safe. mbox-style seems to need re-sorting,
1050  * at least with the new threading code. */
1051  if (purge || ((m->type != MUTT_MAILDIR) && (m->type != MUTT_MH)))
1052  {
1053  /* IMAP does this automatically after handling EXPUNGE */
1054  if (m->type != MUTT_IMAP)
1055  {
1058  }
1059  }
1060  }
1061 
1062  return rc;
1063 }
1064 
1072 struct Message *mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
1073 {
1074  if (!m)
1075  return NULL;
1076 
1077  struct Address *p = NULL;
1078  struct Message *msg = NULL;
1079 
1080  if (!m->mx_ops || !m->mx_ops->msg_open_new)
1081  {
1082  mutt_debug(LL_DEBUG1, "function unimplemented for mailbox type %d\n", m->type);
1083  return NULL;
1084  }
1085 
1086  msg = mutt_mem_calloc(1, sizeof(struct Message));
1087  msg->write = true;
1088 
1089  if (e)
1090  {
1091  msg->flags.flagged = e->flagged;
1092  msg->flags.replied = e->replied;
1093  msg->flags.read = e->read;
1094  msg->flags.draft = (flags & MUTT_SET_DRAFT);
1095  msg->received = e->received;
1096  }
1097 
1098  if (msg->received == 0)
1099  msg->received = mutt_date_epoch();
1100 
1101  if (m->mx_ops->msg_open_new(m, msg, e) == 0)
1102  {
1103  if (m->type == MUTT_MMDF)
1104  fputs(MMDF_SEP, msg->fp);
1105 
1106  if (((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) && (flags & MUTT_ADD_FROM))
1107  {
1108  if (e)
1109  {
1110  p = TAILQ_FIRST(&e->env->return_path);
1111  if (!p)
1112  p = TAILQ_FIRST(&e->env->sender);
1113  if (!p)
1114  p = TAILQ_FIRST(&e->env->from);
1115  }
1116 
1117  // Force a 'C' locale for the date, so that day/month names are in English
1118  locale_t loc = newlocale(LC_TIME_MASK, "C", 0);
1119  char buf[64] = { 0 };
1120  struct tm tm = mutt_date_localtime(msg->received);
1121  strftime_l(buf, sizeof(buf), "%a %b %e %H:%M:%S %Y", &tm, loc);
1122  freelocale(loc);
1123  fprintf(msg->fp, "From %s %s\n", p ? p->mailbox : NONULL(Username), buf);
1124  }
1125  }
1126  else
1127  FREE(&msg);
1128 
1129  return msg;
1130 }
1131 
1139 int mx_mbox_check(struct Mailbox *m)
1140 {
1141  if (!m || !m->mx_ops)
1142  return -1;
1143 
1144  int rc = m->mx_ops->mbox_check(m);
1145  if ((rc == MUTT_NEW_MAIL) || (rc == MUTT_REOPENED))
1147 
1148  return rc;
1149 }
1150 
1158 struct Message *mx_msg_open(struct Mailbox *m, int msgno)
1159 {
1160  if (!m || !m->emails || (msgno < 0) || (msgno >= m->msg_count))
1161  return NULL;
1162 
1163  if (!m->mx_ops || !m->mx_ops->msg_open)
1164  {
1165  mutt_debug(LL_DEBUG1, "function not implemented for mailbox type %d\n", m->type);
1166  return NULL;
1167  }
1168 
1169  struct Message *msg = mutt_mem_calloc(1, sizeof(struct Message));
1170  if (m->mx_ops->msg_open(m, msg, msgno) < 0)
1171  FREE(&msg);
1172 
1173  return msg;
1174 }
1175 
1183 int mx_msg_commit(struct Mailbox *m, struct Message *msg)
1184 {
1185  if (!m || !m->mx_ops || !m->mx_ops->msg_commit || !msg)
1186  return -1;
1187 
1188  if (!(msg->write && m->append))
1189  {
1190  mutt_debug(LL_DEBUG1, "msg->write = %d, m->append = %d\n", msg->write, m->append);
1191  return -1;
1192  }
1193 
1194  return m->mx_ops->msg_commit(m, msg);
1195 }
1196 
1204 int mx_msg_close(struct Mailbox *m, struct Message **msg)
1205 {
1206  if (!m || !msg || !*msg)
1207  return 0;
1208 
1209  int rc = 0;
1210 
1211  if (m->mx_ops && m->mx_ops->msg_close)
1212  rc = m->mx_ops->msg_close(m, *msg);
1213 
1214  if ((*msg)->path)
1215  {
1216  mutt_debug(LL_DEBUG1, "unlinking %s\n", (*msg)->path);
1217  unlink((*msg)->path);
1218  FREE(&(*msg)->path);
1219  }
1220 
1221  FREE(&(*msg)->committed_path);
1222  FREE(msg);
1223  return rc;
1224 }
1225 
1230 void mx_alloc_memory(struct Mailbox *m)
1231 {
1232  size_t s = MAX(sizeof(struct Email *), sizeof(int));
1233 
1234  if ((m->email_max + 25) * s < m->email_max * s)
1235  {
1236  mutt_error(_("Out of memory"));
1237  mutt_exit(1);
1238  }
1239 
1240  m->email_max += 25;
1241  if (m->emails)
1242  {
1243  mutt_mem_realloc(&m->emails, sizeof(struct Email *) * m->email_max);
1244  mutt_mem_realloc(&m->v2r, sizeof(int) * m->email_max);
1245  }
1246  else
1247  {
1248  m->emails = mutt_mem_calloc(m->email_max, sizeof(struct Email *));
1249  m->v2r = mutt_mem_calloc(m->email_max, sizeof(int));
1250  }
1251  for (int i = m->email_max - 25; i < m->email_max; i++)
1252  {
1253  m->emails[i] = NULL;
1254  m->v2r[i] = -1;
1255  }
1256 }
1257 
1265 int mx_path_is_empty(const char *path)
1266 {
1267  if (!path || (*path == '\0'))
1268  return -1;
1269 
1270  enum MailboxType type = mx_path_probe(path);
1271  const struct MxOps *ops = mx_get_ops(type);
1272  if (!ops || !ops->path_is_empty)
1273  return -1;
1274 
1275  return ops->path_is_empty(path);
1276 }
1277 
1288 int mx_tags_edit(struct Mailbox *m, const char *tags, char *buf, size_t buflen)
1289 {
1290  if (!m || !buf)
1291  return -1;
1292 
1293  if (m->mx_ops->tags_edit)
1294  return m->mx_ops->tags_edit(m, tags, buf, buflen);
1295 
1296  mutt_message(_("Folder doesn't support tagging, aborting"));
1297  return -1;
1298 }
1299 
1308 int mx_tags_commit(struct Mailbox *m, struct Email *e, char *tags)
1309 {
1310  if (!m || !e || !tags)
1311  return -1;
1312 
1313  if (m->mx_ops->tags_commit)
1314  return m->mx_ops->tags_commit(m, e, tags);
1315 
1316  mutt_message(_("Folder doesn't support tagging, aborting"));
1317  return -1;
1318 }
1319 
1326 {
1327  return m && m->mx_ops->tags_commit && m->mx_ops->tags_edit;
1328 }
1329 
1335 enum MailboxType mx_path_probe(const char *path)
1336 {
1337  if (!path)
1338  return MUTT_UNKNOWN;
1339 
1340  enum MailboxType rc;
1341 
1342  // First, search the non-local Mailbox types (is_local == false)
1343  for (const struct MxOps **ops = mx_ops; *ops; ops++)
1344  {
1345  if ((*ops)->is_local)
1346  continue;
1347  rc = (*ops)->path_probe(path, NULL);
1348  if (rc != MUTT_UNKNOWN)
1349  return rc;
1350  }
1351 
1352  struct stat st = { 0 };
1353  if (stat(path, &st) != 0)
1354  {
1355  mutt_debug(LL_DEBUG1, "unable to stat %s: %s (errno %d)\n", path, strerror(errno), errno);
1356  return MUTT_UNKNOWN;
1357  }
1358 
1359  if (S_ISFIFO(st.st_mode))
1360  {
1361  mutt_error(_("Can't open %s: it is a pipe"), path);
1362  return MUTT_UNKNOWN;
1363  }
1364 
1365  // Next, search the local Mailbox types (is_local == true)
1366  for (const struct MxOps **ops = mx_ops; *ops; ops++)
1367  {
1368  if (!(*ops)->is_local)
1369  continue;
1370  rc = (*ops)->path_probe(path, &st);
1371  if (rc != MUTT_UNKNOWN)
1372  return rc;
1373  }
1374 
1375  return rc;
1376 }
1377 
1381 int mx_path_canon(char *buf, size_t buflen, const char *folder, enum MailboxType *type)
1382 {
1383  if (!buf)
1384  return -1;
1385 
1386  for (size_t i = 0; i < 3; i++)
1387  {
1388  /* Look for !! ! - < > or ^ followed by / or NUL */
1389  if ((buf[0] == '!') && (buf[1] == '!'))
1390  {
1391  if (((buf[2] == '/') || (buf[2] == '\0')))
1392  {
1393  mutt_str_inline_replace(buf, buflen, 2, LastFolder);
1394  }
1395  }
1396  else if ((buf[0] == '+') || (buf[0] == '='))
1397  {
1398  size_t folder_len = mutt_str_len(folder);
1399  if ((folder_len > 0) && (folder[folder_len - 1] != '/'))
1400  {
1401  buf[0] = '/';
1402  mutt_str_inline_replace(buf, buflen, 0, folder);
1403  }
1404  else
1405  {
1406  mutt_str_inline_replace(buf, buflen, 1, folder);
1407  }
1408  }
1409  else if ((buf[1] == '/') || (buf[1] == '\0'))
1410  {
1411  if (buf[0] == '!')
1412  {
1413  mutt_str_inline_replace(buf, buflen, 1, C_Spoolfile);
1414  }
1415  else if (buf[0] == '-')
1416  {
1417  mutt_str_inline_replace(buf, buflen, 1, LastFolder);
1418  }
1419  else if (buf[0] == '<')
1420  {
1421  mutt_str_inline_replace(buf, buflen, 1, C_Record);
1422  }
1423  else if (buf[0] == '>')
1424  {
1425  mutt_str_inline_replace(buf, buflen, 1, C_Mbox);
1426  }
1427  else if (buf[0] == '^')
1428  {
1429  mutt_str_inline_replace(buf, buflen, 1, CurrentFolder);
1430  }
1431  else if (buf[0] == '~')
1432  {
1433  mutt_str_inline_replace(buf, buflen, 1, HomeDir);
1434  }
1435  }
1436  else if (buf[0] == '@')
1437  {
1438  /* elm compatibility, @ expands alias to user name */
1439  struct AddressList *al = alias_lookup(buf + 1);
1440  if (!al || TAILQ_EMPTY(al))
1441  break;
1442 
1443  struct Email *e = email_new();
1444  e->env = mutt_env_new();
1445  mutt_addrlist_copy(&e->env->from, al, false);
1446  mutt_addrlist_copy(&e->env->to, al, false);
1447  mutt_default_save(buf, buflen, e);
1448  email_free(&e);
1449  break;
1450  }
1451  else
1452  {
1453  break;
1454  }
1455  }
1456 
1457  // if (!folder) //XXX - use inherited version, or pass NULL to backend?
1458  // return -1;
1459 
1460  enum MailboxType type2 = mx_path_probe(buf);
1461  if (type)
1462  *type = type2;
1463  const struct MxOps *ops = mx_get_ops(type2);
1464  if (!ops || !ops->path_canon)
1465  return -1;
1466 
1467  if (ops->path_canon(buf, buflen) < 0)
1468  {
1469  mutt_path_canon(buf, buflen, HomeDir, true);
1470  }
1471 
1472  return 0;
1473 }
1474 
1482 int mx_path_canon2(struct Mailbox *m, const char *folder)
1483 {
1484  if (!m)
1485  return -1;
1486 
1487  char buf[PATH_MAX];
1488 
1489  if (m->realpath)
1490  mutt_str_copy(buf, m->realpath, sizeof(buf));
1491  else
1492  mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
1493 
1494  int rc = mx_path_canon(buf, sizeof(buf), folder, &m->type);
1495 
1496  mutt_str_replace(&m->realpath, buf);
1497 
1498  if (rc >= 0)
1499  {
1500  m->mx_ops = mx_get_ops(m->type);
1502  }
1503 
1504  return rc;
1505 }
1506 
1510 int mx_path_pretty(char *buf, size_t buflen, const char *folder)
1511 {
1512  if (!buf)
1513  return -1;
1514 
1515  enum MailboxType type = mx_path_probe(buf);
1516  const struct MxOps *ops = mx_get_ops(type);
1517  if (!ops)
1518  return -1;
1519 
1520  if (!ops->path_canon)
1521  return -1;
1522 
1523  if (ops->path_canon(buf, buflen) < 0)
1524  return -1;
1525 
1526  if (!ops->path_pretty)
1527  return -1;
1528 
1529  if (ops->path_pretty(buf, buflen, folder) < 0)
1530  return -1;
1531 
1532  return 0;
1533 }
1534 
1538 int mx_path_parent(char *buf, size_t buflen)
1539 {
1540  if (!buf)
1541  return -1;
1542 
1543  return 0;
1544 }
1545 
1555 {
1556  if (!m || !m->mx_ops || !m->mx_ops->msg_padding_size)
1557  return 0;
1558 
1559  return m->mx_ops->msg_padding_size(m);
1560 }
1561 
1568 struct Account *mx_ac_find(struct Mailbox *m)
1569 {
1570  if (!m || !m->mx_ops || !m->realpath)
1571  return NULL;
1572 
1573  struct Account *np = NULL;
1574  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1575  {
1576  if (np->type != m->type)
1577  continue;
1578 
1579  if (m->mx_ops->ac_find(np, m->realpath))
1580  return np;
1581  }
1582 
1583  return NULL;
1584 }
1585 
1592 struct Mailbox *mx_mbox_find(struct Account *a, const char *path)
1593 {
1594  if (!a || !path)
1595  return NULL;
1596 
1597  struct MailboxNode *np = NULL;
1598  struct Url *url_p = NULL;
1599  struct Url *url_a = NULL;
1600 
1601  const bool use_url = (a->type == MUTT_IMAP);
1602  if (use_url)
1603  {
1604  url_p = url_parse(path);
1605  if (!url_p)
1606  goto done;
1607  }
1608 
1609  STAILQ_FOREACH(np, &a->mailboxes, entries)
1610  {
1611  if (!use_url)
1612  {
1613  if (mutt_str_equal(np->mailbox->realpath, path))
1614  return np->mailbox;
1615  continue;
1616  }
1617 
1618  url_free(&url_a);
1619  url_a = url_parse(np->mailbox->realpath);
1620  if (!url_a)
1621  continue;
1622 
1623  if (!mutt_istr_equal(url_a->host, url_p->host))
1624  continue;
1625  if (url_p->user && !mutt_istr_equal(url_a->user, url_p->user))
1626  continue;
1627  if (a->type == MUTT_IMAP)
1628  {
1629  if (imap_mxcmp(url_a->path, url_p->path) == 0)
1630  break;
1631  }
1632  else
1633  {
1634  if (mutt_str_equal(url_a->path, url_p->path))
1635  break;
1636  }
1637  }
1638 
1639 done:
1640  url_free(&url_p);
1641  url_free(&url_a);
1642 
1643  if (!np)
1644  return NULL;
1645  return np->mailbox;
1646 }
1647 
1654 struct Mailbox *mx_mbox_find2(const char *path)
1655 {
1656  if (!path)
1657  return NULL;
1658 
1659  char buf[PATH_MAX];
1660  mutt_str_copy(buf, path, sizeof(buf));
1661  mx_path_canon(buf, sizeof(buf), C_Folder, NULL);
1662 
1663  struct Account *np = NULL;
1664  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1665  {
1666  struct Mailbox *m = mx_mbox_find(np, buf);
1667  if (m)
1668  return m;
1669  }
1670 
1671  return NULL;
1672 }
1673 
1681 struct Mailbox *mx_path_resolve(const char *path)
1682 {
1683  if (!path)
1684  return NULL;
1685 
1686  struct Mailbox *m = mx_mbox_find2(path);
1687  if (m)
1688  return m;
1689 
1690  m = mailbox_new();
1691  m->flags = MB_HIDDEN;
1692  mutt_buffer_strcpy(&m->pathbuf, path);
1694 
1695  return m;
1696 }
1697 
1704 static struct Mailbox *mx_mbox_find_by_name_ac(struct Account *a, const char *name)
1705 {
1706  if (!a || !name)
1707  return NULL;
1708 
1709  struct MailboxNode *np = NULL;
1710 
1711  STAILQ_FOREACH(np, &a->mailboxes, entries)
1712  {
1713  if (mutt_str_equal(np->mailbox->name, name))
1714  return np->mailbox;
1715  }
1716 
1717  return NULL;
1718 }
1719 
1725 static struct Mailbox *mx_mbox_find_by_name(const char *name)
1726 {
1727  if (!name)
1728  return NULL;
1729 
1730  struct Account *np = NULL;
1731  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1732  {
1733  struct Mailbox *m = mx_mbox_find_by_name_ac(np, name);
1734  if (m)
1735  return m;
1736  }
1737 
1738  return NULL;
1739 }
1740 
1750 struct Mailbox *mx_resolve(const char *path_or_name)
1751 {
1752  if (!path_or_name)
1753  return NULL;
1754 
1755  // Order is name first because you can create a Mailbox from
1756  // a path, but can't from a name. So fallback behavior creates
1757  // a new Mailbox for us.
1758  struct Mailbox *m = mx_mbox_find_by_name(path_or_name);
1759  if (!m)
1760  m = mx_path_resolve(path_or_name);
1761 
1762  return m;
1763 }
1764 
1768 int mx_ac_add(struct Account *a, struct Mailbox *m)
1769 {
1770  if (!a || !m || !m->mx_ops || !m->mx_ops->ac_add)
1771  return -1;
1772 
1773  if (m->mx_ops->ac_add(a, m) < 0)
1774  return -1;
1775 
1776  account_mailbox_add(a, m);
1777  return 0;
1778 }
1779 
1784 int mx_ac_remove(struct Mailbox *m)
1785 {
1786  if (!m || !m->account)
1787  return -1;
1788 
1789  struct Account *a = m->account;
1791  mailbox_free(&m);
1792  if (STAILQ_EMPTY(&a->mailboxes))
1793  {
1795  }
1796  return 0;
1797 }
1798 
1802 int mx_mbox_check_stats(struct Mailbox *m, int flags)
1803 {
1804  if (!m)
1805  return -1;
1806 
1807  return m->mx_ops->mbox_check_stats(m, flags);
1808 }
1809 
1819 int mx_save_hcache(struct Mailbox *m, struct Email *e)
1820 {
1821  if (!m || !m->mx_ops || !m->mx_ops->msg_save_hcache || !e)
1822  return 0;
1823 
1824  return m->mx_ops->msg_save_hcache(m, e);
1825 }
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mx.h:53
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
Convenience wrapper for the gui headers.
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:416
int mx_path_is_empty(const char *path)
Is the mailbox empty.
Definition: mx.c:1265
The "current" mailbox.
Definition: context.h:38
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:203
#define MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn&#39;t exist.
Definition: mx.h:60
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:297
int(* msg_commit)(struct Mailbox *m, struct Message *msg)
Save changes to an email.
Definition: mx.h:246
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:67
off_t size
Size of the Mailbox.
Definition: mailbox.h:87
Representation of the email&#39;s header.
int msg_in_pager
Message currently shown in the pager.
Definition: context.h:44
IMAP network mailbox.
bool C_MarkOld
Config: Mark new emails as old when leaving the mailbox.
Definition: globals.c:36
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
#define TAILQ_FIRST(head)
Definition: queue.h:716
#define mutt_perror(...)
Definition: logging.h:85
Clear the &#39;last-tagged&#39; pointer.
Definition: mailbox.h:177
WHERE bool C_SaveEmpty
Config: (mbox,mmdf) Preserve empty mailboxes.
Definition: mutt_globals.h:158
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe()
Definition: imap.c:2367
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
Update internal tables.
Definition: mailbox.h:176
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:96
int msg_unread
Number of unread messages.
Definition: mailbox.h:92
int mx_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Wrapper for MxOps::ac_add()
Definition: mx.c:1768
int mx_path_canon2(struct Mailbox *m, const char *folder)
Canonicalise the path to realpath.
Definition: mx.c:1482
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:52
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:630
Structs that make up an email.
void mbox_reset_atime(struct Mailbox *m, struct stat *st)
Reset the access time on the mailbox file.
Definition: mbox.c:837
struct MxOps MxNotmuchOps
Notmuch Mailbox - Implements MxOps.
Definition: notmuch.c:2655
The "currently-open" mailbox.
struct MxOps MxMhOps
MH Mailbox - Implements MxOps.
Definition: mh.c:1245
int(* mbox_check_stats)(struct Mailbox *m, int flags)
Check the Mailbox statistics.
Definition: mx.h:182
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:643
bool replied
Definition: mx.h:92
int mx_path_pretty(char *buf, size_t buflen, const char *folder)
Abbreviate a mailbox path - Wrapper for MxOps::path_pretty()
Definition: mx.c:1510
struct HashTable * label_hash
Hash Table for x-labels.
Definition: mailbox.h:129
struct MxOps MxCompOps
Compressed Mailbox - Implements MxOps.
Definition: compress.c:932
int mx_path_parent(char *buf, size_t buflen)
Find the parent of a mailbox path - Wrapper for MxOps::path_parent()
Definition: mx.c:1538
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:447
#define mutt_message(...)
Definition: logging.h:83
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:93
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:66
static int sync_mailbox(struct Mailbox *m)
save changes to disk
Definition: mx.c:483
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:40
int emaillist_add_email(struct EmailList *el, struct Email *e)
Add an Email to a list.
Definition: email.c:151
static struct Mailbox * mx_mbox_find_by_name(const char *name)
Find a Mailbox with given name.
Definition: mx.c:1725
void mutt_sort_headers(struct Mailbox *m, struct ThreadsContext *threads, bool init, off_t *vsize)
Sort emails by their headers.
Definition: sort.c:366
static int trash_append(struct Mailbox *m)
move deleted mails to the trash folder
Definition: mx.c:514
bool peekonly
Just taking a glance, revert atime.
Definition: mailbox.h:117
struct NntpAccountData * adata
Definition: lib.h:153
enum UrlScheme scheme
Scheme, e.g. U_SMTPS.
Definition: url.h:68
unsigned char C_Move
Config: Move emails from $spoolfile to $mbox when read.
Definition: mx.c:85
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
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:737
struct MailboxList mailboxes
List of Mailboxes.
Definition: account.h:41
struct ThreadsContext * threads
Threads context.
Definition: context.h:43
A group of associated Mailboxes.
Definition: account.h:36
struct MxOps MxMaildirOps
Maildir Mailbox - Implements MxOps.
Definition: maildir.c:1632
String manipulation buffer.
Definition: buffer.h:33
void mx_alloc_memory(struct Mailbox *m)
Create storage for the emails.
Definition: mx.c:1230
#define _(a)
Definition: message.h:28
Mailbox wasn&#39;t recognised.
Definition: mailbox.h:47
Error occurred examining Mailbox.
Definition: mailbox.h:46
An email address.
Definition: address.h:34
struct MxOps MxNntpOps
NNTP Mailbox - Implements MxOps.
Definition: nntp.c:2834
struct Mailbox * mx_mbox_find(struct Account *a, const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1592
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:1704
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:303
char * mailbox
Mailbox and host address.
Definition: address.h:37
Messages to be purged (bypass trash)
Definition: mutt.h:100
int(* ac_add)(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account.
Definition: mx.h:134
Index panel (list of emails)
Definition: keymap.h:80
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mx.h:50
int(* path_is_empty)(const char *path)
Is the Mailbox empty?
Definition: mx.h:373
Email list was changed.
Definition: mailbox.h:173
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:123
#define MUTT_READONLY
Open in read-only mode.
Definition: mx.h:54
enum MailboxType type
Type of Mailboxes this Account contains.
Definition: account.h:38
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:1819
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1654
WHERE bool OptNeedRescore
(pseudo) set when the &#39;score&#39; command is used
Definition: options.h:42
struct Account * mx_ac_find(struct Mailbox *m)
Find the Account owning a Mailbox.
Definition: mx.c:1568
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:654
All user-callable functions.
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:34
Container for Accounts, Notifications.
Definition: neomutt.h:36
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1349
int vcount
The number of virtual messages.
Definition: mailbox.h:102
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:66
int mx_mbox_sync(struct Mailbox *m)
Save changes to mailbox.
Definition: mx.c:937
int imap_sync_mailbox(struct Mailbox *m, bool expunge, bool close)
Sync all the changes to the server.
Definition: imap.c:1506
char * HomeDir
User&#39;s home directory.
Definition: mutt_globals.h:49
Email Address Handling.
Assorted sorting methods.
WHERE char * Username
User&#39;s login name.
Definition: mutt_globals.h:52
int(* mbox_open)(struct Mailbox *m)
Open a Mailbox.
Definition: mx.h:146
int(* mbox_open_append)(struct Mailbox *m, OpenMailboxFlags flags)
Open a Mailbox for appending.
Definition: mx.h:158
Some miscellaneous functions.
#define MAX(a, b)
Definition: memory.h:30
bool has_new
Mailbox has new mail.
Definition: mailbox.h:88
char * C_Trash
Config: Folder to put deleted emails.
Definition: mx.c:86
int(* path_canon)(char *buf, size_t buflen)
Canonicalise a Mailbox path.
Definition: mx.h:336
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1204
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:1446
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1072
struct Mailbox * mailbox
Definition: context.h:50
struct HashTable * id_hash
Hash Table by msg id.
Definition: mailbox.h:127
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:63
#define MUTT_PEEK
Revert atime back after taking a look (if applicable)
Definition: mx.h:59
void mutt_file_unlink_empty(const char *path)
Delete a file if it&#39;s empty.
Definition: file.c:1311
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:276
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:119
The Context has been opened.
Definition: context.h:61
struct Mailbox * mx_resolve(const char *path_or_name)
Get a Mailbox from either a path or name.
Definition: mx.c:1750
struct Envelope * env
Envelope information.
Definition: email.h:90
Convenience wrapper for the core headers.
int mx_tags_commit(struct Mailbox *m, struct Email *e, char *tags)
Save tags to the Mailbox - Wrapper for MxOps::tags_commit()
Definition: mx.c:1308
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:445
struct MxOps MxImapOps
IMAP Mailbox - Implements MxOps.
Definition: imap.c:2454
char * group
Definition: lib.h:140
struct MxOps MxPopOps
POP Mailbox - Implements MxOps.
Definition: pop.c:1245
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:113
User aborted the question (with Ctrl-G)
Definition: quad.h:38
unsigned char C_CatchupNewsgroup
Config: (nntp) Mark all articles as read when leaving a newsgroup.
Definition: config.c:37
Compressed mbox local mailbox type.
int(* msg_padding_size)(struct Mailbox *m)
Bytes of padding between messages.
Definition: mx.h:269
void * mdata
Driver specific data.
Definition: mailbox.h:136
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:169
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
struct HashTable * subj_hash
Hash Table by subject.
Definition: mailbox.h:128
#define MUTT_MBOX_HOOK
mbox-hook: move messages after reading them
Definition: hook.h:46
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:51
Usenet network mailbox type; talk to an NNTP server.
int flags
e.g. MB_NORMAL
Definition: mailbox.h:134
enum MailboxType type
Mailbox type, e.g. MUTT_IMAP.
Definition: mx.h:106
int imap_mxcmp(const char *mx1, const char *mx2)
Compare mailbox names, giving priority to INBOX.
Definition: util.c:689
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
struct Keymap * km_find_func(enum MenuType menu, int func)
Find a function&#39;s mapping in a Menu.
Definition: keymap.c:939
Old messages.
Definition: mutt.h:94
off_t vsize
Size (in bytes) of the messages shown.
Definition: context.h:40
Email list needs resorting.
Definition: mailbox.h:174
#define mutt_b2s(buf)
Definition: buffer.h:41
int(* mbox_check)(struct Mailbox *m)
Check for new mail.
Definition: mx.h:169
WHERE bool OptForceRefresh
(pseudo) refresh even during macros
Definition: options.h:37
Prototypes for many functions.
#define MB_HIDDEN
Definition: mailbox.h:38
Notmuch virtual mailbox type.
int(* tags_edit)(struct Mailbox *m, const char *tags, char *buf, size_t buflen)
Prompt and validate new messages tags.
Definition: mx.h:298
struct Context * ctx_new(struct Mailbox *m)
Create a new Context.
Definition: context.c:76
bool flagged
Definition: mx.h:91
A local copy of an email.
Definition: mx.h:82
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
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:1560
void ctx_update(struct Context *ctx)
Update the Context&#39;s message counts.
Definition: context.c:112
struct Message::@0 flags
int imap_access(const char *path)
Check permissions on an IMAP mailbox with a new connection.
Definition: imap.c:467
Messages to be deleted.
Definition: mutt.h:98
A mailbox.
Definition: mailbox.h:81
#define PATH_MAX
Definition: mutt.h:44
char * mutt_find_hook(HookFlags type, const char *pat)
Find a matching hook.
Definition: hook.c:552
char * user
Username.
Definition: url.h:69
#define MUTT_NOSORT
Do not sort the mailbox after opening it.
Definition: mx.h:52
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:50
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:911
struct MxOps MxMmdfOps
MMDF Mailbox - Implements MxOps.
Definition: mbox.c:1844
int(* mbox_sync)(struct Mailbox *m)
Save changes to the Mailbox.
Definition: mx.h:193
bool dontwrite
Don&#39;t write the mailbox on close.
Definition: mailbox.h:115
int(* msg_save_hcache)(struct Mailbox *m, struct Email *e)
Save message to the header cache.
Definition: mx.h:282
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: mutt_globals.h:96
&#39;mmdf&#39; Mailbox type
Definition: mailbox.h:49
int(* msg_open)(struct Mailbox *m, struct Message *msg, int msgno)
Open an email message in a Mailbox.
Definition: mx.h:219
POP network mailbox.
Compressed file Mailbox type.
Definition: mailbox.h:56
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
const struct MxOps * mx_ops
MXAPI callback functions.
Definition: mailbox.h:111
char * host
Host.
Definition: url.h:71
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
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:1288
unsigned char C_MboxType
Config: Default type for creating new mailboxes.
Definition: mx.c:84
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:97
WHERE bool C_MailCheckRecent
Config: Notify the user about new mail since the last time the mailbox was opened.
Definition: mutt_globals.h:150
bool draft
Definition: mx.h:93
#define MUTT_QUIET
Do not print any messages.
Definition: mx.h:55
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:121
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
struct Account * account_new(const char *name, struct ConfigSubset *sub)
Create a new Account.
Definition: account.c:43
int mx_mbox_check(struct Mailbox *m)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1139
uint8_t MsgOpenFlags
Flags for mx_msg_open_new(), e.g. MUTT_ADD_FROM.
Definition: mx.h:63
NNTP-specific Mailbox data -.
Definition: lib.h:138
Maildir local mailbox type.
#define MMDF_SEP
Definition: lib.h:64
WHERE char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:55
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:73
&#39;mbox&#39; Mailbox type
Definition: mailbox.h:48
bool write
nonzero if message is open for writing
Definition: mx.h:87
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:137
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
void mutt_make_label_hash(struct Mailbox *m)
Create a Hash Table to store the labels.
Definition: mutt_header.c:365
WHERE char * C_Record
Config: Folder to save &#39;sent&#39; messages.
Definition: mutt_globals.h:98
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:517
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
struct Mailbox * mailbox_new(void)
Create a new Mailbox.
Definition: mailbox.c:42
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1335
WHERE unsigned char C_Delete
Config: Really delete messages, when the mailbox is closed.
Definition: mutt_globals.h:125
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
Context has changed, NotifyContext, EventContext.
Definition: notify_type.h:38
Duplicate the structure of an entire email.
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:323
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
WHERE char * C_Spoolfile
Config: Inbox.
Definition: mutt_globals.h:108
Log at debug level 1.
Definition: logging.h:40
bool flagged
Marked important?
Definition: email.h:43
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:130
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:716
int(* msg_open_new)(struct Mailbox *m, struct Message *msg, const struct Email *e)
Open a new message in a Mailbox.
Definition: mx.h:233
int(* mbox_close)(struct Mailbox *m)
Close a Mailbox.
Definition: mx.h:204
static int mx_open_mailbox_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox for appending.
Definition: mx.c:200
int msg_new
Number of new messages.
Definition: mailbox.h:95
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:1802
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
bool collapsed
Are all threads collapsed?
Definition: context.h:48
bool deleted
Email is deleted.
Definition: email.h:45
int(* path_pretty)(char *buf, size_t buflen, const char *folder)
Abbreviate a Mailbox path.
Definition: mx.h:349
bool C_MaildirTrash
Config: Use the maildir &#39;trashed&#39; flag, rather than deleting.
Definition: config.c:42
#define mutt_error(...)
Definition: logging.h:84
bool replied
Email has been replied to.
Definition: email.h:54
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1183
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:54
int mutt_append_message(struct Mailbox *dest, struct Mailbox *src, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
Append a message.
Definition: copy.c:905
FILE * fp
pointer to the message data
Definition: mx.h:84
bool account_mailbox_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account.
Definition: account.c:66
#define FREE(x)
Definition: memory.h:40
int(* msg_close)(struct Mailbox *m, struct Message *msg)
Close an email.
Definition: mx.h:259
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:94
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1681
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:42
Mapping between user-readable string and a constant.
Definition: mapping.h:31
int mx_access(const char *path, int flags)
Wrapper for access, checks permissions on a given mailbox.
Definition: mx.c:183
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:266
#define STAILQ_EMPTY(head)
Definition: queue.h:345
time_t received
the time at which this message was received
Definition: mx.h:95
struct MxOps MxMboxOps
Mbox Mailbox - Implements MxOps.
Definition: mbox.c:1814
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:321
bool neomutt_account_remove(struct NeoMutt *n, struct Account *a)
Remove an Account from the global list.
Definition: neomutt.c:105
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
struct AddressList sender
Email&#39;s sender.
Definition: envelope.h:61
WHERE bool OptSortSubthreads
(pseudo) used when $sort_aux changes
Definition: options.h:54
struct Email * email_new(void)
Create a new Email.
Definition: email.c:72
List of Mailboxes.
Definition: mailbox.h:152
bool changed
Mailbox has been modified.
Definition: mailbox.h:114
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:50
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
void mutt_mailbox_set_notified(struct Mailbox *m)
Note when the user was last notified of new mail.
Definition: mutt_mailbox.c:285
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:1554
New mail received in Mailbox.
Definition: mx.h:73
bool mutt_str_inline_replace(char *buf, size_t buflen, size_t xlen, const char *rstr)
Replace the beginning of a string.
Definition: string.c:1013
bool mx_tags_is_supported(struct Mailbox *m)
return true if mailbox support tagging
Definition: mx.c:1325
struct Notify * notify
Notifications handler.
Definition: mailbox.h:144
bool C_KeepFlagged
Config: Don&#39;t move flagged messages from $spoolfile to $mbox
Definition: mx.c:83
An Event that happened to an Context.
Definition: context.h:68
struct Account *(* ac_find)(struct Account *a, const char *path)
Find an Account that matches a Mailbox path.
Definition: mx.h:121
#define TAILQ_EMPTY(head)
Definition: queue.h:714
#define MUTT_NEWFOLDER
Create a new folder - same as MUTT_APPEND,.
Definition: mx.h:56
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:1784
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition: newsrc.c:1293
struct Buffer pathbuf
Definition: mailbox.h:83
Convenience wrapper for the library headers.
bool read
Definition: mx.h:90
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:65
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:43
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Mailbox was reopened.
Definition: mx.h:75
&#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:1381
int imap_fast_trash(struct Mailbox *m, char *dest)
Use server COPY command to copy deleted messages to trash.
Definition: imap.c:1394
WHERE char * C_Mbox
Config: Folder that receives read emails (see Move)
Definition: mutt_globals.h:94
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:177
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:1158
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:83
char * path
path to temp file
Definition: mx.h:85
bool mutt_comp_can_append(struct Mailbox *m)
Can we append to this path?
Definition: compress.c:356
The Mailbox API.
Definition: mx.h:104
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:154
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:234
int(* tags_commit)(struct Mailbox *m, struct Email *e, char *buf)
Save the tags to a message.
Definition: mx.h:313
WHERE bool C_Confirmappend
Config: Confirm before appending emails to a mailbox.
Definition: mutt_globals.h:141
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:152