NeoMutt  2025-12-11-949-g4870ee
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 {
95 edata = e->edata;
96 }
97
98 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
99 const char *p = strrchr(path, c_maildir_field_delimiter);
100 if (p && mutt_str_startswith(p + 1, "2,"))
101 {
102 p += 3;
103
104 mutt_str_replace(&edata->custom_flags, p);
105 q = edata->custom_flags;
106
107 while (*p)
108 {
109 switch (*p)
110 {
111 case 'F': // Flagged
112 e->flagged = true;
113 break;
114
115 case 'R': // Replied
116 e->replied = true;
117 break;
118
119 case 'S': // Seen
120 e->read = true;
121 break;
122
123 case 'T': // Trashed
124 {
125 const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
126 if (!e->flagged || !c_flag_safe)
127 {
128 e->trash = true;
129 e->deleted = true;
130 }
131 break;
132 }
133
134 default:
135 *q++ = *p;
136 break;
137 }
138 p++;
139 }
140 }
141
142 if (q == edata->custom_flags)
143 FREE(&edata->custom_flags);
144 else if (q)
145 *q = '\0';
146}
147
159bool maildir_parse_stream(FILE *fp, const char *fname, bool is_old, struct Email *e)
160{
161 if (!fp || !fname || !e)
162 return false;
163
164 const long size = mutt_file_get_size_fp(fp);
165 if (size == 0)
166 return false;
167
168 e->env = mutt_rfc822_read_header(fp, e, false, false);
169
170 if (e->received == 0)
171 e->received = e->date_sent;
172
173 /* always update the length since we have fresh information available. */
174 e->body->length = size - e->body->offset;
175
176 e->index = -1;
177
178 /* maildir stores its flags in the filename, so ignore the
179 * flags in the header of the message */
180 e->old = is_old;
181 maildir_parse_flags(e, fname);
182
183 return true;
184}
185
196bool maildir_parse_message(const char *fname, bool is_old, struct Email *e)
197{
198 if (!fname || !e)
199 return false;
200
201 FILE *fp = mutt_file_fopen(fname, "r");
202 if (!fp)
203 return false;
204
205 bool rc = maildir_parse_stream(fp, fname, is_old, e);
206 mutt_file_fclose(&fp);
207 return rc;
208}
209
217static int maildir_move_to_mailbox(struct Mailbox *m, const struct MdEmailArray *mda)
218{
219 if (!m)
220 return 0;
221
222 int oldmsgcount = m->msg_count;
223
224 struct MdEmail *md = NULL;
225 struct MdEmail **mdp = NULL;
226 ARRAY_FOREACH(mdp, mda)
227 {
228 md = *mdp;
229 mutt_debug(LL_DEBUG2, "Considering %s\n", NONULL(md->canon_fname));
230 if (!md->email)
231 continue;
232
233 mutt_debug(LL_DEBUG2, "Adding header structure. Flags: %s%s%s%s%s\n",
234 md->email->flagged ? "f" : "", md->email->deleted ? "D" : "",
235 md->email->replied ? "r" : "", md->email->old ? "O" : "",
236 md->email->read ? "R" : "");
238
239 m->emails[m->msg_count] = md->email;
240 m->emails[m->msg_count]->index = m->msg_count;
241 mailbox_size_add(m, md->email);
242
243 md->email = NULL;
244 m->msg_count++;
245 }
246
247 int num = 0;
248 if (m->msg_count > oldmsgcount)
249 num = m->msg_count - oldmsgcount;
250
251 return num;
252}
253
257static int maildir_sort_inode(const void *a, const void *b, void *sdata)
258{
259 const struct MdEmail *ma = *(struct MdEmail **) a;
260 const struct MdEmail *mb = *(struct MdEmail **) b;
261
262 return mutt_numeric_cmp(ma->inode, mb->inode);
263}
264
275static int maildir_parse_dir(struct Mailbox *m, struct MdEmailArray *mda,
276 const char *subdir, struct Progress *progress)
277{
278 struct dirent *de = NULL;
279 int rc = 0;
280 bool is_old = false;
281 struct MdEmail *entry = NULL;
282 struct Email *e = NULL;
283
284 struct Buffer *buf = buf_pool_get();
285
286 buf_printf(buf, "%s/%s", mailbox_path(m), subdir);
287 is_old = mutt_str_equal("cur", subdir);
288
290 if (!dir)
291 {
292 rc = -1;
293 goto cleanup;
294 }
295
296 while (((de = readdir(dir))) && !SigInt)
297 {
298 if (*de->d_name == '.')
299 continue;
300
301 mutt_debug(LL_DEBUG2, "queueing %s\n", de->d_name);
302
303 e = maildir_email_new();
304 e->old = is_old;
305 maildir_parse_flags(e, de->d_name);
306
307 progress_update(progress, ARRAY_SIZE(mda) + 1, -1);
308
309 buf_printf(buf, "%s/%s", subdir, de->d_name);
310 e->path = buf_strdup(buf);
311
312 entry = maildir_entry_new();
313 entry->email = e;
314 entry->inode = de->d_ino;
315 ARRAY_ADD(mda, entry);
316 }
317
318 closedir(dir);
319
320 if (SigInt)
321 {
322 SigInt = false;
323 rc = -2; /* action aborted */
324 goto cleanup;
325 }
326
327 ARRAY_SORT(mda, maildir_sort_inode, NULL);
328
329cleanup:
330 buf_pool_release(&buf);
331
332 return rc;
333}
334
341static void maildir_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda,
342 struct Progress *progress)
343{
344 char fn[PATH_MAX] = { 0 };
345
346 struct HeaderCache *hc = maildir_hcache_open(m);
347
348 struct MdEmail *md = NULL;
349 struct MdEmail **mdp = NULL;
350 ARRAY_FOREACH(mdp, mda)
351 {
352 md = *mdp;
353 if (!md || !md->email || md->header_parsed)
354 continue;
355
356 progress_update(progress, ARRAY_FOREACH_IDX_mdp, -1);
357
358 snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
359
360 struct Email *e = maildir_hcache_read(hc, md->email, fn);
361 if (e)
362 {
363 email_free(&md->email);
364 md->email = e;
365 }
366 else
367 {
368 if (maildir_parse_message(fn, md->email->old, md->email))
369 {
370 md->header_parsed = true;
372 }
373 else
374 {
375 email_free(&md->email);
376 }
377 }
378 }
379
381}
382
392static void maildir_check_dir(struct Mailbox *m, const char *dir_name,
393 bool check_new, bool check_stats)
394{
395 DIR *dir = NULL;
396 struct dirent *de = NULL;
397 char *p = NULL;
398 struct stat st = { 0 };
399
400 struct Buffer *path = buf_pool_get();
401 struct Buffer *msgpath = buf_pool_get();
402 buf_printf(path, "%s/%s", mailbox_path(m), dir_name);
403
404 /* when $mail_check_recent is set, if the new/ directory hasn't been modified since
405 * the user last exited the mailbox, then we know there is no recent mail. */
406 const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
407 if (check_new && c_mail_check_recent)
408 {
409 if ((stat(buf_string(path), &st) == 0) &&
411 {
412 check_new = false;
413 }
414 }
415
416 if (!(check_new || check_stats))
417 goto cleanup;
418
420 if (!dir)
421 {
422 m->type = MUTT_UNKNOWN;
423 goto cleanup;
424 }
425
426 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
427
428 char delimiter_version[8] = { 0 };
429 snprintf(delimiter_version, sizeof(delimiter_version), "%c2,", c_maildir_field_delimiter);
430 while ((de = readdir(dir)))
431 {
432 if (*de->d_name == '.')
433 continue;
434
435 p = strstr(de->d_name, delimiter_version);
436 if (p && strchr(p + 3, 'T'))
437 continue;
438
439 if (check_stats)
440 {
441 m->msg_count++;
442 if (p && strchr(p + 3, 'F'))
443 m->msg_flagged++;
444 }
445 if (!p || !strchr(p + 3, 'S'))
446 {
447 if (check_stats)
448 m->msg_unread++;
449 if (check_new)
450 {
451 if (c_mail_check_recent)
452 {
453 buf_printf(msgpath, "%s/%s", buf_string(path), de->d_name);
454 /* ensure this message was received since leaving this m */
455 if ((stat(buf_string(msgpath), &st) == 0) &&
457 {
458 continue;
459 }
460 }
461 m->has_new = true;
462 if (check_stats)
463 {
464 m->msg_new++;
465 }
466 else
467 {
468 break;
469 }
470 }
471 }
472 }
473
474 closedir(dir);
475
476cleanup:
477 buf_pool_release(&path);
478 buf_pool_release(&msgpath);
479}
480
488static int maildir_read_dir(struct Mailbox *m, const char *subdir)
489{
490 if (!m)
491 return -1;
492
493 mutt_path_tidy(&m->pathbuf, true);
494
495 struct Progress *progress = NULL;
496
497 if (m->verbose)
498 {
499 progress = progress_new(MUTT_PROGRESS_READ, 0);
500 progress_set_message(progress, _("Scanning %s..."), mailbox_path(m));
501 }
502
504 if (!mdata)
505 {
507 m->mdata = mdata;
509 }
510
511 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
512 int rc = maildir_parse_dir(m, &mda, subdir, progress);
513 progress_free(&progress);
514 if (rc < 0)
515 return -1;
516
517 if (m->verbose)
518 {
519 progress = progress_new(MUTT_PROGRESS_READ, ARRAY_SIZE(&mda));
520 progress_set_message(progress, _("Reading %s..."), mailbox_path(m));
521 }
522 maildir_delayed_parsing(m, &mda, progress);
523 progress_free(&progress);
524
526 maildirarray_clear(&mda);
527
528 if (!mdata->umask)
529 mdata->umask = maildir_umask(m);
530
531 return 0;
532}
533
546static enum MxStatus maildir_check(struct Mailbox *m)
547{
548 struct stat st_new = { 0 }; /* status of the "new" subdirectory */
549 struct stat st_cur = { 0 }; /* status of the "cur" subdirectory */
550 int changed = MMC_NO_DIRS; /* which subdirectories have changed */
551 bool occult = false; /* messages were removed from the mailbox */
552 int num_new = 0; /* number of new messages added to the mailbox */
553 bool flags_changed = false; /* message flags were changed in the mailbox */
554 struct HashTable *hash_names = NULL; // Hash Table: "base-filename" -> MdEmail
556 if (!mdata)
557 return MX_STATUS_ERROR;
558
559 const bool c_check_new = cs_subset_bool(NeoMutt->sub, "check_new");
560 if (!c_check_new)
561 return MX_STATUS_OK;
562
563 struct Buffer *buf = buf_pool_get();
564 buf_printf(buf, "%s/new", mailbox_path(m));
565 if (stat(buf_string(buf), &st_new) == -1)
566 {
567 buf_pool_release(&buf);
568 return MX_STATUS_ERROR;
569 }
570
571 buf_printf(buf, "%s/cur", mailbox_path(m));
572 if (stat(buf_string(buf), &st_cur) == -1)
573 {
574 buf_pool_release(&buf);
575 return MX_STATUS_ERROR;
576 }
577
578 /* determine which subdirectories need to be scanned */
579 if (mutt_file_stat_timespec_compare(&st_new, MUTT_STAT_MTIME, &mdata->mtime) > 0)
580 changed = MMC_NEW_DIR;
582 changed |= MMC_CUR_DIR;
583
584 if (changed == MMC_NO_DIRS)
585 {
586 buf_pool_release(&buf);
587 return MX_STATUS_OK; /* nothing to do */
588 }
589
590 /* Update the modification times on the mailbox.
591 *
592 * The monitor code notices changes in the open mailbox too quickly.
593 * In practice, this sometimes leads to all the new messages not being
594 * noticed during the SAME group of mtime stat updates. To work around
595 * the problem, don't update the stat times for a monitor caused check. */
596#ifdef USE_INOTIFY
598 {
599 MonitorCurMboxChanged = false;
600 }
601 else
602#endif
603 {
606 }
607
608 /* do a fast scan of just the filenames in
609 * the subdirectories that have changed. */
610 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
611 if (changed & MMC_NEW_DIR)
612 maildir_parse_dir(m, &mda, "new", NULL);
613 if (changed & MMC_CUR_DIR)
614 maildir_parse_dir(m, &mda, "cur", NULL);
615
616 /* we create a hash table keyed off the canonical (sans flags) filename
617 * of each message we scanned. This is used in the loop over the
618 * existing messages below to do some correlation. */
619 hash_names = mutt_hash_new(ARRAY_SIZE(&mda), MUTT_HASH_NONE);
620
621 struct MdEmail *md = NULL;
622 struct MdEmail **mdp = NULL;
623 ARRAY_FOREACH(mdp, &mda)
624 {
625 md = *mdp;
627 md->canon_fname = buf_strdup(buf);
628 mutt_hash_insert(hash_names, md->canon_fname, md);
629 }
630
631 /* check for modifications and adjust flags */
632 for (int i = 0; i < m->msg_count; i++)
633 {
634 struct Email *e = m->emails[i];
635 if (!e)
636 break;
637
639 md = mutt_hash_find(hash_names, buf_string(buf));
640 if (md && md->email)
641 {
642 /* message already exists, merge flags */
643
644 /* check to see if the message has moved to a different
645 * subdirectory. If so, update the associated filename. */
646 if (!mutt_str_equal(e->path, md->email->path))
647 mutt_str_replace(&e->path, md->email->path);
648
649 /* if the user hasn't modified the flags on this message, update
650 * the flags we just detected. */
651 if (!e->changed)
652 if (maildir_update_flags(m, e, md->email))
653 flags_changed = true;
654
655 if (e->deleted == e->trash)
656 {
657 if (e->deleted != md->email->deleted)
658 {
659 e->deleted = md->email->deleted;
660 flags_changed = true;
661 }
662 }
663 e->trash = md->email->trash;
664
665 /* this is a duplicate of an existing email, so remove it */
666 email_free(&md->email);
667 }
668 /* This message was not in the list of messages we just scanned.
669 * Check to see if we have enough information to know if the
670 * message has disappeared out from underneath us. */
671 else if (((changed & MMC_NEW_DIR) && mutt_strn_equal(e->path, "new/", 4)) ||
672 ((changed & MMC_CUR_DIR) && mutt_strn_equal(e->path, "cur/", 4)))
673 {
674 /* This message disappeared, so we need to simulate a "reopen"
675 * event. We know it disappeared because we just scanned the
676 * subdirectory it used to reside in. */
677 occult = true;
678 e->deleted = true;
679 e->purge = true;
680 }
681 else
682 {
683 /* This message resides in a subdirectory which was not
684 * modified, so we assume that it is still present and
685 * unchanged. */
686 }
687 }
688
689 /* destroy the file name hash */
690 mutt_hash_free(&hash_names);
691
692 /* If we didn't just get new mail, update the tables. */
693 if (occult)
695
696 /* do any delayed parsing we need to do. */
697 maildir_delayed_parsing(m, &mda, NULL);
698
699 /* Incorporate new messages */
700 num_new = maildir_move_to_mailbox(m, &mda);
701 maildirarray_clear(&mda);
702
703 if (num_new > 0)
704 {
706 m->changed = true;
707 }
708
709 buf_pool_release(&buf);
710
711 ARRAY_FREE(&mda);
712 if (occult)
713 return MX_STATUS_REOPENED;
714 if (num_new > 0)
715 return MX_STATUS_NEW_MAIL;
716 if (flags_changed)
717 return MX_STATUS_FLAGS;
718 return MX_STATUS_OK;
719}
720
726{
727 char buf[PATH_MAX] = { 0 };
728 struct stat st = { 0 };
730 if (!mdata)
731 return;
732
733 snprintf(buf, sizeof(buf), "%s/%s", mailbox_path(m), "cur");
734 if (stat(buf, &st) == 0)
736
737 snprintf(buf, sizeof(buf), "%s/%s", mailbox_path(m), "new");
738 if (stat(buf, &st) == 0)
740}
741
742// Mailbox API -----------------------------------------------------------------
743
748{
749 if ((maildir_read_dir(m, "new") == -1) || (maildir_read_dir(m, "cur") == -1))
750 return MX_OPEN_ERROR;
751
752 return MX_OPEN_OK;
753}
754
759{
760 if (!(flags & (MUTT_APPEND | MUTT_APPENDNEW)))
761 {
762 return true;
763 }
764
765 errno = 0;
766 if ((mutt_file_mkdir(mailbox_path(m), S_IRWXU) != 0) && (errno != EEXIST))
767 {
768 mutt_perror("%s", mailbox_path(m));
769 return false;
770 }
771
772 char tmp[PATH_MAX] = { 0 };
773 snprintf(tmp, sizeof(tmp), "%s/cur", mailbox_path(m));
774 errno = 0;
775 if ((mkdir(tmp, S_IRWXU) != 0) && (errno != EEXIST))
776 {
777 mutt_perror("%s", tmp);
778 rmdir(mailbox_path(m));
779 return false;
780 }
781
782 snprintf(tmp, sizeof(tmp), "%s/new", mailbox_path(m));
783 errno = 0;
784 if ((mkdir(tmp, S_IRWXU) != 0) && (errno != EEXIST))
785 {
786 mutt_perror("%s", tmp);
787 snprintf(tmp, sizeof(tmp), "%s/cur", mailbox_path(m));
788 rmdir(tmp);
789 rmdir(mailbox_path(m));
790 return false;
791 }
792
793 snprintf(tmp, sizeof(tmp), "%s/tmp", mailbox_path(m));
794 errno = 0;
795 if ((mkdir(tmp, S_IRWXU) != 0) && (errno != EEXIST))
796 {
797 mutt_perror("%s", tmp);
798 snprintf(tmp, sizeof(tmp), "%s/cur", mailbox_path(m));
799 rmdir(tmp);
800 snprintf(tmp, sizeof(tmp), "%s/new", mailbox_path(m));
801 rmdir(tmp);
802 rmdir(mailbox_path(m));
803 return false;
804 }
805
806 return true;
807}
808
813{
814 return maildir_check(m);
815}
816
820enum MxStatus maildir_mbox_check_stats(struct Mailbox *m, uint8_t flags)
821{
822 bool check_stats = flags & MUTT_MAILBOX_CHECK_STATS;
823 bool check_new = true;
824
825 if (check_stats)
826 {
827 m->msg_new = 0;
828 m->msg_count = 0;
829 m->msg_unread = 0;
830 m->msg_flagged = 0;
831 }
832
833 maildir_check_dir(m, "new", check_new, check_stats);
834
835 const bool c_maildir_check_cur = cs_subset_bool(NeoMutt->sub, "maildir_check_cur");
836 check_new = !m->has_new && c_maildir_check_cur;
837 if (check_new || check_stats)
838 maildir_check_dir(m, "cur", check_new, check_stats);
839
841}
842
850{
851 enum MxStatus check = maildir_check(m);
852 if (check == MX_STATUS_ERROR)
853 return check;
854
855 struct HeaderCache *hc = maildir_hcache_open(m);
856
857 struct Progress *progress = NULL;
858 if (m->verbose)
859 {
861 progress_set_message(progress, _("Writing %s..."), mailbox_path(m));
862 }
863
864 for (int i = 0; i < m->msg_count; i++)
865 {
866 progress_update(progress, i, -1);
867
868 struct Email *e = m->emails[i];
869 if (!maildir_sync_mailbox_message(m, e, hc))
870 {
871 progress_free(&progress);
872 goto err;
873 }
874 }
875 progress_free(&progress);
877
878 /* XXX race condition? */
879
881
882 /* adjust indices */
883
884 if (m->msg_deleted)
885 {
886 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
887 for (int i = 0, j = 0; i < m->msg_count; i++)
888 {
889 struct Email *e = m->emails[i];
890 if (!e)
891 break;
892
893 if (!e->deleted || c_maildir_trash)
894 e->index = j++;
895 }
896 }
897
898 return check;
899
900err:
902 return MX_STATUS_ERROR;
903}
904
910{
911 return MX_STATUS_OK;
912}
#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:168
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
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:183
@ NT_MAILBOX_INVALID
Email list was changed.
Definition mailbox.h:182
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:216
@ 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:1325
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:69
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
@ MUTT_STAT_CTIME
File/dir's ctime - last status change time.
Definition file.h:60
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition file.h:59
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:820
enum MxStatus maildir_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition mailbox.c:812
enum MxStatus maildir_mbox_close(struct Mailbox *m)
Close a Mailbox - Implements MxOps::mbox_close() -.
Definition mailbox.c:909
bool maildir_mbox_open_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a Mailbox for appending - Implements MxOps::mbox_open_append() -.
Definition mailbox.c:758
enum MxOpenReturns maildir_mbox_open(struct Mailbox *m)
Open a Mailbox - Implements MxOps::mbox_open() -.
Definition mailbox.c:747
enum MxStatus maildir_mbox_sync(struct Mailbox *m)
Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
Definition mailbox.c:849
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:257
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
@ MUTT_HASH_NONE
No flags are set.
Definition hash.h:115
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:546
static void maildir_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
This function does the second parsing pass.
Definition mailbox.c:341
static int maildir_read_dir(struct Mailbox *m, const char *subdir)
Read a Maildir style mailbox.
Definition mailbox.c:488
bool maildir_parse_message(const char *fname, bool is_old, struct Email *e)
Actually parse a maildir message.
Definition mailbox.c:196
void maildir_update_mtime(struct Mailbox *m)
Update our record of the Maildir modification time.
Definition mailbox.c:725
static int maildir_move_to_mailbox(struct Mailbox *m, const struct MdEmailArray *mda)
Copy the Maildir list to the Mailbox.
Definition mailbox.c:217
#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:392
static int maildir_parse_dir(struct Mailbox *m, struct MdEmailArray *mda, const char *subdir, struct Progress *progress)
Read a Maildir mailbox.
Definition mailbox.c:275
#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:159
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:1209
API for mailboxes.
uint8_t OpenMailboxFlags
Definition mxapi.h:51
@ MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn't exist.
Definition mxapi.h:48
@ MUTT_APPEND
Open mailbox for appending messages.
Definition mxapi.h:44
MxOpenReturns
Return values for mbox_open()
Definition mxapi.h:83
@ MX_OPEN_ERROR
Open failed with an error.
Definition mxapi.h:85
@ MX_OPEN_OK
Open succeeded.
Definition mxapi.h:84
@ MUTT_MAILBOX_CHECK_STATS
Ignore mail_check_stats and calculate statistics (used by <check-stats>)
Definition mxapi.h:60
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition mxapi.h:70
@ MX_STATUS_ERROR
An error occurred.
Definition mxapi.h:71
@ MX_STATUS_OK
No changes.
Definition mxapi.h:72
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition mxapi.h:76
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition mxapi.h:75
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition mxapi.h:73
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:81
void(* mdata_free)(void **ptr)
Definition mailbox.h:145
bool changed
Mailbox has been modified.
Definition mailbox.h:112
bool has_new
Mailbox has new mail.
Definition mailbox.h:87
int msg_new
Number of new messages.
Definition mailbox.h:94
int msg_count
Total number of messages.
Definition mailbox.h:90
enum MailboxType type
Mailbox type.
Definition mailbox.h:104
void * mdata
Driver specific data.
Definition mailbox.h:134
struct Email ** emails
Array of Emails.
Definition mailbox.h:98
struct Buffer pathbuf
Path of the Mailbox.
Definition mailbox.h:82
int msg_deleted
Number of deleted messages.
Definition mailbox.h:95
int msg_flagged
Number of flagged messages.
Definition mailbox.h:92
struct timespec last_visited
Time of last exit from this mailbox.
Definition mailbox.h:106
bool verbose
Display status messages?
Definition mailbox.h:119
int msg_unread
Number of unread messages.
Definition mailbox.h:91
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