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