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