NeoMutt  2024-12-12-14-g7b49f7
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
91 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
92 char *p = strrchr(path, c_maildir_field_delimiter);
93 if (p && mutt_str_startswith(p + 1, "2,"))
94 {
95 p += 3;
96
97 mutt_str_replace(&edata->custom_flags, p);
98 q = edata->custom_flags;
99
100 while (*p)
101 {
102 switch (*p)
103 {
104 case 'F': // Flagged
105 e->flagged = true;
106 break;
107
108 case 'R': // Replied
109 e->replied = true;
110 break;
111
112 case 'S': // Seen
113 e->read = true;
114 break;
115
116 case 'T': // Trashed
117 {
118 const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
119 if (!e->flagged || !c_flag_safe)
120 {
121 e->trash = true;
122 e->deleted = true;
123 }
124 break;
125 }
126
127 default:
128 *q++ = *p;
129 break;
130 }
131 p++;
132 }
133 }
134
135 if (q == edata->custom_flags)
136 FREE(&edata->custom_flags);
137 else if (q)
138 *q = '\0';
139}
140
152bool maildir_parse_stream(FILE *fp, const char *fname, bool is_old, struct Email *e)
153{
154 if (!fp || !fname || !e)
155 return false;
156
157 const long size = mutt_file_get_size_fp(fp);
158 if (size == 0)
159 return false;
160
161 e->env = mutt_rfc822_read_header(fp, e, false, false);
162
163 if (e->received == 0)
164 e->received = e->date_sent;
165
166 /* always update the length since we have fresh information available. */
167 e->body->length = size - e->body->offset;
168
169 e->index = -1;
170
171 /* maildir stores its flags in the filename, so ignore the
172 * flags in the header of the message */
173 e->old = is_old;
174 maildir_parse_flags(e, fname);
175
176 return e;
177}
178
189bool maildir_parse_message(const char *fname, bool is_old, struct Email *e)
190{
191 if (!fname || !e)
192 return false;
193
194 FILE *fp = mutt_file_fopen(fname, "r");
195 if (!fp)
196 return false;
197
198 bool rc = maildir_parse_stream(fp, fname, is_old, e);
199 mutt_file_fclose(&fp);
200 return rc;
201}
202
210static int maildir_move_to_mailbox(struct Mailbox *m, const struct MdEmailArray *mda)
211{
212 if (!m)
213 return 0;
214
215 int oldmsgcount = m->msg_count;
216
217 struct MdEmail *md = NULL;
218 struct MdEmail **mdp = NULL;
219 ARRAY_FOREACH(mdp, mda)
220 {
221 md = *mdp;
222 mutt_debug(LL_DEBUG2, "Considering %s\n", NONULL(md->canon_fname));
223 if (!md->email)
224 continue;
225
226 mutt_debug(LL_DEBUG2, "Adding header structure. Flags: %s%s%s%s%s\n",
227 md->email->flagged ? "f" : "", md->email->deleted ? "D" : "",
228 md->email->replied ? "r" : "", md->email->old ? "O" : "",
229 md->email->read ? "R" : "");
231
232 m->emails[m->msg_count] = md->email;
233 m->emails[m->msg_count]->index = m->msg_count;
234 mailbox_size_add(m, md->email);
235
236 md->email = NULL;
237 m->msg_count++;
238 }
239
240 int num = 0;
241 if (m->msg_count > oldmsgcount)
242 num = m->msg_count - oldmsgcount;
243
244 return num;
245}
246
250static int maildir_sort_inode(const void *a, const void *b, void *sdata)
251{
252 const struct MdEmail *ma = *(struct MdEmail **) a;
253 const struct MdEmail *mb = *(struct MdEmail **) b;
254
255 return mutt_numeric_cmp(ma->inode, mb->inode);
256}
257
268static int maildir_parse_dir(struct Mailbox *m, struct MdEmailArray *mda,
269 const char *subdir, struct Progress *progress)
270{
271 struct dirent *de = NULL;
272 int rc = 0;
273 bool is_old = false;
274 struct MdEmail *entry = NULL;
275 struct Email *e = NULL;
276
277 struct Buffer *buf = buf_pool_get();
278
279 buf_printf(buf, "%s/%s", mailbox_path(m), subdir);
280 is_old = mutt_str_equal("cur", subdir);
281
283 if (!dir)
284 {
285 rc = -1;
286 goto cleanup;
287 }
288
289 while (((de = readdir(dir))) && !SigInt)
290 {
291 if (*de->d_name == '.')
292 continue;
293
294 mutt_debug(LL_DEBUG2, "queueing %s\n", de->d_name);
295
296 e = maildir_email_new();
297 e->old = is_old;
298 maildir_parse_flags(e, de->d_name);
299
300 progress_update(progress, ARRAY_SIZE(mda) + 1, -1);
301
302 buf_printf(buf, "%s/%s", subdir, de->d_name);
303 e->path = buf_strdup(buf);
304
305 entry = maildir_entry_new();
306 entry->email = e;
307 entry->inode = de->d_ino;
308 ARRAY_ADD(mda, entry);
309 }
310
311 closedir(dir);
312
313 if (SigInt)
314 {
315 SigInt = false;
316 return -2; /* action aborted */
317 }
318
319 ARRAY_SORT(mda, maildir_sort_inode, NULL);
320
321cleanup:
322 buf_pool_release(&buf);
323
324 return rc;
325}
326
333static void maildir_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda,
334 struct Progress *progress)
335{
336 char fn[PATH_MAX] = { 0 };
337
338 struct HeaderCache *hc = maildir_hcache_open(m);
339
340 struct MdEmail *md = NULL;
341 struct MdEmail **mdp = NULL;
342 ARRAY_FOREACH(mdp, mda)
343 {
344 md = *mdp;
345 if (!md || !md->email || md->header_parsed)
346 continue;
347
348 progress_update(progress, ARRAY_FOREACH_IDX, -1);
349
350 snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
351
352 struct Email *e = maildir_hcache_read(hc, md->email, fn);
353 if (e)
354 {
355 email_free(&md->email);
356 md->email = e;
357 }
358 else
359 {
360 if (maildir_parse_message(fn, md->email->old, md->email))
361 {
362 md->header_parsed = true;
364 }
365 else
366 {
367 email_free(&md->email);
368 }
369 }
370 }
371
373}
374
384static void maildir_check_dir(struct Mailbox *m, const char *dir_name,
385 bool check_new, bool check_stats)
386{
387 DIR *dir = NULL;
388 struct dirent *de = NULL;
389 char *p = NULL;
390 struct stat st = { 0 };
391
392 struct Buffer *path = buf_pool_get();
393 struct Buffer *msgpath = buf_pool_get();
394 buf_printf(path, "%s/%s", mailbox_path(m), dir_name);
395
396 /* when $mail_check_recent is set, if the new/ directory hasn't been modified since
397 * the user last exited the mailbox, then we know there is no recent mail. */
398 const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
399 if (check_new && c_mail_check_recent)
400 {
401 if ((stat(buf_string(path), &st) == 0) &&
403 {
404 check_new = false;
405 }
406 }
407
408 if (!(check_new || check_stats))
409 goto cleanup;
410
412 if (!dir)
413 {
414 m->type = MUTT_UNKNOWN;
415 goto cleanup;
416 }
417
418 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
419
420 char delimiter_version[8] = { 0 };
421 snprintf(delimiter_version, sizeof(delimiter_version), "%c2,", c_maildir_field_delimiter);
422 while ((de = readdir(dir)))
423 {
424 if (*de->d_name == '.')
425 continue;
426
427 p = strstr(de->d_name, delimiter_version);
428 if (p && strchr(p + 3, 'T'))
429 continue;
430
431 if (check_stats)
432 {
433 m->msg_count++;
434 if (p && strchr(p + 3, 'F'))
435 m->msg_flagged++;
436 }
437 if (!p || !strchr(p + 3, 'S'))
438 {
439 if (check_stats)
440 m->msg_unread++;
441 if (check_new)
442 {
443 if (c_mail_check_recent)
444 {
445 buf_printf(msgpath, "%s/%s", buf_string(path), de->d_name);
446 /* ensure this message was received since leaving this m */
447 if ((stat(buf_string(msgpath), &st) == 0) &&
449 {
450 continue;
451 }
452 }
453 m->has_new = true;
454 if (check_stats)
455 {
456 m->msg_new++;
457 }
458 else
459 {
460 break;
461 }
462 }
463 }
464 }
465
466 closedir(dir);
467
468cleanup:
469 buf_pool_release(&path);
470 buf_pool_release(&msgpath);
471}
472
480static int maildir_read_dir(struct Mailbox *m, const char *subdir)
481{
482 if (!m)
483 return -1;
484
485 mutt_path_tidy(&m->pathbuf, true);
486
487 struct Progress *progress = NULL;
488
489 if (m->verbose)
490 {
491 progress = progress_new(MUTT_PROGRESS_READ, 0);
492 progress_set_message(progress, _("Scanning %s..."), mailbox_path(m));
493 }
494
496 if (!mdata)
497 {
499 m->mdata = mdata;
501 }
502
503 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
504 int rc = maildir_parse_dir(m, &mda, subdir, progress);
505 progress_free(&progress);
506 if (rc < 0)
507 return -1;
508
509 if (m->verbose)
510 {
511 progress = progress_new(MUTT_PROGRESS_READ, ARRAY_SIZE(&mda));
512 progress_set_message(progress, _("Reading %s..."), mailbox_path(m));
513 }
514 maildir_delayed_parsing(m, &mda, progress);
515 progress_free(&progress);
516
518 maildirarray_clear(&mda);
519
520 if (!mdata->umask)
521 mdata->umask = maildir_umask(m);
522
523 return 0;
524}
525
538static enum MxStatus maildir_check(struct Mailbox *m)
539{
540 struct stat st_new = { 0 }; /* status of the "new" subdirectory */
541 struct stat st_cur = { 0 }; /* status of the "cur" subdirectory */
542 int changed = MMC_NO_DIRS; /* which subdirectories have changed */
543 bool occult = false; /* messages were removed from the mailbox */
544 int num_new = 0; /* number of new messages added to the mailbox */
545 bool flags_changed = false; /* message flags were changed in the mailbox */
546 struct HashTable *hash_names = NULL; // Hash Table: "base-filename" -> MdEmail
548
549 const bool c_check_new = cs_subset_bool(NeoMutt->sub, "check_new");
550 if (!c_check_new)
551 return MX_STATUS_OK;
552
553 struct Buffer *buf = buf_pool_get();
554 buf_printf(buf, "%s/new", mailbox_path(m));
555 if (stat(buf_string(buf), &st_new) == -1)
556 {
557 buf_pool_release(&buf);
558 return MX_STATUS_ERROR;
559 }
560
561 buf_printf(buf, "%s/cur", mailbox_path(m));
562 if (stat(buf_string(buf), &st_cur) == -1)
563 {
564 buf_pool_release(&buf);
565 return MX_STATUS_ERROR;
566 }
567
568 /* determine which subdirectories need to be scanned */
569 if (mutt_file_stat_timespec_compare(&st_new, MUTT_STAT_MTIME, &mdata->mtime) > 0)
570 changed = MMC_NEW_DIR;
572 changed |= MMC_CUR_DIR;
573
574 if (changed == MMC_NO_DIRS)
575 {
576 buf_pool_release(&buf);
577 return MX_STATUS_OK; /* nothing to do */
578 }
579
580 /* Update the modification times on the mailbox.
581 *
582 * The monitor code notices changes in the open mailbox too quickly.
583 * In practice, this sometimes leads to all the new messages not being
584 * noticed during the SAME group of mtime stat updates. To work around
585 * the problem, don't update the stat times for a monitor caused check. */
586#ifdef USE_INOTIFY
588 {
589 MonitorCurMboxChanged = false;
590 }
591 else
592#endif
593 {
596 }
597
598 /* do a fast scan of just the filenames in
599 * the subdirectories that have changed. */
600 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
601 if (changed & MMC_NEW_DIR)
602 maildir_parse_dir(m, &mda, "new", NULL);
603 if (changed & MMC_CUR_DIR)
604 maildir_parse_dir(m, &mda, "cur", NULL);
605
606 /* we create a hash table keyed off the canonical (sans flags) filename
607 * of each message we scanned. This is used in the loop over the
608 * existing messages below to do some correlation. */
609 hash_names = mutt_hash_new(ARRAY_SIZE(&mda), MUTT_HASH_NO_FLAGS);
610
611 struct MdEmail *md = NULL;
612 struct MdEmail **mdp = NULL;
613 ARRAY_FOREACH(mdp, &mda)
614 {
615 md = *mdp;
617 md->canon_fname = buf_strdup(buf);
618 mutt_hash_insert(hash_names, md->canon_fname, md);
619 }
620
621 /* check for modifications and adjust flags */
622 for (int i = 0; i < m->msg_count; i++)
623 {
624 struct Email *e = m->emails[i];
625 if (!e)
626 break;
627
629 md = mutt_hash_find(hash_names, buf_string(buf));
630 if (md && md->email)
631 {
632 /* message already exists, merge flags */
633
634 /* check to see if the message has moved to a different
635 * subdirectory. If so, update the associated filename. */
636 if (!mutt_str_equal(e->path, md->email->path))
637 mutt_str_replace(&e->path, md->email->path);
638
639 /* if the user hasn't modified the flags on this message, update
640 * the flags we just detected. */
641 if (!e->changed)
642 if (maildir_update_flags(m, e, md->email))
643 flags_changed = true;
644
645 if (e->deleted == e->trash)
646 {
647 if (e->deleted != md->email->deleted)
648 {
649 e->deleted = md->email->deleted;
650 flags_changed = true;
651 }
652 }
653 e->trash = md->email->trash;
654
655 /* this is a duplicate of an existing email, so remove it */
656 email_free(&md->email);
657 }
658 /* This message was not in the list of messages we just scanned.
659 * Check to see if we have enough information to know if the
660 * message has disappeared out from underneath us. */
661 else if (((changed & MMC_NEW_DIR) && mutt_strn_equal(e->path, "new/", 4)) ||
662 ((changed & MMC_CUR_DIR) && mutt_strn_equal(e->path, "cur/", 4)))
663 {
664 /* This message disappeared, so we need to simulate a "reopen"
665 * event. We know it disappeared because we just scanned the
666 * subdirectory it used to reside in. */
667 occult = true;
668 e->deleted = true;
669 e->purge = true;
670 }
671 else
672 {
673 /* This message resides in a subdirectory which was not
674 * modified, so we assume that it is still present and
675 * unchanged. */
676 }
677 }
678
679 /* destroy the file name hash */
680 mutt_hash_free(&hash_names);
681
682 /* If we didn't just get new mail, update the tables. */
683 if (occult)
685
686 /* do any delayed parsing we need to do. */
687 maildir_delayed_parsing(m, &mda, NULL);
688
689 /* Incorporate new messages */
690 num_new = maildir_move_to_mailbox(m, &mda);
691 maildirarray_clear(&mda);
692
693 if (num_new > 0)
694 {
696 m->changed = true;
697 }
698
699 buf_pool_release(&buf);
700
701 ARRAY_FREE(&mda);
702 if (occult)
703 return MX_STATUS_REOPENED;
704 if (num_new > 0)
705 return MX_STATUS_NEW_MAIL;
706 if (flags_changed)
707 return MX_STATUS_FLAGS;
708 return MX_STATUS_OK;
709}
710
716{
717 char buf[PATH_MAX] = { 0 };
718 struct stat st = { 0 };
720
721 snprintf(buf, sizeof(buf), "%s/%s", mailbox_path(m), "cur");
722 if (stat(buf, &st) == 0)
724
725 snprintf(buf, sizeof(buf), "%s/%s", mailbox_path(m), "new");
726 if (stat(buf, &st) == 0)
728}
729
730// Mailbox API -----------------------------------------------------------------
731
736{
737 if ((maildir_read_dir(m, "new") == -1) || (maildir_read_dir(m, "cur") == -1))
738 return MX_OPEN_ERROR;
739
740 return MX_OPEN_OK;
741}
742
747{
748 if (!(flags & (MUTT_APPEND | MUTT_APPENDNEW | MUTT_NEWFOLDER)))
749 {
750 return true;
751 }
752
753 errno = 0;
754 if ((mutt_file_mkdir(mailbox_path(m), S_IRWXU) != 0) && (errno != EEXIST))
755 {
756 mutt_perror("%s", mailbox_path(m));
757 return false;
758 }
759
760 char tmp[PATH_MAX] = { 0 };
761 snprintf(tmp, sizeof(tmp), "%s/cur", mailbox_path(m));
762 errno = 0;
763 if ((mkdir(tmp, S_IRWXU) != 0) && (errno != EEXIST))
764 {
765 mutt_perror("%s", tmp);
766 rmdir(mailbox_path(m));
767 return false;
768 }
769
770 snprintf(tmp, sizeof(tmp), "%s/new", mailbox_path(m));
771 errno = 0;
772 if ((mkdir(tmp, S_IRWXU) != 0) && (errno != EEXIST))
773 {
774 mutt_perror("%s", tmp);
775 snprintf(tmp, sizeof(tmp), "%s/cur", mailbox_path(m));
776 rmdir(tmp);
777 rmdir(mailbox_path(m));
778 return false;
779 }
780
781 snprintf(tmp, sizeof(tmp), "%s/tmp", 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 snprintf(tmp, sizeof(tmp), "%s/new", mailbox_path(m));
789 rmdir(tmp);
790 rmdir(mailbox_path(m));
791 return false;
792 }
793
794 return true;
795}
796
801{
802 return maildir_check(m);
803}
804
808enum MxStatus maildir_mbox_check_stats(struct Mailbox *m, uint8_t flags)
809{
810 bool check_stats = flags & MUTT_MAILBOX_CHECK_STATS;
811 bool check_new = true;
812
813 if (check_stats)
814 {
815 m->msg_new = 0;
816 m->msg_count = 0;
817 m->msg_unread = 0;
818 m->msg_flagged = 0;
819 }
820
821 maildir_check_dir(m, "new", check_new, check_stats);
822
823 const bool c_maildir_check_cur = cs_subset_bool(NeoMutt->sub, "maildir_check_cur");
824 check_new = !m->has_new && c_maildir_check_cur;
825 if (check_new || check_stats)
826 maildir_check_dir(m, "cur", check_new, check_stats);
827
829}
830
838{
839 enum MxStatus check = maildir_check(m);
840 if (check == MX_STATUS_ERROR)
841 return check;
842
843 struct HeaderCache *hc = maildir_hcache_open(m);
844
845 struct Progress *progress = NULL;
846 if (m->verbose)
847 {
849 progress_set_message(progress, _("Writing %s..."), mailbox_path(m));
850 }
851
852 for (int i = 0; i < m->msg_count; i++)
853 {
854 progress_update(progress, i, -1);
855
856 struct Email *e = m->emails[i];
857 if (!maildir_sync_mailbox_message(m, e, hc))
858 {
859 progress_free(&progress);
860 goto err;
861 }
862 }
863 progress_free(&progress);
865
866 /* XXX race condition? */
867
869
870 /* adjust indices */
871
872 if (m->msg_deleted)
873 {
874 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
875 for (int i = 0, j = 0; i < m->msg_count; i++)
876 {
877 struct Email *e = m->emails[i];
878 if (!e)
879 break;
880
881 if (!e->deleted || c_maildir_trash)
882 e->index = j++;
883 }
884 }
885
886 return check;
887
888err:
890 return MX_STATUS_ERROR;
891}
892
898{
899 return MX_STATUS_OK;
900}
#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:1579
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:974
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1537
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:642
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:1619
@ MUTT_OPENDIR_CREATE
Create the directory if it doesn't exist.
Definition: file.h:64
#define mutt_file_fclose(FP)
Definition: file.h:138
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:137
@ 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:808
enum MxStatus maildir_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition: mailbox.c:800
enum MxStatus maildir_mbox_close(struct Mailbox *m)
Close a Mailbox - Implements MxOps::mbox_close() -.
Definition: mailbox.c:897
bool maildir_mbox_open_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a Mailbox for appending - Implements MxOps::mbox_open_append() -.
Definition: mailbox.c:746
enum MxOpenReturns maildir_mbox_open(struct Mailbox *m)
Open a Mailbox - Implements MxOps::mbox_open() -.
Definition: mailbox.c:735
enum MxStatus maildir_mbox_sync(struct Mailbox *m)
Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
Definition: mailbox.c:837
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:250
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:538
static void maildir_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
This function does the second parsing pass.
Definition: mailbox.c:333
static int maildir_read_dir(struct Mailbox *m, const char *subdir)
Read a Maildir style mailbox.
Definition: mailbox.c:480
bool maildir_parse_message(const char *fname, bool is_old, struct Email *e)
Actually parse a maildir message.
Definition: mailbox.c:189
void maildir_update_mtime(struct Mailbox *m)
Update our record of the Maildir modification time.
Definition: mailbox.c:715
static int maildir_move_to_mailbox(struct Mailbox *m, const struct MdEmailArray *mda)
Copy the Maildir list to the Mailbox.
Definition: mailbox.c:210
#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:384
static int maildir_parse_dir(struct Mailbox *m, struct MdEmailArray *mda, const char *subdir, struct Progress *progress)
Read a Maildir mailbox.
Definition: mailbox.c:268
#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:152
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:1206
API for mailboxes.
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mxapi.h:39
#define MUTT_NEWFOLDER
Create a new folder - same as MUTT_APPEND, but uses mutt_file_fopen() with mode "w" for mbox-style fo...
Definition: mxapi.h:45
#define MUTT_MAILBOX_CHECK_STATS
Ignore mail_check_stats and calculate statistics (used by <check-stats>)
Definition: mxapi.h:55
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:42
MxOpenReturns
Return values for mbox_open()
Definition: mxapi.h:76
@ MX_OPEN_ERROR
Open failed with an error.
Definition: mxapi.h:78
@ MX_OPEN_OK
Open succeeded.
Definition: mxapi.h:77
#define MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn't exist.
Definition: mxapi.h:49
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition: mxapi.h:63
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:64
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:65
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition: mxapi.h:69
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:68
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:66
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