NeoMutt  2024-11-14-34-g5aaf0d
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
mx.c
Go to the documentation of this file.
1
36#include "config.h"
37#include <errno.h>
38#include <stdbool.h>
39#include <stdio.h>
40#include <string.h>
41#include <sys/stat.h>
42#include <time.h>
43#include <unistd.h>
44#include "mutt/lib.h"
45#include "address/lib.h"
46#include "config/lib.h"
47#include "email/lib.h"
48#include "core/lib.h"
49#include "alias/lib.h"
50#include "gui/lib.h"
51#include "mutt.h"
52#include "mx.h"
53#include "compmbox/lib.h"
54#include "imap/lib.h"
55#include "key/lib.h"
56#include "maildir/lib.h"
57#include "mbox/lib.h"
58#include "menu/lib.h"
59#include "mh/lib.h"
60#include "nntp/lib.h"
61#include "pop/lib.h"
62#include "question/lib.h"
63#include "copy.h"
64#include "external.h"
65#include "globals.h"
66#include "hook.h"
67#include "mutt_header.h"
68#include "mutt_logging.h"
69#include "mutt_mailbox.h"
70#include "muttlib.h"
71#include "nntp/mdata.h" // IWYU pragma: keep
72#include "protos.h"
73#ifdef USE_NOTMUCH
74#include "notmuch/lib.h"
75#endif
76#ifdef ENABLE_NLS
77#include <libintl.h>
78#endif
79
81static const struct Mapping MboxTypeMap[] = {
82 // clang-format off
83 { "mbox", MUTT_MBOX, },
84 { "MMDF", MUTT_MMDF, },
85 { "MH", MUTT_MH, },
86 { "Maildir", MUTT_MAILDIR, },
87 { NULL, 0, },
88 // clang-format on
89};
90
92const struct EnumDef MboxTypeDef = {
93 "mbox_type",
94 4,
95 (struct Mapping *) &MboxTypeMap,
96};
97
101static const struct MxOps *MxOps[] = {
102 /* These mailboxes can be recognised by their Url scheme */
103 &MxImapOps,
104#ifdef USE_NOTMUCH
106#endif
107 &MxPopOps,
108 &MxNntpOps,
109
110 /* Local mailboxes */
112 &MxMboxOps,
113 &MxMhOps,
114 &MxMmdfOps,
115
116 /* If everything else fails... */
117 &MxCompOps,
118 NULL,
119};
120
127const struct MxOps *mx_get_ops(enum MailboxType type)
128{
129 for (const struct MxOps **ops = MxOps; *ops; ops++)
130 if ((*ops)->type == type)
131 return *ops;
132
133 return NULL;
134}
135
141static bool mutt_is_spool(const char *str)
142{
143 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
144 if (mutt_str_equal(str, c_spool_file))
145 return true;
146
147 struct Url *ua = url_parse(str);
148 struct Url *ub = url_parse(c_spool_file);
149
150 const bool is_spool = ua && ub && (ua->scheme == ub->scheme) &&
151 mutt_istr_equal(ua->host, ub->host) &&
152 mutt_istr_equal(ua->path, ub->path) &&
153 (!ua->user || !ub->user || mutt_str_equal(ua->user, ub->user));
154
155 url_free(&ua);
156 url_free(&ub);
157 return is_spool;
158}
159
170int mx_access(const char *path, int flags)
171{
172 if (imap_path_probe(path, NULL) == MUTT_IMAP)
173 return imap_access(path);
174
175 return access(path, flags);
176}
177
186{
187 if (!m)
188 return false;
189
190 struct stat st = { 0 };
191
192 m->append = true;
193 if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR))
194 {
196
197 if (m->type == MUTT_UNKNOWN)
198 {
199 if (flags & (MUTT_APPEND | MUTT_NEWFOLDER))
200 {
202 }
203 else
204 {
205 mutt_error(_("%s is not a mailbox"), mailbox_path(m));
206 return false;
207 }
208 }
209
210 if (m->type == MUTT_MAILBOX_ERROR)
211 {
212 if (stat(mailbox_path(m), &st) == -1)
213 {
214 if (errno == ENOENT)
215 {
218 else
219 m->type = cs_subset_enum(NeoMutt->sub, "mbox_type");
220 flags |= MUTT_APPENDNEW;
221 }
222 else
223 {
224 mutt_perror("%s", mailbox_path(m));
225 return false;
226 }
227 }
228 else
229 {
230 return false;
231 }
232 }
233
234 m->mx_ops = mx_get_ops(m->type);
235 }
236
237 if (!m->mx_ops || !m->mx_ops->mbox_open_append)
238 return false;
239
240 const bool rc = m->mx_ops->mbox_open_append(m, flags);
241 m->opened++;
242 return rc;
243}
244
252{
253 if (!m)
254 return false;
255
256 if (m->account)
257 return true;
258
259 struct Account *a = mx_ac_find(m);
260 const bool new_account = !a;
261 if (new_account)
262 {
263 a = account_new(NULL, NeoMutt->sub);
264 a->type = m->type;
265 }
266 if (!mx_ac_add(a, m))
267 {
268 if (new_account)
269 {
270 account_free(&a);
271 }
272 return false;
273 }
274 if (new_account)
275 {
277 }
278 return true;
279}
280
289{
290 if (!m)
291 return false;
292
293 if ((m->type == MUTT_UNKNOWN) && (flags & (MUTT_NEWFOLDER | MUTT_APPEND)))
294 {
295 m->type = cs_subset_enum(NeoMutt->sub, "mbox_type");
296 m->mx_ops = mx_get_ops(m->type);
297 }
298
299 const bool newly_linked_account = !m->account;
300 if (newly_linked_account)
301 {
302 if (!mx_mbox_ac_link(m))
303 {
304 return false;
305 }
306 }
307
308 m->verbose = !(flags & MUTT_QUIET);
309 m->readonly = (flags & MUTT_READONLY);
310 m->peekonly = (flags & MUTT_PEEK);
311
312 if (flags & (MUTT_APPEND | MUTT_NEWFOLDER))
313 {
314 if (!mx_open_mailbox_append(m, flags))
315 {
316 goto error;
317 }
318 return true;
319 }
320
321 if (m->opened > 0)
322 {
323 m->opened++;
324 return true;
325 }
326
327 m->size = 0;
328 m->msg_unread = 0;
329 m->msg_flagged = 0;
330 m->rights = MUTT_ACL_ALL;
331
332 if (m->type == MUTT_UNKNOWN)
333 {
335 m->mx_ops = mx_get_ops(m->type);
336 }
337
338 if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR) || !m->mx_ops)
339 {
340 if (m->type == MUTT_MAILBOX_ERROR)
341 mutt_perror("%s", mailbox_path(m));
342 else if ((m->type == MUTT_UNKNOWN) || !m->mx_ops)
343 mutt_error(_("%s is not a mailbox"), mailbox_path(m));
344 goto error;
345 }
346
348
349 /* if the user has a 'push' command in their .neomuttrc, or in a folder-hook,
350 * it will cause the progress messages not to be displayed because
351 * mutt_refresh() will think we are in the middle of a macro. so set a
352 * flag to indicate that we should really refresh the screen. */
353 OptForceRefresh = true;
354
355 if (m->verbose)
356 mutt_message(_("Reading %s..."), mailbox_path(m));
357
358 // Clear out any existing emails
359 for (int i = 0; i < m->email_max; i++)
360 {
361 email_free(&m->emails[i]);
362 }
363
364 m->msg_count = 0;
365 m->msg_unread = 0;
366 m->msg_flagged = 0;
367 m->msg_new = 0;
368 m->msg_deleted = 0;
369 m->msg_tagged = 0;
370 m->vcount = 0;
371
372 enum MxOpenReturns rc = m->mx_ops->mbox_open(m);
373 m->opened++;
374
375 if ((rc == MX_OPEN_OK) || (rc == MX_OPEN_ABORT))
376 {
377 if ((flags & MUTT_NOSORT) == 0)
378 {
379 /* avoid unnecessary work since the mailbox is completely unthreaded
380 * to begin with */
381 OptSortSubthreads = false;
382 OptNeedRescore = false;
383 }
384 if (m->verbose)
386 if (rc == MX_OPEN_ABORT)
387 {
388 mutt_error(_("Reading from %s interrupted..."), mailbox_path(m));
389 }
390 }
391 else
392 {
393 goto error;
394 }
395
396 if (!m->peekonly)
397 m->has_new = false;
398 OptForceRefresh = false;
399
400 return true;
401
402error:
403 mx_fastclose_mailbox(m, newly_linked_account);
404 if (newly_linked_account)
406 return false;
407}
408
414void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
415{
416 if (!m)
417 return;
418
419 m->opened--;
420 if (m->opened != 0)
421 return;
422
423 /* never announce that a mailbox we've just left has new mail.
424 * TODO: really belongs in mx_mbox_close, but this is a nice hook point */
425 if (!m->peekonly)
427
428 if (m->mx_ops)
429 m->mx_ops->mbox_close(m);
430
434
435 if (m->emails)
436 {
437 for (int i = 0; i < m->msg_count; i++)
438 {
439 if (!m->emails[i])
440 break;
441 email_free(&m->emails[i]);
442 }
443 }
444
445 if (!m->visible)
446 {
447 mx_ac_remove(m, keep_account);
448 }
449}
450
456static enum MxStatus sync_mailbox(struct Mailbox *m)
457{
458 if (!m || !m->mx_ops || !m->mx_ops->mbox_sync)
459 return MX_STATUS_ERROR;
460
461 if (m->verbose)
462 {
463 /* L10N: Displayed before/as a mailbox is being synced */
464 mutt_message(_("Writing %s..."), mailbox_path(m));
465 }
466
467 enum MxStatus rc = m->mx_ops->mbox_sync(m);
468 if (rc != MX_STATUS_OK)
469 {
470 mutt_debug(LL_DEBUG2, "mbox_sync returned: %d\n", rc);
471 if ((rc == MX_STATUS_ERROR) && m->verbose)
472 {
473 /* L10N: Displayed if a mailbox sync fails */
474 mutt_error(_("Unable to write %s"), mailbox_path(m));
475 }
476 }
477
478 return rc;
479}
480
487static int trash_append(struct Mailbox *m)
488{
489 if (!m)
490 return -1;
491
492 struct stat st = { 0 };
493 struct stat stc = { 0 };
494 int rc;
495
496 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
497 const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
498 if (!c_trash || (m->msg_deleted == 0) || ((m->type == MUTT_MAILDIR) && c_maildir_trash))
499 {
500 return 0;
501 }
502
503 int delmsgcount = 0;
504 int first_del = -1;
505 for (int i = 0; i < m->msg_count; i++)
506 {
507 struct Email *e = m->emails[i];
508 if (!e)
509 break;
510
511 if (e->deleted && !e->purge)
512 {
513 if (first_del < 0)
514 first_del = i;
515 delmsgcount++;
516 }
517 }
518
519 if (delmsgcount == 0)
520 return 0; /* nothing to be done */
521
522 /* avoid the "append messages" prompt */
523 const bool c_confirm_append = cs_subset_bool(NeoMutt->sub, "confirm_append");
524 cs_subset_str_native_set(NeoMutt->sub, "confirm_append", false, NULL);
525 rc = mutt_save_confirm(c_trash, &st);
526 cs_subset_str_native_set(NeoMutt->sub, "confirm_append", c_confirm_append, NULL);
527 if (rc != 0)
528 {
529 /* L10N: Although we know the precise number of messages, we do not show it to the user.
530 So feel free to use a "generic plural" as plural translation if your language has one. */
531 mutt_error(ngettext("message not deleted", "messages not deleted", delmsgcount));
532 return -1;
533 }
534
535 if ((lstat(mailbox_path(m), &stc) == 0) && (stc.st_ino == st.st_ino) &&
536 (stc.st_dev == st.st_dev) && (stc.st_rdev == st.st_rdev))
537 {
538 return 0; /* we are in the trash folder: simple sync */
539 }
540
541 if ((m->type == MUTT_IMAP) && (imap_path_probe(c_trash, NULL) == MUTT_IMAP))
542 {
543 if (imap_fast_trash(m, c_trash) == 0)
544 return 0;
545 }
546
547 struct Mailbox *m_trash = mx_path_resolve(c_trash);
548 const bool old_append = m_trash->append;
549 if (!mx_mbox_open(m_trash, MUTT_APPEND))
550 {
551 mutt_error(_("Can't open trash folder"));
552 mailbox_free(&m_trash);
553 return -1;
554 }
555
556 /* continue from initial scan above */
557 for (int i = first_del; i < m->msg_count; i++)
558 {
559 struct Email *e = m->emails[i];
560 if (!e)
561 break;
562
563 if (e->deleted && !e->purge)
564 {
565 if (mutt_append_message(m_trash, m, e, NULL, MUTT_CM_NO_FLAGS, CH_NO_FLAGS) == -1)
566 {
567 mx_mbox_close(m_trash);
568 // L10N: Displayed if appending to $trash fails when syncing or closing a mailbox
569 mutt_error(_("Unable to append to trash folder"));
570 m_trash->append = old_append;
571 mailbox_free(&m_trash);
572 return -1;
573 }
574 }
575 }
576
577 mx_mbox_close(m_trash);
578 m_trash->append = old_append;
579 mailbox_free(&m_trash);
580
581 return 0;
582}
583
599{
600 if (!m)
601 return MX_STATUS_ERROR;
602
603 const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
604 if (c_mail_check_recent && !m->peekonly)
605 m->has_new = false;
606
607 if (m->readonly || m->dontwrite || m->append || m->peekonly)
608 {
609 mx_fastclose_mailbox(m, false);
610 return 0;
611 }
612
613 int i, read_msgs = 0;
614 enum MxStatus rc = MX_STATUS_ERROR;
615 enum QuadOption move_messages = MUTT_NO;
617 struct Buffer *mbox = NULL;
618 struct Buffer *buf = buf_pool_get();
619
620 if ((m->msg_unread != 0) && (m->type == MUTT_NNTP))
621 {
622 struct NntpMboxData *mdata = m->mdata;
623
624 if (mdata && mdata->adata && mdata->group)
625 {
626 enum QuadOption ans = query_quadoption(_("Mark all articles read?"),
627 NeoMutt->sub, "catchup_newsgroup");
628 if (ans == MUTT_ABORT)
629 goto cleanup;
630 if (ans == MUTT_YES)
631 mutt_newsgroup_catchup(m, mdata->adata, mdata->group);
632 }
633 }
634
635 const bool c_keep_flagged = cs_subset_bool(NeoMutt->sub, "keep_flagged");
636 for (i = 0; i < m->msg_count; i++)
637 {
638 struct Email *e = m->emails[i];
639 if (!e)
640 break;
641
642 if (!e->deleted && e->read && !(e->flagged && c_keep_flagged))
643 read_msgs++;
644 }
645
646 /* don't need to move articles from newsgroup */
647 if (m->type == MUTT_NNTP)
648 read_msgs = 0;
649
650 const enum QuadOption c_move = cs_subset_quad(NeoMutt->sub, "move");
651 if ((read_msgs != 0) && (c_move != MUTT_NO))
652 {
653 bool is_spool;
654 mbox = buf_pool_get();
655
657 if (p)
658 {
659 is_spool = true;
660 buf_strcpy(mbox, p);
661 }
662 else
663 {
664 const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
665 buf_strcpy(mbox, c_mbox);
666 is_spool = mutt_is_spool(mailbox_path(m)) && !mutt_is_spool(buf_string(mbox));
667 }
668
669 if (is_spool && !buf_is_empty(mbox))
670 {
671 buf_expand_path(mbox);
672 buf_printf(buf,
673 /* L10N: The first argument is the number of read messages to be
674 moved, the second argument is the target mailbox. */
675 ngettext("Move %d read message to %s?", "Move %d read messages to %s?", read_msgs),
676 read_msgs, buf_string(mbox));
677 move_messages = query_quadoption(buf_string(buf), NeoMutt->sub, "move");
678 if (move_messages == MUTT_ABORT)
679 goto cleanup;
680 }
681 }
682
683 /* There is no point in asking whether or not to purge if we are
684 * just marking messages as "trash". */
685 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
686 if ((m->msg_deleted != 0) && !((m->type == MUTT_MAILDIR) && c_maildir_trash))
687 {
688 buf_printf(buf, ngettext("Purge %d deleted message?", "Purge %d deleted messages?", m->msg_deleted),
689 m->msg_deleted);
690 purge = query_quadoption(buf_string(buf), NeoMutt->sub, "delete");
691 if (purge == MUTT_ABORT)
692 goto cleanup;
693 }
694
695 const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
696 if (c_mark_old && !m->peekonly)
697 {
698 for (i = 0; i < m->msg_count; i++)
699 {
700 struct Email *e = m->emails[i];
701 if (!e)
702 break;
703 if (!e->deleted && !e->old && !e->read)
704 mutt_set_flag(m, e, MUTT_OLD, true, true);
705 }
706 }
707
708 if (move_messages)
709 {
710 if (m->verbose)
711 mutt_message(_("Moving read messages to %s..."), buf_string(mbox));
712
713 /* try to use server-side copy first */
714 i = 1;
715
716 if ((m->type == MUTT_IMAP) && (imap_path_probe(buf_string(mbox), NULL) == MUTT_IMAP))
717 {
718 /* add messages for moving, and clear old tags, if any */
719 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
720 for (i = 0; i < m->msg_count; i++)
721 {
722 struct Email *e = m->emails[i];
723 if (!e)
724 break;
725
726 if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
727 {
728 e->tagged = true;
729 ARRAY_ADD(&ea, e);
730 }
731 else
732 {
733 e->tagged = false;
734 }
735 }
736
737 i = imap_copy_messages(m, &ea, buf_string(mbox), SAVE_MOVE);
738 if (i == 0)
739 {
740 const bool c_delete_untag = cs_subset_bool(NeoMutt->sub, "delete_untag");
741 if (c_delete_untag)
742 {
743 struct Email **ep = NULL;
744 ARRAY_FOREACH(ep, &ea)
745 {
746 mutt_set_flag(m, *ep, MUTT_TAG, false, true);
747 }
748 }
749 }
750 ARRAY_FREE(&ea);
751 }
752
753 if (i == 0) /* success */
754 {
756 }
757 else if (i == -1) /* horrible error, bail */
758 {
759 goto cleanup;
760 }
761 else /* use regular append-copy mode */
762 {
763 struct Mailbox *m_read = mx_path_resolve(buf_string(mbox));
764 if (!mx_mbox_open(m_read, MUTT_APPEND))
765 {
766 mailbox_free(&m_read);
767 goto cleanup;
768 }
769
770 for (i = 0; i < m->msg_count; i++)
771 {
772 struct Email *e = m->emails[i];
773 if (!e)
774 break;
775 if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
776 {
777 if (mutt_append_message(m_read, m, e, NULL, MUTT_CM_NO_FLAGS, CH_UPDATE_LEN) == 0)
778 {
779 mutt_set_flag(m, e, MUTT_DELETE, true, true);
780 mutt_set_flag(m, e, MUTT_PURGE, true, true);
781 }
782 else
783 {
784 mx_mbox_close(m_read);
785 goto cleanup;
786 }
787 }
788 }
789
790 mx_mbox_close(m_read);
791 }
792 }
793 else if (!m->changed && (m->msg_deleted == 0))
794 {
795 if (m->verbose)
796 mutt_message(_("Mailbox is unchanged"));
797 if ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF))
798 mbox_reset_atime(m, NULL);
799 mx_fastclose_mailbox(m, false);
800 rc = MX_STATUS_OK;
801 goto cleanup;
802 }
803
804 /* copy mails to the trash before expunging */
805 const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
806 const struct Mailbox *m_trash = mx_mbox_find(m->account, c_trash);
807 if (purge && (m->msg_deleted != 0) && (m != m_trash))
808 {
809 if (trash_append(m) != 0)
810 goto cleanup;
811 }
812
813 /* allow IMAP to preserve the deleted flag across sessions */
814 if (m->type == MUTT_IMAP)
815 {
816 const enum MxStatus check = imap_sync_mailbox(m, (purge != MUTT_NO), true);
817 if (check == MX_STATUS_ERROR)
818 {
819 rc = check;
820 goto cleanup;
821 }
822 }
823 else
824 {
825 if (purge == MUTT_NO)
826 {
827 for (i = 0; i < m->msg_count; i++)
828 {
829 struct Email *e = m->emails[i];
830 if (!e)
831 break;
832
833 e->deleted = false;
834 e->purge = false;
835 }
836 m->msg_deleted = 0;
837 }
838
839 if (m->changed || (m->msg_deleted != 0))
840 {
841 enum MxStatus check = sync_mailbox(m);
842 if (check != MX_STATUS_OK)
843 {
844 rc = check;
845 goto cleanup;
846 }
847 }
848 }
849
850 if (m->verbose)
851 {
852 if (move_messages)
853 {
854 mutt_message(_("%d kept, %d moved, %d deleted"),
855 m->msg_count - m->msg_deleted, read_msgs, m->msg_deleted);
856 }
857 else
858 {
859 mutt_message(_("%d kept, %d deleted"), m->msg_count - m->msg_deleted, m->msg_deleted);
860 }
861 }
862
863 const bool c_save_empty = cs_subset_bool(NeoMutt->sub, "save_empty");
864 if ((m->msg_count == m->msg_deleted) &&
865 ((m->type == MUTT_MMDF) || (m->type == MUTT_MBOX)) &&
866 !mutt_is_spool(mailbox_path(m)) && !c_save_empty)
867 {
869 }
870
871 if ((purge == MUTT_YES) && (m->msg_deleted != 0))
872 {
873 for (i = 0; i < m->msg_count; i++)
874 {
875 struct Email *e = m->emails[i];
876 if (!e)
877 break;
878 if (e->deleted && !e->read)
879 {
880 m->msg_unread--;
881 if (!e->old)
882 m->msg_new--;
883 }
884 if (e->deleted && e->flagged)
885 m->msg_flagged--;
886 }
887 }
888
889 mx_fastclose_mailbox(m, false);
890
891 rc = MX_STATUS_OK;
892
893cleanup:
894 buf_pool_release(&mbox);
895 buf_pool_release(&buf);
896 return rc;
897}
898
907{
908 if (!m)
909 return MX_STATUS_ERROR;
910
911 enum MxStatus rc = MX_STATUS_OK;
912 int purge = 1;
913 int msgcount, deleted;
914
915 if (m->dontwrite)
916 {
917 char buf[512] = { 0 };
918 char tmp[768] = { 0 };
919 if (km_expand_key(buf, sizeof(buf), km_find_func(MENU_INDEX, OP_TOGGLE_WRITE)))
920 snprintf(tmp, sizeof(tmp), _(" Press '%s' to toggle write"), buf);
921 else
922 mutt_str_copy(tmp, _("Use 'toggle-write' to re-enable write"), sizeof(tmp));
923
924 mutt_error(_("Mailbox is marked unwritable. %s"), tmp);
925 return MX_STATUS_ERROR;
926 }
927 else if (m->readonly)
928 {
929 mutt_error(_("Mailbox is read-only"));
930 return MX_STATUS_ERROR;
931 }
932
933 if (!m->changed && (m->msg_deleted == 0))
934 {
935 if (m->verbose)
936 mutt_message(_("Mailbox is unchanged"));
937 return MX_STATUS_OK;
938 }
939
940 if (m->msg_deleted != 0)
941 {
942 char buf[128] = { 0 };
943
944 snprintf(buf, sizeof(buf),
945 ngettext("Purge %d deleted message?", "Purge %d deleted messages?", m->msg_deleted),
946 m->msg_deleted);
947 purge = query_quadoption(buf, NeoMutt->sub, "delete");
948 if (purge == MUTT_ABORT)
949 return MX_STATUS_ERROR;
950 if (purge == MUTT_NO)
951 {
952 if (!m->changed)
953 return MX_STATUS_OK; /* nothing to do! */
954 /* let IMAP servers hold on to D flags */
955 if (m->type != MUTT_IMAP)
956 {
957 for (int i = 0; i < m->msg_count; i++)
958 {
959 struct Email *e = m->emails[i];
960 if (!e)
961 break;
962 e->deleted = false;
963 e->purge = false;
964 }
965 m->msg_deleted = 0;
966 }
967 }
969 }
970
971 /* really only for IMAP - imap_sync_mailbox results in a call to
972 * ctx_update_tables, so m->msg_deleted is 0 when it comes back */
973 msgcount = m->msg_count;
974 deleted = m->msg_deleted;
975
976 const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
977 const struct Mailbox *m_trash = mx_mbox_find(m->account, c_trash);
978 if (purge && (m->msg_deleted != 0) && (m != m_trash))
979 {
980 if (trash_append(m) != 0)
981 return MX_STATUS_OK;
982 }
983
984 if (m->type == MUTT_IMAP)
985 rc = imap_sync_mailbox(m, purge, false);
986 else
987 rc = sync_mailbox(m);
988 if (rc != MX_STATUS_ERROR)
989 {
990 if ((m->type == MUTT_IMAP) && !purge)
991 {
992 if (m->verbose)
993 mutt_message(_("Mailbox checkpointed"));
994 }
995 else
996 {
997 if (m->verbose)
998 mutt_message(_("%d kept, %d deleted"), msgcount - deleted, deleted);
999 }
1000
1001 mutt_sleep(0);
1002
1003 const bool c_save_empty = cs_subset_bool(NeoMutt->sub, "save_empty");
1004 if ((m->msg_count == m->msg_deleted) &&
1005 ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) &&
1006 !mutt_is_spool(mailbox_path(m)) && !c_save_empty)
1007 {
1008 unlink(mailbox_path(m));
1009 mx_fastclose_mailbox(m, false);
1010 return MX_STATUS_OK;
1011 }
1012
1013 /* if we haven't deleted any messages, we don't need to resort
1014 * ... except for certain folder formats which need "unsorted"
1015 * sort order in order to synchronize folders.
1016 *
1017 * MH and maildir are safe. mbox-style seems to need re-sorting,
1018 * at least with the new threading code. */
1019 if (purge || ((m->type != MUTT_MAILDIR) && (m->type != MUTT_MH)))
1020 {
1021 /* IMAP does this automatically after handling EXPUNGE */
1022 if (m->type != MUTT_IMAP)
1023 {
1026 }
1027 }
1028 }
1029
1030 return rc;
1031}
1032
1040struct Message *mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
1041{
1042 if (!m)
1043 return NULL;
1044
1045 struct Address *p = NULL;
1046 struct Message *msg = NULL;
1047
1048 if (!m->mx_ops || !m->mx_ops->msg_open_new)
1049 {
1050 mutt_debug(LL_DEBUG1, "function unimplemented for mailbox type %d\n", m->type);
1051 return NULL;
1052 }
1053
1054 msg = message_new();
1055 msg->write = true;
1056
1057 if (e)
1058 {
1059 msg->flags.flagged = e->flagged;
1060 msg->flags.replied = e->replied;
1061 msg->flags.read = e->read;
1062 msg->flags.draft = (flags & MUTT_SET_DRAFT);
1063 msg->received = e->received;
1064 }
1065
1066 if (msg->received == 0)
1067 msg->received = mutt_date_now();
1068
1069 if (m->mx_ops->msg_open_new(m, msg, e))
1070 {
1071 if (m->type == MUTT_MMDF)
1072 fputs(MMDF_SEP, msg->fp);
1073
1074 if (((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) && (flags & MUTT_ADD_FROM))
1075 {
1076 if (e)
1077 {
1078 p = TAILQ_FIRST(&e->env->return_path);
1079 if (!p)
1080 p = TAILQ_FIRST(&e->env->sender);
1081 if (!p)
1082 p = TAILQ_FIRST(&e->env->from);
1083 }
1084
1085 // Use C locale for the date, so that day/month names are in English
1086 char buf[64] = { 0 };
1087 mutt_date_localtime_format_locale(buf, sizeof(buf), "%a %b %e %H:%M:%S %Y",
1089 fprintf(msg->fp, "From %s %s\n", p ? buf_string(p->mailbox) : NONULL(Username), buf);
1090 }
1091 }
1092 else
1093 {
1094 message_free(&msg);
1095 }
1096
1097 return msg;
1098}
1099
1106{
1107 if (!m || !m->mx_ops)
1108 return MX_STATUS_ERROR;
1109
1110 const short c_mail_check = cs_subset_number(NeoMutt->sub, "mail_check");
1111
1112 time_t t = mutt_date_now();
1113 if ((t - m->last_checked) < c_mail_check)
1114 return MX_STATUS_OK;
1115
1116 m->last_checked = t;
1117
1118 enum MxStatus rc = m->mx_ops->mbox_check(m);
1119 if ((rc == MX_STATUS_NEW_MAIL) || (rc == MX_STATUS_REOPENED))
1120 {
1122 }
1123
1124 return rc;
1125}
1126
1134struct Message *mx_msg_open(struct Mailbox *m, struct Email *e)
1135{
1136 if (!m || !e)
1137 return NULL;
1138
1139 if (!m->mx_ops || !m->mx_ops->msg_open)
1140 {
1141 mutt_debug(LL_DEBUG1, "function not implemented for mailbox type %d\n", m->type);
1142 return NULL;
1143 }
1144
1145 struct Message *msg = message_new();
1146 if (!m->mx_ops->msg_open(m, msg, e))
1147 message_free(&msg);
1148
1149 return msg;
1150}
1151
1159int mx_msg_commit(struct Mailbox *m, struct Message *msg)
1160{
1161 if (!m || !m->mx_ops || !m->mx_ops->msg_commit || !msg)
1162 return -1;
1163
1164 if (!(msg->write && m->append))
1165 {
1166 mutt_debug(LL_DEBUG1, "msg->write = %d, m->append = %d\n", msg->write, m->append);
1167 return -1;
1168 }
1169
1170 return m->mx_ops->msg_commit(m, msg);
1171}
1172
1180int mx_msg_close(struct Mailbox *m, struct Message **ptr)
1181{
1182 if (!m || !ptr || !*ptr)
1183 return 0;
1184
1185 int rc = 0;
1186 struct Message *msg = *ptr;
1187
1188 if (m->mx_ops && m->mx_ops->msg_close)
1189 rc = m->mx_ops->msg_close(m, msg);
1190
1191 if (msg->path)
1192 {
1193 mutt_debug(LL_DEBUG1, "unlinking %s\n", msg->path);
1194 unlink(msg->path);
1195 }
1196
1197 message_free(ptr);
1198 return rc;
1199}
1200
1206void mx_alloc_memory(struct Mailbox *m, int req_size)
1207{
1208 if ((req_size + 1) <= m->email_max)
1209 return;
1210
1211 // Step size to increase by
1212 // Larger mailboxes get a larger step (limited to 1000)
1213 const int grow = CLAMP(m->email_max, 25, 1000);
1214
1215 // Sanity checks
1216 req_size = ROUND_UP(req_size + 1, grow);
1217
1218 const size_t s = MAX(sizeof(struct Email *), sizeof(int));
1219 if ((req_size * s) < (m->email_max * s))
1220 {
1221 mutt_error("%s", strerror(ENOMEM));
1222 mutt_exit(1);
1223 }
1224
1225 if (m->emails)
1226 {
1227 MUTT_MEM_REALLOC(&m->emails, req_size, struct Email *);
1228 MUTT_MEM_REALLOC(&m->v2r, req_size, int);
1229 }
1230 else
1231 {
1232 m->emails = MUTT_MEM_CALLOC(req_size, struct Email *);
1233 m->v2r = MUTT_MEM_CALLOC(req_size, int);
1234 }
1235
1236 for (int i = m->email_max; i < req_size; i++)
1237 {
1238 m->emails[i] = NULL;
1239 m->v2r[i] = -1;
1240 }
1241
1242 m->email_max = req_size;
1243}
1244
1253{
1254 if (buf_is_empty(path))
1255 return -1;
1256
1258 const struct MxOps *ops = mx_get_ops(type);
1259 if (!ops || !ops->path_is_empty)
1260 return -1;
1261
1262 return ops->path_is_empty(path);
1263}
1264
1274int mx_tags_edit(struct Mailbox *m, const char *tags, struct Buffer *buf)
1275{
1276 if (!m || !buf)
1277 return -1;
1278
1279 if (m->mx_ops->tags_edit)
1280 return m->mx_ops->tags_edit(m, tags, buf);
1281
1282 mutt_message(_("Folder doesn't support tagging, aborting"));
1283 return -1;
1284}
1285
1294int mx_tags_commit(struct Mailbox *m, struct Email *e, const char *tags)
1295{
1296 if (!m || !e || !tags)
1297 return -1;
1298
1299 if (m->mx_ops->tags_commit)
1300 return m->mx_ops->tags_commit(m, e, tags);
1301
1302 mutt_message(_("Folder doesn't support tagging, aborting"));
1303 return -1;
1304}
1305
1312{
1313 return m && m->mx_ops->tags_commit && m->mx_ops->tags_edit;
1314}
1315
1321enum MailboxType mx_path_probe(const char *path)
1322{
1323 if (!path)
1324 return MUTT_UNKNOWN;
1325
1326 enum MailboxType rc = MUTT_UNKNOWN;
1327
1328 // First, search the non-local Mailbox types (is_local == false)
1329 for (const struct MxOps **ops = MxOps; *ops; ops++)
1330 {
1331 if ((*ops)->is_local)
1332 continue;
1333 rc = (*ops)->path_probe(path, NULL);
1334 if (rc != MUTT_UNKNOWN)
1335 return rc;
1336 }
1337
1338 struct stat st = { 0 };
1339 if (stat(path, &st) != 0)
1340 {
1341 mutt_debug(LL_DEBUG1, "unable to stat %s: %s (errno %d)\n", path, strerror(errno), errno);
1342 return MUTT_UNKNOWN;
1343 }
1344
1345 if (S_ISFIFO(st.st_mode))
1346 {
1347 mutt_error(_("Can't open %s: it is a pipe"), path);
1348 return MUTT_UNKNOWN;
1349 }
1350
1351 // Next, search the local Mailbox types (is_local == true)
1352 for (const struct MxOps **ops = MxOps; *ops; ops++)
1353 {
1354 if (!(*ops)->is_local)
1355 continue;
1356 rc = (*ops)->path_probe(path, &st);
1357 if (rc != MUTT_UNKNOWN)
1358 return rc;
1359 }
1360
1361 return rc;
1362}
1363
1367int mx_path_canon(struct Buffer *path, const char *folder, enum MailboxType *type)
1368{
1369 if (buf_is_empty(path))
1370 return -1;
1371
1372 for (size_t i = 0; i < 3; i++)
1373 {
1374 /* Look for !! ! - < > or ^ followed by / or NUL */
1375 if ((buf_at(path, 0) == '!') && (buf_at(path, 1) == '!'))
1376 {
1377 if (((buf_at(path, 2) == '/') || (buf_at(path, 2) == '\0')))
1378 {
1379 buf_inline_replace(path, 0, 2, LastFolder);
1380 }
1381 }
1382 else if ((buf_at(path, 0) == '+') || (buf_at(path, 0) == '='))
1383 {
1384 size_t folder_len = mutt_str_len(folder);
1385 if ((folder_len > 0) && (folder[folder_len - 1] != '/'))
1386 {
1387 path->data[0] = '/';
1388 buf_inline_replace(path, 0, 0, folder);
1389 }
1390 else
1391 {
1392 buf_inline_replace(path, 0, 1, folder);
1393 }
1394 }
1395 else if ((buf_at(path, 1) == '/') || (buf_at(path, 1) == '\0'))
1396 {
1397 if (buf_at(path, 0) == '!')
1398 {
1399 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1400 buf_inline_replace(path, 0, 1, c_spool_file);
1401 }
1402 else if (buf_at(path, 0) == '-')
1403 {
1404 buf_inline_replace(path, 0, 1, LastFolder);
1405 }
1406 else if (buf_at(path, 0) == '<')
1407 {
1408 const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
1409 buf_inline_replace(path, 0, 1, c_record);
1410 }
1411 else if (buf_at(path, 0) == '>')
1412 {
1413 const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
1414 buf_inline_replace(path, 0, 1, c_mbox);
1415 }
1416 else if (buf_at(path, 0) == '^')
1417 {
1418 buf_inline_replace(path, 0, 1, CurrentFolder);
1419 }
1420 else if (buf_at(path, 0) == '~')
1421 {
1422 buf_inline_replace(path, 0, 1, HomeDir);
1423 }
1424 }
1425 else if (buf_at(path, 0) == '@')
1426 {
1427 /* elm compatibility, @ expands alias to user name */
1428 struct AddressList *al = alias_lookup(buf_string(path));
1429 if (!al || TAILQ_EMPTY(al))
1430 break;
1431
1432 struct Email *e = email_new();
1433 e->env = mutt_env_new();
1434 mutt_addrlist_copy(&e->env->from, al, false);
1435 mutt_addrlist_copy(&e->env->to, al, false);
1437 email_free(&e);
1438 break;
1439 }
1440 else
1441 {
1442 break;
1443 }
1444 }
1445
1446 // if (!folder) //XXX - use inherited version, or pass NULL to backend?
1447 // return -1;
1448
1450 if (type)
1451 *type = type2;
1452 const struct MxOps *ops = mx_get_ops(type2);
1453 if (!ops || !ops->path_canon)
1454 return -1;
1455
1456 if (ops->path_canon(path) < 0)
1457 {
1458 mutt_path_canon(path, HomeDir, true);
1459 }
1460
1461 return 0;
1462}
1463
1471int mx_path_canon2(struct Mailbox *m, const char *folder)
1472{
1473 if (!m)
1474 return -1;
1475
1476 struct Buffer *path = buf_pool_get();
1477
1478 if (m->realpath)
1479 buf_strcpy(path, m->realpath);
1480 else
1481 buf_strcpy(path, mailbox_path(m));
1482
1483 int rc = mx_path_canon(path, folder, &m->type);
1484
1486 buf_pool_release(&path);
1487
1488 if (rc >= 0)
1489 {
1490 m->mx_ops = mx_get_ops(m->type);
1491 buf_strcpy(&m->pathbuf, m->realpath);
1492 }
1493
1494 return rc;
1495}
1496
1506{
1507 if (!m || !m->mx_ops || !m->mx_ops->msg_padding_size)
1508 return 0;
1509
1510 return m->mx_ops->msg_padding_size(m);
1511}
1512
1519struct Account *mx_ac_find(struct Mailbox *m)
1520{
1521 if (!m || !m->mx_ops || !m->realpath)
1522 return NULL;
1523
1524 struct Account *np = NULL;
1525 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1526 {
1527 if (np->type != m->type)
1528 continue;
1529
1530 if (m->mx_ops->ac_owns_path(np, m->realpath))
1531 return np;
1532 }
1533
1534 return NULL;
1535}
1536
1543struct Mailbox *mx_mbox_find(struct Account *a, const char *path)
1544{
1545 if (!a || !path)
1546 return NULL;
1547
1548 struct MailboxNode *np = NULL;
1549 struct Url *url_p = NULL;
1550 struct Url *url_a = NULL;
1551
1552 const bool use_url = (a->type == MUTT_IMAP);
1553 if (use_url)
1554 {
1555 url_p = url_parse(path);
1556 if (!url_p)
1557 goto done;
1558 }
1559
1560 STAILQ_FOREACH(np, &a->mailboxes, entries)
1561 {
1562 if (!use_url)
1563 {
1565 return np->mailbox;
1566 continue;
1567 }
1568
1569 url_free(&url_a);
1570 url_a = url_parse(np->mailbox->realpath);
1571 if (!url_a)
1572 continue;
1573
1574 if (!mutt_istr_equal(url_a->host, url_p->host))
1575 continue;
1576 if (url_p->user && !mutt_istr_equal(url_a->user, url_p->user))
1577 continue;
1578 if (a->type == MUTT_IMAP)
1579 {
1580 if (imap_mxcmp(url_a->path, url_p->path) == 0)
1581 break;
1582 }
1583 else
1584 {
1585 if (mutt_str_equal(url_a->path, url_p->path))
1586 break;
1587 }
1588 }
1589
1590done:
1591 url_free(&url_p);
1592 url_free(&url_a);
1593
1594 if (!np)
1595 return NULL;
1596 return np->mailbox;
1597}
1598
1605struct Mailbox *mx_mbox_find2(const char *path)
1606{
1607 if (!path)
1608 return NULL;
1609
1610 struct Buffer *buf = buf_new(path);
1611 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1612 mx_path_canon(buf, c_folder, NULL);
1613
1614 struct Account *np = NULL;
1615 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1616 {
1617 struct Mailbox *m = mx_mbox_find(np, buf_string(buf));
1618 if (m)
1619 {
1620 buf_free(&buf);
1621 return m;
1622 }
1623 }
1624
1625 buf_free(&buf);
1626 return NULL;
1627}
1628
1636struct Mailbox *mx_path_resolve(const char *path)
1637{
1638 if (!path)
1639 return NULL;
1640
1641 struct Mailbox *m = mx_mbox_find2(path);
1642 if (m)
1643 return m;
1644
1645 m = mailbox_new();
1646 buf_strcpy(&m->pathbuf, path);
1647 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1648 mx_path_canon2(m, c_folder);
1649
1650 return m;
1651}
1652
1659static struct Mailbox *mx_mbox_find_by_name_ac(struct Account *a, const char *name)
1660{
1661 if (!a || !name)
1662 return NULL;
1663
1664 struct MailboxNode *np = NULL;
1665
1666 STAILQ_FOREACH(np, &a->mailboxes, entries)
1667 {
1668 if (mutt_str_equal(np->mailbox->name, name))
1669 return np->mailbox;
1670 }
1671
1672 return NULL;
1673}
1674
1680static struct Mailbox *mx_mbox_find_by_name(const char *name)
1681{
1682 if (!name)
1683 return NULL;
1684
1685 struct Account *np = NULL;
1686 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1687 {
1688 struct Mailbox *m = mx_mbox_find_by_name_ac(np, name);
1689 if (m)
1690 return m;
1691 }
1692
1693 return NULL;
1694}
1695
1705struct Mailbox *mx_resolve(const char *path_or_name)
1706{
1707 if (!path_or_name)
1708 return NULL;
1709
1710 // Order is name first because you can create a Mailbox from
1711 // a path, but can't from a name. So fallback behavior creates
1712 // a new Mailbox for us.
1713 struct Mailbox *m = mx_mbox_find_by_name(path_or_name);
1714 if (!m)
1715 m = mx_path_resolve(path_or_name);
1716
1717 return m;
1718}
1719
1723bool mx_ac_add(struct Account *a, struct Mailbox *m)
1724{
1725 if (!a || !m || !m->mx_ops || !m->mx_ops->ac_add)
1726 return false;
1727
1728 return m->mx_ops->ac_add(a, m) && account_mailbox_add(a, m);
1729}
1730
1740int mx_ac_remove(struct Mailbox *m, bool keep_account)
1741{
1742 if (!m || !m->account)
1743 return -1;
1744
1745 struct Account *a = m->account;
1747 if (!keep_account && STAILQ_EMPTY(&a->mailboxes))
1748 {
1750 }
1751 return 0;
1752}
1753
1759enum MxStatus mx_mbox_check_stats(struct Mailbox *m, uint8_t flags)
1760{
1761 if (!m)
1762 return MX_STATUS_ERROR;
1763
1764 enum MxStatus rc = m->mx_ops->mbox_check_stats(m, flags);
1765 if (rc != MX_STATUS_ERROR)
1766 {
1767 struct EventMailbox ev_m = { m };
1769 }
1770
1771 return rc;
1772}
1773
1783int mx_save_hcache(struct Mailbox *m, struct Email *e)
1784{
1785 if (!m || !m->mx_ops || !m->mx_ops->msg_save_hcache || !e)
1786 return 0;
1787
1788 return m->mx_ops->msg_save_hcache(m, e);
1789}
1790
1797{
1798 return m ? m->type : MUTT_MAILBOX_ERROR;
1799}
1800
1808{
1809 if (!m)
1810 return -1;
1811
1812 if (m->readonly)
1813 {
1814 mutt_error(_("Can't toggle write on a readonly mailbox"));
1815 return -1;
1816 }
1817
1818 if (m->dontwrite)
1819 {
1820 m->dontwrite = false;
1821 mutt_message(_("Changes to folder will be written on folder exit"));
1822 }
1823 else
1824 {
1825 m->dontwrite = true;
1826 mutt_message(_("Changes to folder will not be written"));
1827 }
1828
1829 struct EventMailbox ev_m = { m };
1831 return 0;
1832}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:765
Email Address Handling.
Email Aliases.
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:277
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:156
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:212
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:204
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:58
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition: buffer.c:670
void buf_free(struct Buffer **ptr)
Deallocates a buffer.
Definition: buffer.c:319
void buf_inline_replace(struct Buffer *buf, size_t pos, size_t len, const char *str)
Definition: buffer.c:770
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition: buffer.c:304
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
bool mutt_comp_can_append(struct Mailbox *m)
Can we append to this path?
Definition: compress.c:365
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:291
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:192
unsigned char cs_subset_enum(const struct ConfigSubset *sub, const char *name)
Get a enumeration config item by name.
Definition: helpers.c:71
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:143
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
Convenience wrapper for the config headers.
char * HomeDir
User's home directory.
Definition: globals.c:37
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:982
Duplicate the structure of an entire email.
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:64
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:37
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:53
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:98
struct Account * account_new(const char *name, struct ConfigSubset *sub)
Create a new Account.
Definition: account.c:44
bool account_mailbox_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account.
Definition: account.c:67
void account_free(struct Account **ptr)
Free an Account.
Definition: account.c:143
Convenience wrapper for the core headers.
struct Mailbox * mailbox_new(void)
Create a new Mailbox.
Definition: mailbox.c:68
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:89
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:233
@ NT_MAILBOX_UNTAG
Clear the 'last-tagged' pointer.
Definition: mailbox.h:192
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition: mailbox.h:185
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:190
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:189
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition: mailbox.h:191
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:223
#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
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:77
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:46
Structs that make up an email.
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:46
Manage where the email is piped to external commands.
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: external.h:53
void mutt_file_unlink_empty(const char *path)
Delete a file if it's empty.
Definition: file.c:1335
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:57
char * LastFolder
Previously selected mailbox.
Definition: globals.c:43
bool OptNeedRescore
(pseudo) set when the 'score' command is used
Definition: globals.c:65
bool OptForceRefresh
(pseudo) refresh even during macros
Definition: globals.c:62
char * CurrentFolder
Currently selected mailbox.
Definition: globals.c:42
char * Username
User's login name.
Definition: globals.c:40
bool OptSortSubthreads
(pseudo) used when $sort_aux changes
Definition: globals.c:72
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:2808
const struct MxOps MxMboxOps
Mbox Mailbox - Implements MxOps -.
Definition: mbox.c:1713
const struct MxOps MxNotmuchOps
Notmuch Mailbox - Implements MxOps -.
Definition: notmuch.c:2476
const struct MxOps MxMhOps
MH Mailbox - Implements MxOps -.
Definition: mh.c:1239
const struct MxOps MxPopOps
POP Mailbox - Implements MxOps -.
Definition: pop.c:1179
const struct MxOps MxImapOps
IMAP Mailbox - Implements MxOps -.
Definition: imap.c:2403
const struct MxOps MxCompOps
Compressed Mailbox - Implements MxOps -.
Definition: compress.c:932
const struct MxOps MxMmdfOps
MMDF Mailbox - Implements MxOps -.
Definition: mbox.c:1743
const struct MxOps MxMaildirOps
Maildir Mailbox - Implements MxOps -.
Definition: maildir.c:44
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2345
Convenience wrapper for the gui headers.
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:457
void mutt_default_save(struct Buffer *path, struct Email *e)
Find the default save path for an email.
Definition: hook.c:778
char * mutt_find_hook(HookFlags type, const char *pat)
Find a matching hook.
Definition: hook.c:679
Parse and execute user-defined hooks.
#define MUTT_MBOX_HOOK
mbox-hook: move messages after reading them
Definition: hook.h:38
IMAP network mailbox.
int imap_mxcmp(const char *mx1, const char *mx2)
Compare mailbox names, giving priority to INBOX.
Definition: util.c:549
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:1687
int imap_fast_trash(struct Mailbox *m, const char *dest)
Use server COPY command to copy deleted messages to trash.
Definition: imap.c:1356
enum MxStatus imap_sync_mailbox(struct Mailbox *m, bool expunge, bool close)
Sync all the changes to the server.
Definition: imap.c:1471
int imap_access(const char *path)
Check permissions on an IMAP mailbox with a new connection.
Definition: imap.c:463
struct Keymap * km_find_func(enum MenuType mtype, int func)
Find a function's mapping in a Menu.
Definition: lib.c:509
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: lib.c:457
Manage keymappings.
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
Maildir local mailbox type.
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:269
#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:748
#define ROUND_UP(NUM, STEP)
Definition: memory.h:36
#define MUTT_MEM_CALLOC(n, type)
Definition: memory.h:40
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition: memory.h:43
#define MAX(a, b)
Definition: memory.h:31
#define CLAMP(val, lo, hi)
Definition: memory.h:33
GUI present the user with a selectable list.
Mh local mailbox type.
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:969
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:456
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:248
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:672
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
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:581
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:280
Many unsorted constants and some structs.
@ MUTT_OLD
Old messages.
Definition: mutt.h:71
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:77
@ MUTT_TAG
Tagged messages.
Definition: mutt.h:80
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:75
void mutt_make_label_hash(struct Mailbox *m)
Create a Hash Table to store the labels.
Definition: mutt_header.c:403
Representation of the email's header.
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
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:843
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:746
Some miscellaneous functions.
void mx_alloc_memory(struct Mailbox *m, int req_size)
Create storage for the emails.
Definition: mx.c:1206
int mx_tags_edit(struct Mailbox *m, const char *tags, struct Buffer *buf)
Start the tag editor of the mailbox.
Definition: mx.c:1274
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1180
int mx_ac_remove(struct Mailbox *m, bool keep_account)
Remove a Mailbox from an Account and delete Account if empty.
Definition: mx.c:1740
int mx_access(const char *path, int flags)
Wrapper for access, checks permissions on a given mailbox.
Definition: mx.c:170
const struct EnumDef MboxTypeDef
Data for the $mbox_type enumeration.
Definition: mx.c:92
static enum MxStatus sync_mailbox(struct Mailbox *m)
Save changes to disk.
Definition: mx.c:456
static int trash_append(struct Mailbox *m)
Move deleted mails to the trash folder.
Definition: mx.c:487
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1505
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition: mx.c:414
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:1759
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:1367
static bool mutt_is_spool(const char *str)
Is this the spool_file?
Definition: mx.c:141
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:288
struct Mailbox * mx_mbox_find(struct Account *a, const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1543
struct Mailbox * mx_resolve(const char *path_or_name)
Get a Mailbox from either a path or name.
Definition: mx.c:1705
static struct Mailbox * mx_mbox_find_by_name(const char *name)
Find a Mailbox with given name.
Definition: mx.c:1680
bool mx_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Wrapper for MxOps::ac_add()
Definition: mx.c:1723
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1605
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1134
const struct MxOps * mx_get_ops(enum MailboxType type)
Get mailbox operations.
Definition: mx.c:127
bool mx_tags_is_supported(struct Mailbox *m)
Return true if mailbox support tagging.
Definition: mx.c:1311
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:1294
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:1783
static const struct Mapping MboxTypeMap[]
Lookup table of mailbox types.
Definition: mx.c:81
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:251
struct Account * mx_ac_find(struct Mailbox *m)
Find the Account owning a Mailbox.
Definition: mx.c:1519
enum MailboxType mx_type(struct Mailbox *m)
Return the type of the Mailbox.
Definition: mx.c:1796
int mx_path_is_empty(struct Buffer *path)
Is the mailbox empty.
Definition: mx.c:1252
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1040
int mx_toggle_write(struct Mailbox *m)
Toggle the mailbox's readonly flag.
Definition: mx.c:1807
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1159
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:1659
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1321
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1636
int mx_path_canon2(struct Mailbox *m, const char *folder)
Canonicalise the path to realpath.
Definition: mx.c:1471
enum MxStatus mx_mbox_check(struct Mailbox *m)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1105
enum MxStatus mx_mbox_sync(struct Mailbox *m)
Save changes to mailbox.
Definition: mx.c:906
static bool mx_open_mailbox_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox for appending.
Definition: mx.c:185
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:598
API for mailboxes.
uint8_t MsgOpenFlags
Flags for mx_msg_open_new(), e.g. MUTT_ADD_FROM.
Definition: mx.h:37
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:39
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:40
#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_sync(), 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:110
bool neomutt_account_remove(struct NeoMutt *n, const struct Account *a)
Remove an Account from the global list.
Definition: neomutt.c:133
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:1343
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:379
#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:36
enum MailboxType type
Type of Mailboxes this Account contains.
Definition: account.h:37
struct MailboxList mailboxes
List of Mailboxes.
Definition: account.h:40
An email address.
Definition: address.h:36
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
String manipulation buffer.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:37
The envelope/body of an email.
Definition: email.h:39
bool read
Email is read.
Definition: email.h:50
bool purge
Skip trash folder when deleting.
Definition: email.h:79
struct Envelope * env
Envelope information.
Definition: email.h:68
bool old
Email is seen, but unread.
Definition: email.h:49
bool flagged
Marked important?
Definition: email.h:47
bool replied
Email has been replied to.
Definition: email.h:51
char * path
Path of Email (for local Mailboxes)
Definition: email.h:70
bool deleted
Email is deleted.
Definition: email.h:78
bool tagged
Email is tagged.
Definition: email.h:107
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:61
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:199
List of Mailboxes.
Definition: mailbox.h:166
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:167
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:110
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:109
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:98
const struct MxOps * mx_ops
MXAPI callback functions.
Definition: mailbox.h:107
int msg_new
Number of new messages.
Definition: mailbox.h:92
time_t last_checked
Last time we checked this mailbox for new mail.
Definition: mailbox.h:105
int msg_count
Total number of messages.
Definition: mailbox.h:88
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:119
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:132
struct HashTable * subj_hash
Hash Table: "subject" -> Email.
Definition: mailbox.h:124
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:145
struct HashTable * id_hash
Hash Table: "message-id" -> Email.
Definition: mailbox.h:123
struct Buffer pathbuf
Path of the Mailbox.
Definition: mailbox.h:80
bool peekonly
Just taking a glance, revert atime.
Definition: mailbox.h:114
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:93
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:127
bool dontwrite
Don't write the mailbox on close.
Definition: mailbox.h:111
off_t size
Size of the Mailbox.
Definition: mailbox.h:84
struct HashTable * label_hash
Hash Table: "x-labels" -> Email.
Definition: mailbox.h:125
bool visible
True if a result of "mailboxes".
Definition: mailbox.h:130
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:90
int opened
Number of times mailbox is opened.
Definition: mailbox.h:128
bool readonly
Don't allow changes to the mailbox.
Definition: mailbox.h:116
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:94
bool verbose
Display status messages?
Definition: mailbox.h:117
int msg_unread
Number of unread messages.
Definition: mailbox.h:89
Mapping between user-readable string and a constant.
Definition: mapping.h:33
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:363
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(* 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:42
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:47
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
locale_t time_c_locale
Current locale but LC_TIME=C.
Definition: neomutt.h:48
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:297
@ MENU_INDEX
Index panel (list of emails)
Definition: type.h:51
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:239
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:124