NeoMutt  2025-12-11-800-ga0ee0f
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
mailbox.c
Go to the documentation of this file.
1
23
29
30#include "config.h"
31#include <dirent.h>
32#include <errno.h>
33#include <limits.h>
34#include <stdio.h>
35#include <string.h>
36#include <sys/stat.h>
37#include <unistd.h>
38#include "mutt/lib.h"
39#include "config/lib.h"
40#include "email/lib.h"
41#include "mailbox.h"
42#include "progress/lib.h"
43#include "edata.h"
44#include "hcache.h"
45#include "mdata.h"
46#include "mdemail.h"
47#include "mx.h"
48#include "shared.h"
49#ifdef USE_INOTIFY
50#include "monitor.h"
51#endif
52
53struct Progress;
54
55// Flags for maildir_check()
56#define MMC_NO_DIRS 0
57#define MMC_NEW_DIR (1 << 0)
58#define MMC_CUR_DIR (1 << 1)
59
69{
70 struct Email *e = email_new();
73
74 return e;
75}
76
82void maildir_parse_flags(struct Email *e, const char *path)
83{
84 char *q = NULL;
85
86 e->flagged = false;
87 e->read = false;
88 e->replied = false;
89
91 if (!edata)
92 {
94 edata = e->edata;
95 }
96
97 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
98 char *p = strrchr(path, c_maildir_field_delimiter);
99 if (p && mutt_str_startswith(p + 1, "2,"))
100 {
101 p += 3;
102
103 mutt_str_replace(&edata->custom_flags, p);
104 q = edata->custom_flags;
105
106 while (*p)
107 {
108 switch (*p)
109 {
110 case 'F': // Flagged
111 e->flagged = true;
112 break;
113
114 case 'R': // Replied
115 e->replied = true;
116 break;
117
118 case 'S': // Seen
119 e->read = true;
120 break;
121
122 case 'T': // Trashed
123 {
124 const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
125 if (!e->flagged || !c_flag_safe)
126 {
127 e->trash = true;
128 e->deleted = true;
129 }
130 break;
131 }
132
133 default:
134 *q++ = *p;
135 break;
136 }
137 p++;
138 }
139 }
140
141 if (q == edata->custom_flags)
142 FREE(&edata->custom_flags);
143 else if (q)
144 *q = '\0';
145}
146
158bool maildir_parse_stream(FILE *fp, const char *fname, bool is_old, struct Email *e)
159{
160 if (!fp || !fname || !e)
161 return false;
162
163 const long size = mutt_file_get_size_fp(fp);
164 if (size == 0)
165 return false;
166
167 e->env = mutt_rfc822_read_header(fp, e, false, false);
168
169 if (e->received == 0)
170 e->received = e->date_sent;
171
172 /* always update the length since we have fresh information available. */
173 e->body->length = size - e->body->offset;
174
175 e->index = -1;
176
177 /* maildir stores its flags in the filename, so ignore the
178 * flags in the header of the message */
179 e->old = is_old;
180 maildir_parse_flags(e, fname);
181
182 return true;
183}
184
195bool maildir_parse_message(const char *fname, bool is_old, struct Email *e)
196{
197 if (!fname || !e)
198 return false;
199
200 FILE *fp = mutt_file_fopen(fname, "r");
201 if (!fp)
202 return false;
203
204 bool rc = maildir_parse_stream(fp, fname, is_old, e);
205 mutt_file_fclose(&fp);
206 return rc;
207}
208
216static int maildir_move_to_mailbox(struct Mailbox *m, const struct MdEmailArray *mda)
217{
218 if (!m)
219 return 0;
220
221 int oldmsgcount = m->msg_count;
222
223 struct MdEmail *md = NULL;
224 struct MdEmail **mdp = NULL;
225 ARRAY_FOREACH(mdp, mda)
226 {
227 md = *mdp;
228 mutt_debug(LL_DEBUG2, "Considering %s\n", NONULL(md->canon_fname));
229 if (!md->email)
230 continue;
231
232 mutt_debug(LL_DEBUG2, "Adding header structure. Flags: %s%s%s%s%s\n",
233 md->email->flagged ? "f" : "", md->email->deleted ? "D" : "",
234 md->email->replied ? "r" : "", md->email->old ? "O" : "",
235 md->email->read ? "R" : "");
237
238 m->emails[m->msg_count] = md->email;
239 m->emails[m->msg_count]->index = m->msg_count;
240 mailbox_size_add(m, md->email);
241
242 md->email = NULL;
243 m->msg_count++;
244 }
245
246 int num = 0;
247 if (m->msg_count > oldmsgcount)
248 num = m->msg_count - oldmsgcount;
249
250 return num;
251}
252
256static int maildir_sort_inode(const void *a, const void *b, void *sdata)
257{
258 const struct MdEmail *ma = *(struct MdEmail **) a;
259 const struct MdEmail *mb = *(struct MdEmail **) b;
260
261 return mutt_numeric_cmp(ma->inode, mb->inode);
262}
263
274static int maildir_parse_dir(struct Mailbox *m, struct MdEmailArray *mda,
275 const char *subdir, struct Progress *progress)
276{
277 struct dirent *de = NULL;
278 int rc = 0;
279 bool is_old = false;
280 struct MdEmail *entry = NULL;
281 struct Email *e = NULL;
282
283 struct Buffer *buf = buf_pool_get();
284
285 buf_printf(buf, "%s/%s", mailbox_path(m), subdir);
286 is_old = mutt_str_equal("cur", subdir);
287
289 if (!dir)
290 {
291 rc = -1;
292 goto cleanup;
293 }
294
295 while (((de = readdir(dir))) && !SigInt)
296 {
297 if (*de->d_name == '.')
298 continue;
299
300 mutt_debug(LL_DEBUG2, "queueing %s\n", de->d_name);
301
302 e = maildir_email_new();
303 e->old = is_old;
304 maildir_parse_flags(e, de->d_name);
305
306 progress_update(progress, ARRAY_SIZE(mda) + 1, -1);
307
308 buf_printf(buf, "%s/%s", subdir, de->d_name);
309 e->path = buf_strdup(buf);
310
311 entry = maildir_entry_new();
312 entry->email = e;
313 entry->inode = de->d_ino;
314 ARRAY_ADD(mda, entry);
315 }
316
317 closedir(dir);
318
319 if (SigInt)
320 {
321 SigInt = false;
322 rc = -2; /* action aborted */
323 goto cleanup;
324 }
325
326 ARRAY_SORT(mda, maildir_sort_inode, NULL);
327
328cleanup:
329 buf_pool_release(&buf);
330
331 return rc;
332}
333
340static void maildir_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda,
341 struct Progress *progress)
342{
343 char fn[PATH_MAX] = { 0 };
344
345 struct HeaderCache *hc = maildir_hcache_open(m);
346
347 struct MdEmail *md = NULL;
348 struct MdEmail **mdp = NULL;
349 ARRAY_FOREACH(mdp, mda)
350 {
351 md = *mdp;
352 if (!md || !md->email || md->header_parsed)
353 continue;
354
355 progress_update(progress, ARRAY_FOREACH_IDX_mdp, -1);
356
357 snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
358
359 struct Email *e = maildir_hcache_read(hc, md->email, fn);
360 if (e)
361 {
362 email_free(&md->email);
363 md->email = e;
364 }
365 else
366 {
367 if (maildir_parse_message(fn, md->email->old, md->email))
368 {
369 md->header_parsed = true;
371 }
372 else
373 {
374 email_free(&md->email);
375 }
376 }
377 }
378
380}
381
391static void maildir_check_dir(struct Mailbox *m, const char *dir_name,
392 bool check_new, bool check_stats)
393{
394 DIR *dir = NULL;
395 struct dirent *de = NULL;
396 char *p = NULL;
397 struct stat st = { 0 };
398
399 struct Buffer *path = buf_pool_get();
400 struct Buffer *msgpath = buf_pool_get();
401 buf_printf(path, "%s/%s", mailbox_path(m), dir_name);
402
403 /* when $mail_check_recent is set, if the new/ directory hasn't been modified since
404 * the user last exited the mailbox, then we know there is no recent mail. */
405 const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
406 if (check_new && c_mail_check_recent)
407 {
408 if ((stat(buf_string(path), &st) == 0) &&
410 {
411 check_new = false;
412 }
413 }
414
415 if (!(check_new || check_stats))
416 goto cleanup;
417
419 if (!dir)
420 {
421 m->type = MUTT_UNKNOWN;
422 goto cleanup;
423 }
424
425 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
426
427 char delimiter_version[8] = { 0 };
428 snprintf(delimiter_version, sizeof(delimiter_version), "%c2,", c_maildir_field_delimiter);
429 while ((de = readdir(dir)))
430 {
431 if (*de->d_name == '.')
432 continue;
433
434 p = strstr(de->d_name, delimiter_version);
435 if (p && strchr(p + 3, 'T'))
436 continue;
437
438 if (check_stats)
439 {
440 m->msg_count++;
441 if (p && strchr(p + 3, 'F'))
442 m->msg_flagged++;
443 }
444 if (!p || !strchr(p + 3, 'S'))
445 {
446 if (check_stats)
447 m->msg_unread++;
448 if (check_new)
449 {
450 if (c_mail_check_recent)
451 {
452 buf_printf(msgpath, "%s/%s", buf_string(path), de->d_name);
453 /* ensure this message was received since leaving this m */
454 if ((stat(buf_string(msgpath), &st) == 0) &&
456 {
457 continue;
458 }
459 }
460 m->has_new = true;
461 if (check_stats)
462 {
463 m->msg_new++;
464 }
465 else
466 {
467 break;
468 }
469 }
470 }
471 }
472
473 closedir(dir);
474
475cleanup:
476 buf_pool_release(&path);
477 buf_pool_release(&msgpath);
478}
479
487static int maildir_read_dir(struct Mailbox *m, const char *subdir)
488{
489 if (!m)
490 return -1;
491
492 mutt_path_tidy(&m->pathbuf, true);
493
494 struct Progress *progress = NULL;
495
496 if (m->verbose)
497 {
498 progress = progress_new(MUTT_PROGRESS_READ, 0);
499 progress_set_message(progress, _("Scanning %s..."), mailbox_path(m));
500 }
501
503 if (!mdata)
504 {
506 m->mdata = mdata;
508 }
509
510 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
511 int rc = maildir_parse_dir(m, &mda, subdir, progress);
512 progress_free(&progress);
513 if (rc < 0)
514 return -1;
515
516 if (m->verbose)
517 {
518 progress = progress_new(MUTT_PROGRESS_READ, ARRAY_SIZE(&mda));
519 progress_set_message(progress, _("Reading %s..."), mailbox_path(m));
520 }
521 maildir_delayed_parsing(m, &mda, progress);
522 progress_free(&progress);
523
525 maildirarray_clear(&mda);
526
527 if (!mdata->umask)
528 mdata->umask = maildir_umask(m);
529
530 return 0;
531}
532
545static enum MxStatus maildir_check(struct Mailbox *m)
546{
547 struct stat st_new = { 0 }; /* status of the "new" subdirectory */
548 struct stat st_cur = { 0 }; /* status of the "cur" subdirectory */
549 int changed = MMC_NO_DIRS; /* which subdirectories have changed */
550 bool occult = false; /* messages were removed from the mailbox */
551 int num_new = 0; /* number of new messages added to the mailbox */
552 bool flags_changed = false; /* message flags were changed in the mailbox */
553 struct HashTable *hash_names = NULL; // Hash Table: "base-filename" -> MdEmail
555 if (!mdata)
556 return MX_STATUS_ERROR;
557
558 const bool c_check_new = cs_subset_bool(NeoMutt->sub, "check_new");
559 if (!c_check_new)
560 return MX_STATUS_OK;
561
562 struct Buffer *buf = buf_pool_get();
563 buf_printf(buf, "%s/new", mailbox_path(m));
564 if (stat(buf_string(buf), &st_new) == -1)
565 {
566 buf_pool_release(&buf);
567 return MX_STATUS_ERROR;
568 }
569
570 buf_printf(buf, "%s/cur", mailbox_path(m));
571 if (stat(buf_string(buf), &st_cur) == -1)
572 {
573 buf_pool_release(&buf);
574 return MX_STATUS_ERROR;
575 }
576
577 /* determine which subdirectories need to be scanned */
578 if (mutt_file_stat_timespec_compare(&st_new, MUTT_STAT_MTIME, &mdata->mtime) > 0)
579 changed = MMC_NEW_DIR;
581 changed |= MMC_CUR_DIR;
582
583 if (changed == MMC_NO_DIRS)
584 {
585 buf_pool_release(&buf);
586 return MX_STATUS_OK; /* nothing to do */
587 }
588
589 /* Update the modification times on the mailbox.
590 *
591 * The monitor code notices changes in the open mailbox too quickly.
592 * In practice, this sometimes leads to all the new messages not being
593 * noticed during the SAME group of mtime stat updates. To work around
594 * the problem, don't update the stat times for a monitor caused check. */
595#ifdef USE_INOTIFY
597 {
598 MonitorCurMboxChanged = false;
599 }
600 else
601#endif
602 {
605 }
606
607 /* do a fast scan of just the filenames in
608 * the subdirectories that have changed. */
609 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
610 if (changed & MMC_NEW_DIR)
611 maildir_parse_dir(m, &mda, "new", NULL);
612 if (changed & MMC_CUR_DIR)
613 maildir_parse_dir(m, &mda, "cur", NULL);
614
615 /* we create a hash table keyed off the canonical (sans flags) filename
616 * of each message we scanned. This is used in the loop over the
617 * existing messages below to do some correlation. */
618 hash_names = mutt_hash_new(ARRAY_SIZE(&mda), MUTT_HASH_NO_FLAGS);
619
620 struct MdEmail *md = NULL;
621 struct MdEmail **mdp = NULL;
622 ARRAY_FOREACH(mdp, &mda)
623 {
624 md = *mdp;
626 md->canon_fname = buf_strdup(buf);
627 mutt_hash_insert(hash_names, md->canon_fname, md);
628 }
629
630 /* check for modifications and adjust flags */
631 for (int i = 0; i < m->msg_count; i++)
632 {
633 struct Email *e = m->emails[i];
634 if (!e)
635 break;
636
638 md = mutt_hash_find(hash_names, buf_string(buf));
639 if (md && md->email)
640 {
641 /* message already exists, merge flags */
642
643 /* check to see if the message has moved to a different
644 * subdirectory. If so, update the associated filename. */
645 if (!mutt_str_equal(e->path, md->email->path))
646 mutt_str_replace(&e->path, md->email->path);
647
648 /* if the user hasn't modified the flags on this message, update
649 * the flags we just detected. */
650 if (!e->changed)
651 if (maildir_update_flags(m, e, md->email))
652 flags_changed = true;
653
654 if (e->deleted == e->trash)
655 {
656 if (e->deleted != md->email->deleted)
657 {
658 e->deleted = md->email->deleted;
659 flags_changed = true;
660 }
661 }
662 e->trash = md->email->trash;
663
664 /* this is a duplicate of an existing email, so remove it */
665 email_free(&md->email);
666 }
667 /* This message was not in the list of messages we just scanned.
668 * Check to see if we have enough information to know if the
669 * message has disappeared out from underneath us. */
670 else if (((changed & MMC_NEW_DIR) && mutt_strn_equal(e->path, "new/", 4)) ||
671 ((changed & MMC_CUR_DIR) && mutt_strn_equal(e->path, "cur/", 4)))
672 {
673 /* This message disappeared, so we need to simulate a "reopen"
674 * event. We know it disappeared because we just scanned the
675 * subdirectory it used to reside in. */
676 occult = true;
677 e->deleted = true;
678 e->purge = true;
679 }
680 else
681 {
682 /* This message resides in a subdirectory which was not
683 * modified, so we assume that it is still present and
684 * unchanged. */
685 }
686 }
687
688 /* destroy the file name hash */
689 mutt_hash_free(&hash_names);
690
691 /* If we didn't just get new mail, update the tables. */
692 if (occult)
694
695 /* do any delayed parsing we need to do. */
696 maildir_delayed_parsing(m, &mda, NULL);
697
698 /* Incorporate new messages */
699 num_new = maildir_move_to_mailbox(m, &mda);
700 maildirarray_clear(&mda);
701
702 if (num_new > 0)
703 {
705 m->changed = true;
706 }
707
708 buf_pool_release(&buf);
709
710 ARRAY_FREE(&mda);
711 if (occult)
712 return MX_STATUS_REOPENED;
713 if (num_new > 0)
714 return MX_STATUS_NEW_MAIL;
715 if (flags_changed)
716 return MX_STATUS_FLAGS;
717 return MX_STATUS_OK;
718}
719
725{
726 char buf[PATH_MAX] = { 0 };
727 struct stat st = { 0 };
729 if (!mdata)
730 return;
731
732 snprintf(buf, sizeof(buf), "%s/%s", mailbox_path(m), "cur");
733 if (stat(buf, &st) == 0)
735
736 snprintf(buf, sizeof(buf), "%s/%s", mailbox_path(m), "new");
737 if (stat(buf, &st) == 0)
739}
740
741// Mailbox API -----------------------------------------------------------------
742
747{
748 if ((maildir_read_dir(m, "new") == -1) || (maildir_read_dir(m, "cur") == -1))
749 return MX_OPEN_ERROR;
750
751 return MX_OPEN_OK;
752}
753
758{
759 if (!(flags & (MUTT_APPEND | MUTT_APPENDNEW)))
760 {
761 return true;
762 }
763
764 errno = 0;
765 if ((mutt_file_mkdir(mailbox_path(m), S_IRWXU) != 0) && (errno != EEXIST))
766 {
767 mutt_perror("%s", mailbox_path(m));
768 return false;
769 }
770
771 char tmp[PATH_MAX] = { 0 };
772 snprintf(tmp, sizeof(tmp), "%s/cur", mailbox_path(m));
773 errno = 0;
774 if ((mkdir(tmp, S_IRWXU) != 0) && (errno != EEXIST))
775 {
776 mutt_perror("%s", tmp);
777 rmdir(mailbox_path(m));
778 return false;
779 }
780
781 snprintf(tmp, sizeof(tmp), "%s/new", mailbox_path(m));
782 errno = 0;
783 if ((mkdir(tmp, S_IRWXU) != 0) && (errno != EEXIST))
784 {
785 mutt_perror("%s", tmp);
786 snprintf(tmp, sizeof(tmp), "%s/cur", mailbox_path(m));
787 rmdir(tmp);
788 rmdir(mailbox_path(m));
789 return false;
790 }
791
792 snprintf(tmp, sizeof(tmp), "%s/tmp", mailbox_path(m));
793 errno = 0;
794 if ((mkdir(tmp, S_IRWXU) != 0) && (errno != EEXIST))
795 {
796 mutt_perror("%s", tmp);
797 snprintf(tmp, sizeof(tmp), "%s/cur", mailbox_path(m));
798 rmdir(tmp);
799 snprintf(tmp, sizeof(tmp), "%s/new", mailbox_path(m));
800 rmdir(tmp);
801 rmdir(mailbox_path(m));
802 return false;
803 }
804
805 return true;
806}
807
812{
813 return maildir_check(m);
814}
815
819enum MxStatus maildir_mbox_check_stats(struct Mailbox *m, uint8_t flags)
820{
821 bool check_stats = flags & MUTT_MAILBOX_CHECK_STATS;
822 bool check_new = true;
823
824 if (check_stats)
825 {
826 m->msg_new = 0;
827 m->msg_count = 0;
828 m->msg_unread = 0;
829 m->msg_flagged = 0;
830 }
831
832 maildir_check_dir(m, "new", check_new, check_stats);
833
834 const bool c_maildir_check_cur = cs_subset_bool(NeoMutt->sub, "maildir_check_cur");
835 check_new = !m->has_new && c_maildir_check_cur;
836 if (check_new || check_stats)
837 maildir_check_dir(m, "cur", check_new, check_stats);
838
840}
841
849{
850 enum MxStatus check = maildir_check(m);
851 if (check == MX_STATUS_ERROR)
852 return check;
853
854 struct HeaderCache *hc = maildir_hcache_open(m);
855
856 struct Progress *progress = NULL;
857 if (m->verbose)
858 {
860 progress_set_message(progress, _("Writing %s..."), mailbox_path(m));
861 }
862
863 for (int i = 0; i < m->msg_count; i++)
864 {
865 progress_update(progress, i, -1);
866
867 struct Email *e = m->emails[i];
868 if (!maildir_sync_mailbox_message(m, e, hc))
869 {
870 progress_free(&progress);
871 goto err;
872 }
873 }
874 progress_free(&progress);
876
877 /* XXX race condition? */
878
880
881 /* adjust indices */
882
883 if (m->msg_deleted)
884 {
885 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
886 for (int i = 0, j = 0; i < m->msg_count; i++)
887 {
888 struct Email *e = m->emails[i];
889 if (!e)
890 break;
891
892 if (!e->deleted || c_maildir_trash)
893 e->index = j++;
894 }
895 }
896
897 return check;
898
899err:
901 return MX_STATUS_ERROR;
902}
903
909{
910 return MX_STATUS_OK;
911}
#define ARRAY_SORT(head, fn, sdata)
Sort an array.
Definition array.h:373
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
#define mutt_numeric_cmp(a, b)
Compare two numbers, return -1, 0, or 1.
Definition sort.h:27
const char * cc_maildir_field_delimiter(void)
Get the cached value of $maildir_field_delimiter.
void mailbox_size_add(struct Mailbox *m, const struct Email *e)
Add an email's size to the total size of a Mailbox.
Definition mailbox.c:248
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition mailbox.c:232
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition mailbox.h:180
@ NT_MAILBOX_INVALID
Email list was changed.
Definition mailbox.h:179
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:213
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition mailbox.h:43
struct Email * email_new(void)
Create a new Email.
Definition email.c:77
void email_free(struct Email **ptr)
Free an Email.
Definition email.c:46
Structs that make up an email.
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition parse.c:1175
void mutt_file_get_stat_timespec(struct timespec *dest, struct stat *st, enum MuttStatType type)
Read the stat() time into a time value.
Definition file.c:1474
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition file.c:844
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1432
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition file.c:535
int mutt_file_stat_timespec_compare(struct stat *st, enum MuttStatType type, struct timespec *b)
Compare stat info with a time value.
Definition file.c:1514
@ MUTT_OPENDIR_CREATE
Create the directory if it doesn't exist.
Definition file.h:64
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
@ MUTT_STAT_CTIME
File/dir's ctime - creation time.
Definition file.h:55
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition file.h:54
void maildir_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free() -.
Definition edata.c:38
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
void maildir_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free() -.
Definition mdata.c:37
enum MxStatus maildir_mbox_check_stats(struct Mailbox *m, uint8_t flags)
Check the Mailbox statistics - Implements MxOps::mbox_check_stats() -.
Definition mailbox.c:819
enum MxStatus maildir_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition mailbox.c:811
enum MxStatus maildir_mbox_close(struct Mailbox *m)
Close a Mailbox - Implements MxOps::mbox_close() -.
Definition mailbox.c:908
bool maildir_mbox_open_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a Mailbox for appending - Implements MxOps::mbox_open_append() -.
Definition mailbox.c:757
enum MxOpenReturns maildir_mbox_open(struct Mailbox *m)
Open a Mailbox - Implements MxOps::mbox_open() -.
Definition mailbox.c:746
enum MxStatus maildir_mbox_sync(struct Mailbox *m)
Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
Definition mailbox.c:848
static int maildir_sort_inode(const void *a, const void *b, void *sdata)
Compare two Maildirs by inode number - Implements sort_t -.
Definition mailbox.c:256
struct HashElem * mutt_hash_insert(struct HashTable *table, const char *strkey, void *data)
Add a new element to the Hash Table (with string keys)
Definition hash.c:337
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition hash.c:364
struct HashTable * mutt_hash_new(size_t num_elems, HashFlags flags)
Create a new Hash Table (with string keys)
Definition hash.c:261
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition hash.c:459
#define MUTT_HASH_NO_FLAGS
No flags are set.
Definition hash.h:111
Maildir Header Cache.
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
struct MaildirEmailData * maildir_edata_get(struct Email *e)
Get the private data for this Email.
Definition edata.c:63
struct MaildirEmailData * maildir_edata_new(void)
Create a new MaildirEmailData object.
Definition edata.c:53
Maildir-specific Email data.
int maildir_hcache_store(struct HeaderCache *hc, struct Email *e)
Save an Email to the Header Cache.
Definition hcache.c:163
struct Email * maildir_hcache_read(struct HeaderCache *hc, struct Email *e, const char *fn)
Read an Email from the Header Cache.
Definition hcache.c:121
struct HeaderCache * maildir_hcache_open(struct Mailbox *m)
Open the Header Cache.
Definition hcache.c:104
void maildir_hcache_close(struct HeaderCache **ptr)
Close the Header Cache.
Definition hcache.c:77
static enum MxStatus maildir_check(struct Mailbox *m)
Check for new mail.
Definition mailbox.c:545
static void maildir_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
This function does the second parsing pass.
Definition mailbox.c:340
static int maildir_read_dir(struct Mailbox *m, const char *subdir)
Read a Maildir style mailbox.
Definition mailbox.c:487
bool maildir_parse_message(const char *fname, bool is_old, struct Email *e)
Actually parse a maildir message.
Definition mailbox.c:195
void maildir_update_mtime(struct Mailbox *m)
Update our record of the Maildir modification time.
Definition mailbox.c:724
static int maildir_move_to_mailbox(struct Mailbox *m, const struct MdEmailArray *mda)
Copy the Maildir list to the Mailbox.
Definition mailbox.c:216
#define MMC_CUR_DIR
'cur' directory changed
Definition mailbox.c:58
struct Email * maildir_email_new(void)
Create a Maildir Email.
Definition mailbox.c:68
#define MMC_NO_DIRS
No directories changed.
Definition mailbox.c:56
static void maildir_check_dir(struct Mailbox *m, const char *dir_name, bool check_new, bool check_stats)
Check for new mail / mail counts.
Definition mailbox.c:391
static int maildir_parse_dir(struct Mailbox *m, struct MdEmailArray *mda, const char *subdir, struct Progress *progress)
Read a Maildir mailbox.
Definition mailbox.c:274
#define MMC_NEW_DIR
'new' directory changed
Definition mailbox.c:57
bool maildir_parse_stream(FILE *fp, const char *fname, bool is_old, struct Email *e)
Parse a Maildir message.
Definition mailbox.c:158
void maildir_parse_flags(struct Email *e, const char *path)
Parse Maildir file flags.
Definition mailbox.c:82
Maildir Mailbox.
struct MaildirMboxData * maildir_mdata_get(struct Mailbox *m)
Get the private data for this Mailbox.
Definition mdata.c:59
struct MaildirMboxData * maildir_mdata_new(void)
Create a new MaildirMboxData object.
Definition mdata.c:49
Maildir-specific Mailbox data.
bool maildir_sync_mailbox_message(struct Mailbox *m, struct Email *e, struct HeaderCache *hc)
Save changes to the mailbox.
Definition message.c:315
bool maildir_update_flags(struct Mailbox *m, struct Email *e_old, struct Email *e_new)
Update the mailbox flags.
Definition shared.c:104
mode_t maildir_umask(struct Mailbox *m)
Create a umask from the mailbox directory.
Definition shared.c:46
void maildir_canon_filename(struct Buffer *dest, const char *src)
Generate the canonical filename for a Maildir folder.
Definition shared.c:72
Maildir shared functions.
struct MdEmail * maildir_entry_new(void)
Create a new Maildir entry.
Definition mdemail.c:39
void maildirarray_clear(struct MdEmailArray *mda)
Free a Maildir array.
Definition mdemail.c:64
Maildir Email helper.
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
bool MonitorCurMboxChanged
Set to true when the current mailbox has changed.
Definition monitor.c:55
Monitor files for changes.
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
bool mutt_path_tidy(struct Buffer *path, bool is_dir)
Remove unnecessary parts of a path.
Definition path.c:169
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition string.c:429
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
#define PATH_MAX
Definition mutt.h:49
void mx_alloc_memory(struct Mailbox *m, int req_size)
Create storage for the emails.
Definition mx.c:1208
API for mailboxes.
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition mxapi.h:38
#define MUTT_MAILBOX_CHECK_STATS
Ignore mail_check_stats and calculate statistics (used by <check-stats>)
Definition mxapi.h:51
#define MUTT_APPEND
Open mailbox for appending messages.
Definition mxapi.h:41
MxOpenReturns
Return values for mbox_open()
Definition mxapi.h:72
@ MX_OPEN_ERROR
Open failed with an error.
Definition mxapi.h:74
@ MX_OPEN_OK
Open succeeded.
Definition mxapi.h:73
#define MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn't exist.
Definition mxapi.h:45
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition mxapi.h:59
@ MX_STATUS_ERROR
An error occurred.
Definition mxapi.h:60
@ MX_STATUS_OK
No changes.
Definition mxapi.h:61
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition mxapi.h:65
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition mxapi.h:64
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition mxapi.h:62
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
Progress Bar.
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition lib.h:84
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition lib.h:85
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition progress.c:139
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition progress.c:110
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition progress.c:80
volatile sig_atomic_t SigInt
true after SIGINT is received
Definition signal.c:68
#define NONULL(x)
Definition string2.h:44
LOFF_T offset
offset where the actual data begins
Definition body.h:52
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
String manipulation buffer.
Definition buffer.h:36
The envelope/body of an email.
Definition email.h:39
bool read
Email is read.
Definition email.h:50
bool purge
Skip trash folder when deleting.
Definition email.h:79
struct Envelope * env
Envelope information.
Definition email.h:68
void * edata
Driver-specific data.
Definition email.h:74
struct Body * body
List of MIME parts.
Definition email.h:69
bool old
Email is seen, but unread.
Definition email.h:49
void(* edata_free)(void **ptr)
Definition email.h:90
bool changed
Email has been edited.
Definition email.h:77
bool flagged
Marked important?
Definition email.h:47
time_t date_sent
Time when the message was sent (UTC)
Definition email.h:60
bool replied
Email has been replied to.
Definition email.h:51
char * path
Path of Email (for local Mailboxes)
Definition email.h:70
bool deleted
Email is deleted.
Definition email.h:78
int index
The absolute (unsorted) message number.
Definition email.h:110
bool trash
Message is marked as trashed on disk (used by the maildir_trash option)
Definition email.h:53
time_t received
Time when the message was placed in the mailbox.
Definition email.h:61
A Hash Table.
Definition hash.h:99
Header Cache.
Definition lib.h:87
A mailbox.
Definition mailbox.h:78
void(* mdata_free)(void **ptr)
Definition mailbox.h:142
bool changed
Mailbox has been modified.
Definition mailbox.h:109
bool has_new
Mailbox has new mail.
Definition mailbox.h:84
int msg_new
Number of new messages.
Definition mailbox.h:91
int msg_count
Total number of messages.
Definition mailbox.h:87
enum MailboxType type
Mailbox type.
Definition mailbox.h:101
void * mdata
Driver specific data.
Definition mailbox.h:131
struct Email ** emails
Array of Emails.
Definition mailbox.h:95
struct Buffer pathbuf
Path of the Mailbox.
Definition mailbox.h:79
int msg_deleted
Number of deleted messages.
Definition mailbox.h:92
int msg_flagged
Number of flagged messages.
Definition mailbox.h:89
struct timespec last_visited
Time of last exit from this mailbox.
Definition mailbox.h:103
bool verbose
Display status messages?
Definition mailbox.h:116
int msg_unread
Number of unread messages.
Definition mailbox.h:88
Maildir-specific Email data -.
Definition edata.h:32
Maildir-specific Mailbox data -.
Definition mdata.h:35
struct timespec mtime_cur
Timestamp of the 'cur' dir.
Definition mdata.h:37
mode_t umask
umask to use when creating files
Definition mdata.h:38
struct timespec mtime
Time Mailbox was last changed.
Definition mdata.h:36
A Maildir Email helper.
Definition mdemail.h:34
bool header_parsed
Has the Email header been parsed?
Definition mdemail.h:37
char * canon_fname
Canonical filename for hashing.
Definition mdemail.h:36
struct Email * email
Temporary Email.
Definition mdemail.h:35
ino_t inode
Inode number of the file.
Definition mdemail.h:38
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49