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