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