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