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