NeoMutt  2022-04-29-215-gc12b98
Teaching an old dog new tricks
DOXYGEN
mh.c
Go to the documentation of this file.
1
34#include "config.h"
35#include <ctype.h>
36#include <dirent.h>
37#include <errno.h>
38#include <fcntl.h>
39#include <inttypes.h>
40#include <limits.h>
41#include <stdbool.h>
42#include <stdio.h>
43#include <string.h>
44#include <sys/stat.h>
45#include <unistd.h>
46#include "private.h"
47#include "mutt/lib.h"
48#include "config/lib.h"
49#include "email/lib.h"
50#include "core/lib.h"
51#include "lib.h"
52#include "progress/lib.h"
53#include "copy.h"
54#include "edata.h"
55#include "errno.h"
56#include "mdata.h"
57#include "mdemail.h"
58#include "mutt_globals.h"
59#include "mx.h"
60#include "sequence.h"
61#ifdef USE_INOTIFY
62#include "monitor.h"
63#endif
64#ifdef USE_HCACHE
65#include "hcache/lib.h"
66#endif
67
68struct Progress;
69
78bool mh_mkstemp(struct Mailbox *m, FILE **fp, char **tgt)
79{
80 int fd;
81 char path[PATH_MAX] = { 0 };
82
83 mode_t omask = umask(mh_umask(m));
84 while (true)
85 {
86 snprintf(path, sizeof(path), "%s/.neomutt-%s-%d-%" PRIu64, mailbox_path(m),
87 NONULL(ShortHostname), (int) getpid(), mutt_rand64());
88 fd = open(path, O_WRONLY | O_EXCL | O_CREAT, 0666);
89 if (fd == -1)
90 {
91 if (errno != EEXIST)
92 {
93 mutt_perror(path);
94 umask(omask);
95 return false;
96 }
97 }
98 else
99 {
100 *tgt = mutt_str_dup(path);
101 break;
102 }
103 }
104 umask(omask);
105
106 *fp = fdopen(fd, "w");
107 if (!*fp)
108 {
109 FREE(tgt);
110 close(fd);
111 unlink(path);
112 return false;
113 }
114
115 return true;
116}
117
126static int mh_already_notified(struct Mailbox *m, int msgno)
127{
128 char path[PATH_MAX] = { 0 };
129 struct stat st = { 0 };
130
131 if ((snprintf(path, sizeof(path), "%s/%d", mailbox_path(m), msgno) < sizeof(path)) &&
132 (stat(path, &st) == 0))
133 {
135 }
136 return -1;
137}
138
149bool mh_valid_message(const char *s)
150{
151 for (; *s; s++)
152 {
153 if (!isdigit((unsigned char) *s))
154 return false;
155 }
156 return true;
157}
158
166int mh_check_empty(const char *path)
167{
168 struct dirent *de = NULL;
169 int rc = 1; /* assume empty until we find a message */
170
171 DIR *dp = opendir(path);
172 if (!dp)
173 return -1;
174 while ((de = readdir(dp)))
175 {
176 if (mh_valid_message(de->d_name))
177 {
178 rc = 0;
179 break;
180 }
181 }
182 closedir(dp);
183
184 return rc;
185}
186
190static enum MxStatus mh_mbox_check_stats(struct Mailbox *m, uint8_t flags)
191{
192 struct MhSequences mhs = { 0 };
193 DIR *dirp = NULL;
194 struct dirent *de = NULL;
195
196 /* when $mail_check_recent is set and the .mh_sequences file hasn't changed
197 * since the last m visit, there is no "new mail" */
198 const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
199 if (c_mail_check_recent && (mh_seq_changed(m) <= 0))
200 {
201 return MX_STATUS_OK;
202 }
203
204 if (mh_seq_read(&mhs, mailbox_path(m)) < 0)
205 return MX_STATUS_ERROR;
206
207 m->msg_count = 0;
208 m->msg_unread = 0;
209 m->msg_flagged = 0;
210
211 enum MxStatus rc = MX_STATUS_OK;
212 bool check_new = true;
213 for (int i = mhs.max; i > 0; i--)
214 {
215 if ((mh_seq_check(&mhs, i) & MH_SEQ_FLAGGED))
216 m->msg_flagged++;
217 if (mh_seq_check(&mhs, i) & MH_SEQ_UNSEEN)
218 {
219 m->msg_unread++;
220 if (check_new)
221 {
222 /* if the first unseen message we encounter was in the m during the
223 * last visit, don't notify about it */
224 if (!c_mail_check_recent || (mh_already_notified(m, i) == 0))
225 {
226 m->has_new = true;
228 }
229 /* Because we are traversing from high to low, we can stop
230 * checking for new mail after the first unseen message.
231 * Whether it resulted in "new mail" or not. */
232 check_new = false;
233 }
234 }
235 }
236
237 mh_seq_free(&mhs);
238
239 dirp = opendir(mailbox_path(m));
240 if (dirp)
241 {
242 while ((de = readdir(dirp)))
243 {
244 if (*de->d_name == '.')
245 continue;
246 if (mh_valid_message(de->d_name))
247 m->msg_count++;
248 }
249 closedir(dirp);
250 }
251
252 return rc;
253}
254
260void mh_update_maildir(struct MdEmailArray *mda, struct MhSequences *mhs)
261{
262 struct MdEmail *md = NULL;
263 struct MdEmail **mdp = NULL;
264 ARRAY_FOREACH(mdp, mda)
265 {
266 md = *mdp;
267 char *p = strrchr(md->email->path, '/');
268 if (p)
269 p++;
270 else
271 p = md->email->path;
272
273 int i = 0;
274 if (!mutt_str_atoi_full(p, &i))
275 continue;
276 MhSeqFlags flags = mh_seq_check(mhs, i);
277
278 md->email->read = !(flags & MH_SEQ_UNSEEN);
279 md->email->flagged = (flags & MH_SEQ_FLAGGED);
280 md->email->replied = (flags & MH_SEQ_REPLIED);
281 }
282}
283
293int mh_commit_msg(struct Mailbox *m, struct Message *msg, struct Email *e, bool updseq)
294{
295 struct dirent *de = NULL;
296 char *cp = NULL, *dep = NULL;
297 unsigned int n, hi = 0;
298 char path[PATH_MAX] = { 0 };
299 char tmp[16] = { 0 };
300
301 if (mutt_file_fsync_close(&msg->fp))
302 {
303 mutt_perror(_("Could not flush message to disk"));
304 return -1;
305 }
306
307 DIR *dirp = opendir(mailbox_path(m));
308 if (!dirp)
309 {
311 return -1;
312 }
313
314 /* figure out what the next message number is */
315 while ((de = readdir(dirp)))
316 {
317 dep = de->d_name;
318 if (*dep == ',')
319 dep++;
320 cp = dep;
321 while (*cp)
322 {
323 if (!isdigit((unsigned char) *cp))
324 break;
325 cp++;
326 }
327 if (*cp == '\0')
328 {
329 if (!mutt_str_atoui(dep, &n))
330 mutt_debug(LL_DEBUG2, "Invalid MH message number '%s'\n", dep);
331 if (n > hi)
332 hi = n;
333 }
334 }
335 closedir(dirp);
336
337 /* Now try to rename the file to the proper name.
338 * Note: We may have to try multiple times, until we find a free slot. */
339
340 while (true)
341 {
342 hi++;
343 snprintf(tmp, sizeof(tmp), "%u", hi);
344 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), tmp);
345 if (mutt_file_safe_rename(msg->path, path) == 0)
346 {
347 if (e)
348 mutt_str_replace(&e->path, tmp);
349 mutt_str_replace(&msg->committed_path, path);
350 FREE(&msg->path);
351 break;
352 }
353 else if (errno != EEXIST)
354 {
356 return -1;
357 }
358 }
359 if (updseq)
360 {
361 mh_seq_add_one(m, hi, !msg->flags.read, msg->flags.flagged, msg->flags.replied);
362 }
363 return 0;
364}
365
373int mh_rewrite_message(struct Mailbox *m, int msgno)
374{
375 if (!m || !m->emails || (msgno >= m->msg_count))
376 return -1;
377
378 struct Email *e = m->emails[msgno];
379 if (!e)
380 return -1;
381
382 bool restore = true;
383
384 long old_body_offset = e->body->offset;
385 long old_body_length = e->body->length;
386 long old_hdr_lines = e->lines;
387
388 struct Message *src = mx_msg_open(m, msgno);
389 struct Message *dest = mx_msg_open_new(m, e, MUTT_MSG_NO_FLAGS);
390 if (!src || !dest)
391 return -1;
392
393 int rc = mutt_copy_message(dest->fp, e, src, MUTT_CM_UPDATE, CH_UPDATE | CH_UPDATE_LEN, 0);
394 if (rc == 0)
395 {
396 char oldpath[PATH_MAX] = { 0 };
397 char partpath[PATH_MAX] = { 0 };
398 snprintf(oldpath, sizeof(oldpath), "%s/%s", mailbox_path(m), e->path);
399 mutt_str_copy(partpath, e->path, sizeof(partpath));
400
401 rc = mh_commit_msg(m, dest, e, false);
402
403 if (rc == 0)
404 {
405 unlink(oldpath);
406 restore = false;
407 }
408
409 /* Try to move the new message to the old place.
410 * (MH only.)
411 *
412 * This is important when we are just updating flags.
413 *
414 * Note that there is a race condition against programs which
415 * use the first free slot instead of the maximum message
416 * number. NeoMutt does _not_ behave like this.
417 *
418 * Anyway, if this fails, the message is in the folder, so
419 * all what happens is that a concurrently running neomutt will
420 * lose flag modifications. */
421 if (rc == 0)
422 {
423 char newpath[PATH_MAX] = { 0 };
424 snprintf(newpath, sizeof(newpath), "%s/%s", mailbox_path(m), e->path);
425 rc = mutt_file_safe_rename(newpath, oldpath);
426 if (rc == 0)
427 mutt_str_replace(&e->path, partpath);
428 }
429 }
430 mx_msg_close(m, &src);
431 mx_msg_close(m, &dest);
432
433 if ((rc == -1) && restore)
434 {
435 e->body->offset = old_body_offset;
436 e->body->length = old_body_length;
437 e->lines = old_hdr_lines;
438 }
439
441 return rc;
442}
443
451int mh_sync_message(struct Mailbox *m, int msgno)
452{
453 if (!m || !m->emails)
454 return -1;
455
456 struct Email *e = m->emails[msgno];
457 if (!e)
458 return -1;
459
460 /* TODO: why the e->env check? */
461 if (e->attach_del || (e->env && e->env->changed))
462 {
463 if (mh_rewrite_message(m, msgno) != 0)
464 return -1;
465 /* TODO: why the env check? */
466 if (e->env)
467 e->env->changed = 0;
468 }
469
470 return 0;
471}
472
478{
479 char buf[PATH_MAX] = { 0 };
480 struct stat st = { 0 };
482
483 snprintf(buf, sizeof(buf), "%s/.mh_sequences", mailbox_path(m));
484 if (stat(buf, &st) == 0)
486
487 mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
488
489 if (stat(buf, &st) == 0)
491}
492
502int mh_parse_dir(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
503{
504 struct dirent *de = NULL;
505 int rc = 0;
506 struct MdEmail *entry = NULL;
507 struct Email *e = NULL;
508
509 struct Buffer *buf = mutt_buffer_pool_get();
511
512 DIR *dirp = opendir(mutt_buffer_string(buf));
513 if (!dirp)
514 {
515 rc = -1;
516 goto cleanup;
517 }
518
519 while (((de = readdir(dirp))) && !SigInt)
520 {
521 if (!mh_valid_message(de->d_name))
522 continue;
523
524 /* FOO - really ignore the return value? */
525 mutt_debug(LL_DEBUG2, "queueing %s\n", de->d_name);
526
527 e = email_new();
530
531 if (m->verbose && progress)
532 progress_update(progress, ARRAY_SIZE(mda) + 1, -1);
533
534 e->path = mutt_str_dup(de->d_name);
535
536 entry = maildir_entry_new();
537 entry->email = e;
538 ARRAY_ADD(mda, entry);
539 }
540
541 closedir(dirp);
542
543 if (SigInt)
544 {
545 SigInt = false;
546 return -2; /* action aborted */
547 }
548
549cleanup:
551
552 return rc;
553}
554
558int mh_cmp_path(const void *a, const void *b)
559{
560 struct MdEmail const *const *pa = (struct MdEmail const *const *) a;
561 struct MdEmail const *const *pb = (struct MdEmail const *const *) b;
562 return strcmp((*pa)->email->path, (*pb)->email->path);
563}
564
574struct Email *mh_parse_message(const char *fname, struct Email *e)
575{
576 FILE *fp = fopen(fname, "r");
577 if (!fp)
578 {
579 return NULL;
580 }
581
582 const long size = mutt_file_get_size_fp(fp);
583 if (size == 0)
584 {
585 mutt_file_fclose(&fp);
586 return NULL;
587 }
588
589 if (!e)
590 {
591 e = email_new();
594 }
595 e->env = mutt_rfc822_read_header(fp, e, false, false);
596
597 if (e->received != 0)
598 e->received = e->date_sent;
599
600 /* always update the length since we have fresh information available. */
601 e->body->length = size - e->body->offset;
602 e->index = -1;
603
604 mutt_file_fclose(&fp);
605 return e;
606}
607
614void mh_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
615{
616 char fn[PATH_MAX] = { 0 };
617
618#ifdef USE_HCACHE
619 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
620 struct HeaderCache *hc = mutt_hcache_open(c_header_cache, mailbox_path(m), NULL);
621#endif
622
623 struct MdEmail *md = NULL;
624 struct MdEmail **mdp = NULL;
625 ARRAY_FOREACH(mdp, mda)
626 {
627 md = *mdp;
628 if (!md || !md->email || md->header_parsed)
629 continue;
630
631 if (m->verbose && progress)
632 progress_update(progress, ARRAY_FOREACH_IDX, -1);
633
634 snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
635
636#ifdef USE_HCACHE
637 struct stat st_lastchanged = { 0 };
638 int rc = 0;
639 const bool c_maildir_header_cache_verify = cs_subset_bool(NeoMutt->sub, "maildir_header_cache_verify");
640 if (c_maildir_header_cache_verify)
641 {
642 rc = stat(fn, &st_lastchanged);
643 }
644
645 const char *key = md->email->path;
646 size_t keylen = strlen(key);
647 struct HCacheEntry hce = mutt_hcache_fetch(hc, key, keylen, 0);
648
649 if (hce.email && (rc == 0) && (st_lastchanged.st_mtime <= hce.uidvalidity))
650 {
653 hce.email->old = md->email->old;
654 hce.email->path = mutt_str_dup(md->email->path);
655 email_free(&md->email);
656 md->email = hce.email;
657 }
658 else
659#endif
660 {
661 if (mh_parse_message(fn, md->email))
662 {
663 md->header_parsed = true;
664#ifdef USE_HCACHE
665 key = md->email->path;
666 keylen = strlen(key);
667 mutt_hcache_store(hc, key, keylen, md->email, 0);
668#endif
669 }
670 else
671 email_free(&md->email);
672 }
673 }
674#ifdef USE_HCACHE
676#endif
677
678 const short c_sort = cs_subset_sort(NeoMutt->sub, "sort");
679 if (m && mda && (ARRAY_SIZE(mda) > 0) && (c_sort == SORT_ORDER))
680 {
681 mutt_debug(LL_DEBUG3, "maildir: sorting %s into natural order\n", mailbox_path(m));
683 }
684}
685
692static bool mh_read_dir(struct Mailbox *m)
693{
694 if (!m)
695 return false;
696
697 struct MhSequences mhs = { 0 };
698 struct Progress *progress = NULL;
699
700 if (m->verbose)
701 {
702 char msg[PATH_MAX] = { 0 };
703 snprintf(msg, sizeof(msg), _("Scanning %s..."), mailbox_path(m));
704 progress = progress_new(msg, MUTT_PROGRESS_READ, 0);
705 }
706
708 if (!mdata)
709 {
711 m->mdata = mdata;
713 }
714
716
717 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
718 int rc = mh_parse_dir(m, &mda, progress);
719 progress_free(&progress);
720 if (rc < 0)
721 return false;
722
723 if (m->verbose)
724 {
725 char msg[PATH_MAX] = { 0 };
726 snprintf(msg, sizeof(msg), _("Reading %s..."), mailbox_path(m));
727 progress = progress_new(msg, MUTT_PROGRESS_READ, ARRAY_SIZE(&mda));
728 }
729 mh_delayed_parsing(m, &mda, progress);
730 progress_free(&progress);
731
732 if (mh_seq_read(&mhs, mailbox_path(m)) < 0)
733 {
734 maildirarray_clear(&mda);
735 return false;
736 }
737 mh_update_maildir(&mda, &mhs);
738 mh_seq_free(&mhs);
739
741
742 if (!mdata->mh_umask)
743 mdata->mh_umask = mh_umask(m);
744
745 return true;
746}
747
756int mh_sync_mailbox_message(struct Mailbox *m, int msgno, struct HeaderCache *hc)
757{
758 if (!m || !m->emails || (msgno >= m->msg_count))
759 return -1;
760
761 struct Email *e = m->emails[msgno];
762 if (!e)
763 return -1;
764
765 if (e->deleted)
766 {
767 char path[PATH_MAX] = { 0 };
768 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
769 const bool c_mh_purge = cs_subset_bool(NeoMutt->sub, "mh_purge");
770 if (c_mh_purge)
771 {
772#ifdef USE_HCACHE
773 if (hc)
774 {
775 const char *key = e->path;
776 size_t keylen = strlen(key);
777 mutt_hcache_delete_record(hc, key, keylen);
778 }
779#endif
780 unlink(path);
781 }
782 else
783 {
784 /* MH just moves files out of the way when you delete them */
785 if (*e->path != ',')
786 {
787 char tmp[PATH_MAX] = { 0 };
788 snprintf(tmp, sizeof(tmp), "%s/,%s", mailbox_path(m), e->path);
789 unlink(tmp);
790 if (rename(path, tmp) != 0)
791 {
792 return -1;
793 }
794 }
795 }
796 }
797 else if (e->changed || e->attach_del)
798 {
799 if (mh_sync_message(m, msgno) == -1)
800 return -1;
801 }
802
803#ifdef USE_HCACHE
804 if (hc && e->changed)
805 {
806 const char *key = e->path;
807 size_t keylen = strlen(key);
808 mutt_hcache_store(hc, key, keylen, e, 0);
809 }
810#endif
811
812 return 0;
813}
814
818int mh_msg_save_hcache(struct Mailbox *m, struct Email *e)
819{
820 int rc = 0;
821#ifdef USE_HCACHE
822 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
823 struct HeaderCache *hc = mutt_hcache_open(c_header_cache, mailbox_path(m), NULL);
824 rc = mutt_hcache_store(hc, e->path, strlen(e->path), e, 0);
826#endif
827 return rc;
828}
829
833bool mh_ac_owns_path(struct Account *a, const char *path)
834{
835 return true;
836}
837
841bool mh_ac_add(struct Account *a, struct Mailbox *m)
842{
843 return true;
844}
845
849static enum MxOpenReturns mh_mbox_open(struct Mailbox *m)
850{
852}
853
857static bool mh_mbox_open_append(struct Mailbox *m, OpenMailboxFlags flags)
858{
859 if (!(flags & (MUTT_APPENDNEW | MUTT_NEWFOLDER)))
860 return true;
861
862 if (mutt_file_mkdir(mailbox_path(m), S_IRWXU))
863 {
865 return false;
866 }
867
868 char tmp[PATH_MAX] = { 0 };
869 snprintf(tmp, sizeof(tmp), "%s/.mh_sequences", mailbox_path(m));
870 const int i = creat(tmp, S_IRWXU);
871 if (i == -1)
872 {
873 mutt_perror(tmp);
874 rmdir(mailbox_path(m));
875 return false;
876 }
877 close(i);
878
879 return true;
880}
881
893{
894 char buf[PATH_MAX] = { 0 };
895 struct stat st = { 0 };
896 struct stat st_cur = { 0 };
897 bool modified = false, occult = false, flags_changed = false;
898 int num_new = 0;
899 struct MhSequences mhs = { 0 };
900 struct HashTable *fnames = NULL;
902
903 const bool c_check_new = cs_subset_bool(NeoMutt->sub, "check_new");
904 if (!c_check_new)
905 return MX_STATUS_OK;
906
907 mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
908 if (stat(buf, &st) == -1)
909 return MX_STATUS_ERROR;
910
911 /* create .mh_sequences when there isn't one. */
912 snprintf(buf, sizeof(buf), "%s/.mh_sequences", mailbox_path(m));
913 int rc = stat(buf, &st_cur);
914 if ((rc == -1) && (errno == ENOENT))
915 {
916 char *tmp = NULL;
917 FILE *fp = NULL;
918
919 if (mh_mkstemp(m, &fp, &tmp))
920 {
921 mutt_file_fclose(&fp);
922 if (mutt_file_safe_rename(tmp, buf) == -1)
923 unlink(tmp);
924 FREE(&tmp);
925 }
926 }
927
928 if ((rc == -1) && (stat(buf, &st_cur) == -1))
929 modified = true;
930
932 (mutt_file_stat_timespec_compare(&st_cur, MUTT_STAT_MTIME, &mdata->mtime_cur) > 0))
933 {
934 modified = true;
935 }
936
937 if (!modified)
938 return MX_STATUS_OK;
939
940 /* Update the modification times on the mailbox.
941 *
942 * The monitor code notices changes in the open mailbox too quickly.
943 * In practice, this sometimes leads to all the new messages not being
944 * noticed during the SAME group of mtime stat updates. To work around
945 * the problem, don't update the stat times for a monitor caused check. */
946#ifdef USE_INOTIFY
948 MonitorContextChanged = false;
949 else
950#endif
951 {
954 }
955
956 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
957
958 mh_parse_dir(m, &mda, NULL);
959 mh_delayed_parsing(m, &mda, NULL);
960
961 if (mh_seq_read(&mhs, mailbox_path(m)) < 0)
962 return MX_STATUS_ERROR;
963 mh_update_maildir(&mda, &mhs);
964 mh_seq_free(&mhs);
965
966 /* check for modifications and adjust flags */
968
969 struct MdEmail *md = NULL;
970 struct MdEmail **mdp = NULL;
971 ARRAY_FOREACH(mdp, &mda)
972 {
973 md = *mdp;
974 /* the hash key must survive past the header, which is freed below. */
976 mutt_hash_insert(fnames, md->canon_fname, md);
977 }
978
979 for (int i = 0; i < m->msg_count; i++)
980 {
981 struct Email *e = m->emails[i];
982 if (!e)
983 break;
984
985 e->active = false;
986
987 md = mutt_hash_find(fnames, e->path);
988 if (md && md->email && email_cmp_strict(e, md->email))
989 {
990 e->active = true;
991 /* found the right message */
992 if (!e->changed)
993 if (maildir_update_flags(m, e, md->email))
994 flags_changed = true;
995
996 email_free(&md->email);
997 }
998 else /* message has disappeared */
999 occult = true;
1000 }
1001
1002 /* destroy the file name hash */
1003
1004 mutt_hash_free(&fnames);
1005
1006 /* If we didn't just get new mail, update the tables. */
1007 if (occult)
1009
1010 /* Incorporate new messages */
1011 num_new = maildir_move_to_mailbox(m, &mda);
1012 if (num_new > 0)
1013 {
1015 m->changed = true;
1016 }
1017
1018 ARRAY_FREE(&mda);
1019 if (occult)
1020 return MX_STATUS_REOPENED;
1021 if (num_new > 0)
1022 return MX_STATUS_NEW_MAIL;
1023 if (flags_changed)
1024 return MX_STATUS_FLAGS;
1025 return MX_STATUS_OK;
1026}
1027
1038{
1039 enum MxStatus check = mh_mbox_check(m);
1040 if (check == MX_STATUS_ERROR)
1041 return check;
1042
1043 struct HeaderCache *hc = NULL;
1044#ifdef USE_HCACHE
1045 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
1046 if (m->type == MUTT_MH)
1047 hc = mutt_hcache_open(c_header_cache, mailbox_path(m), NULL);
1048#endif
1049
1050 struct Progress *progress = NULL;
1051 if (m->verbose)
1052 {
1053 char msg[PATH_MAX] = { 0 };
1054 snprintf(msg, sizeof(msg), _("Writing %s..."), mailbox_path(m));
1055 progress = progress_new(msg, MUTT_PROGRESS_WRITE, m->msg_count);
1056 }
1057
1058 for (int i = 0; i < m->msg_count; i++)
1059 {
1060 if (m->verbose)
1061 progress_update(progress, i, -1);
1062
1063 if (mh_sync_mailbox_message(m, i, hc) == -1)
1064 {
1065 progress_free(&progress);
1066 goto err;
1067 }
1068 }
1069 progress_free(&progress);
1070
1071#ifdef USE_HCACHE
1072 if (m->type == MUTT_MH)
1074#endif
1075
1076 mh_seq_update(m);
1077
1078 /* XXX race condition? */
1079
1080 mh_update_mtime(m);
1081
1082 /* adjust indices */
1083
1084 if (m->msg_deleted)
1085 {
1086 for (int i = 0, j = 0; i < m->msg_count; i++)
1087 {
1088 struct Email *e = m->emails[i];
1089 if (!e)
1090 break;
1091
1092 if (!e->deleted)
1093 e->index = j++;
1094 }
1095 }
1096
1097 return check;
1098
1099err:
1100#ifdef USE_HCACHE
1101 if (m->type == MUTT_MH)
1103#endif
1104 return MX_STATUS_ERROR;
1105}
1106
1112{
1113 return MX_STATUS_OK;
1114}
1115
1119static bool mh_msg_open(struct Mailbox *m, struct Message *msg, int msgno)
1120{
1121 if (!m || !m->emails || (msgno >= m->msg_count))
1122 return false;
1123
1124 struct Email *e = m->emails[msgno];
1125 if (!e)
1126 return false;
1127
1128 char path[PATH_MAX] = { 0 };
1129
1130 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
1131
1132 msg->fp = fopen(path, "r");
1133 if (!msg->fp)
1134 {
1136 mutt_debug(LL_DEBUG1, "fopen: %s: %s (errno %d)\n", path, strerror(errno), errno);
1137 return false;
1138 }
1139
1140 return true;
1141}
1142
1148static bool mh_msg_open_new(struct Mailbox *m, struct Message *msg, const struct Email *e)
1149{
1150 return mh_mkstemp(m, &msg->fp, &msg->path);
1151}
1152
1156static int mh_msg_commit(struct Mailbox *m, struct Message *msg)
1157{
1158 return mh_commit_msg(m, msg, NULL, true);
1159}
1160
1166int mh_msg_close(struct Mailbox *m, struct Message *msg)
1167{
1168 return mutt_file_fclose(&msg->fp);
1169}
1170
1174int mh_path_canon(char *buf, size_t buflen)
1175{
1176 mutt_path_canon(buf, buflen, HomeDir, true);
1177 return 0;
1178}
1179
1183int mh_path_parent(char *buf, size_t buflen)
1184{
1185 if (mutt_path_parent(buf))
1186 return 0;
1187
1188 if (buf[0] == '~')
1189 mutt_path_canon(buf, buflen, HomeDir, true);
1190
1191 if (mutt_path_parent(buf))
1192 return 0;
1193
1194 return -1;
1195}
1196
1200int mh_path_pretty(char *buf, size_t buflen, const char *folder)
1201{
1202 if (mutt_path_abbr_folder(buf, folder))
1203 return 0;
1204
1205 if (mutt_path_pretty(buf, buflen, HomeDir, false))
1206 return 0;
1207
1208 return -1;
1209}
1210
1214static enum MailboxType mh_path_probe(const char *path, const struct stat *st)
1215{
1216 if (!st || !S_ISDIR(st->st_mode))
1217 return MUTT_UNKNOWN;
1218
1219 char tmp[PATH_MAX] = { 0 };
1220
1221 snprintf(tmp, sizeof(tmp), "%s/.mh_sequences", path);
1222 if (access(tmp, F_OK) == 0)
1223 return MUTT_MH;
1224
1225 snprintf(tmp, sizeof(tmp), "%s/.xmhcache", path);
1226 if (access(tmp, F_OK) == 0)
1227 return MUTT_MH;
1228
1229 snprintf(tmp, sizeof(tmp), "%s/.mew_cache", path);
1230 if (access(tmp, F_OK) == 0)
1231 return MUTT_MH;
1232
1233 snprintf(tmp, sizeof(tmp), "%s/.mew-cache", path);
1234 if (access(tmp, F_OK) == 0)
1235 return MUTT_MH;
1236
1237 snprintf(tmp, sizeof(tmp), "%s/.sylpheed_cache", path);
1238 if (access(tmp, F_OK) == 0)
1239 return MUTT_MH;
1240
1241 /* ok, this isn't an mh folder, but mh mode can be used to read
1242 * Usenet news from the spool. */
1243
1244 snprintf(tmp, sizeof(tmp), "%s/.overview", path);
1245 if (access(tmp, F_OK) == 0)
1246 return MUTT_MH;
1247
1248 return MUTT_UNKNOWN;
1249}
1250
1254struct MxOps MxMhOps = {
1255 // clang-format off
1256 .type = MUTT_MH,
1257 .name = "mh",
1258 .is_local = true,
1259 .ac_owns_path = mh_ac_owns_path,
1260 .ac_add = mh_ac_add,
1261 .mbox_open = mh_mbox_open,
1262 .mbox_open_append = mh_mbox_open_append,
1263 .mbox_check = mh_mbox_check,
1264 .mbox_check_stats = mh_mbox_check_stats,
1265 .mbox_sync = mh_mbox_sync,
1266 .mbox_close = mh_mbox_close,
1267 .msg_open = mh_msg_open,
1268 .msg_open_new = mh_msg_open_new,
1269 .msg_commit = mh_msg_commit,
1270 .msg_close = mh_msg_close,
1271 .msg_padding_size = NULL,
1272 .msg_save_hcache = mh_msg_save_hcache,
1273 .tags_edit = NULL,
1274 .tags_commit = NULL,
1275 .path_probe = mh_path_probe,
1276 .path_canon = mh_path_canon,
1277 .path_pretty = mh_path_pretty,
1278 .path_parent = mh_path_parent,
1279 .path_is_empty = mh_check_empty,
1280 // clang-format on
1281};
#define ARRAY_SORT(head, fn)
Sort an array.
Definition: array.h:277
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:155
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:211
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:86
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:203
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:57
const char * mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: atoi.c:202
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:327
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
Convenience wrapper for the config headers.
char * HomeDir
User's home directory.
Definition: mutt_globals.h:49
int mutt_copy_message(FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:864
Duplicate the structure of an entire email.
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:40
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:52
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
Convenience wrapper for the core headers.
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
bool email_cmp_strict(const struct Email *e1, const struct Email *e2)
Strictly compare message emails.
Definition: email.c:100
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
Structs that make up an email.
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:1611
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:344
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:930
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1569
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:1651
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:168
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:63
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
bool mh_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Implements MxOps::ac_add() -.
Definition: mh.c:841
bool mh_ac_owns_path(struct Account *a, const char *path)
Check whether an Account own a Mailbox path - Implements MxOps::ac_owns_path() -.
Definition: mh.c:833
struct MxOps MxMhOps
MH Mailbox - Implements MxOps -.
Definition: mh.c:1254
static enum MxStatus mh_mbox_check_stats(struct Mailbox *m, uint8_t flags)
Check the Mailbox statistics - Implements MxOps::mbox_check_stats() -.
Definition: mh.c:190
enum MxStatus mh_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition: mh.c:892
enum MxStatus mh_mbox_close(struct Mailbox *m)
Close a Mailbox - Implements MxOps::mbox_close() -.
Definition: mh.c:1111
static bool mh_mbox_open_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a Mailbox for appending - Implements MxOps::mbox_open_append() -.
Definition: mh.c:857
static enum MxOpenReturns mh_mbox_open(struct Mailbox *m)
Open a Mailbox - Implements MxOps::mbox_open() -.
Definition: mh.c:849
enum MxStatus mh_mbox_sync(struct Mailbox *m)
Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
Definition: mh.c:1037
int mh_msg_close(struct Mailbox *m, struct Message *msg)
Close an email - Implements MxOps::msg_close() -.
Definition: mh.c:1166
static int mh_msg_commit(struct Mailbox *m, struct Message *msg)
Save changes to an email - Implements MxOps::msg_commit() -.
Definition: mh.c:1156
static bool mh_msg_open_new(struct Mailbox *m, struct Message *msg, const struct Email *e)
Open a new message in a Mailbox - Implements MxOps::msg_open_new() -.
Definition: mh.c:1148
static bool mh_msg_open(struct Mailbox *m, struct Message *msg, int msgno)
Open an email message in a Mailbox - Implements MxOps::msg_open() -.
Definition: mh.c:1119
int mh_msg_save_hcache(struct Mailbox *m, struct Email *e)
Save message to the header cache - Implements MxOps::msg_save_hcache() -.
Definition: mh.c:818
int mh_path_canon(char *buf, size_t buflen)
Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
Definition: mh.c:1174
int mh_path_parent(char *buf, size_t buflen)
Find the parent of a Mailbox path - Implements MxOps::path_parent() -.
Definition: mh.c:1183
int mh_path_pretty(char *buf, size_t buflen, const char *folder)
Abbreviate a Mailbox path - Implements MxOps::path_pretty() -.
Definition: mh.c:1200
static enum MailboxType mh_path_probe(const char *path, const struct stat *st)
Is this an mh Mailbox? - Implements MxOps::path_probe() -.
Definition: mh.c:1214
int mh_cmp_path(const void *a, const void *b)
Compare two Maildirs by path - Implements sort_t -.
Definition: mh.c:558
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
Header cache multiplexor.
int mutt_hcache_store(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition: hcache.c:552
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:432
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:332
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:631
static struct Email * restore(const unsigned char *d)
Restore an Email from data retrieved from the cache.
Definition: hcache.c:143
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:456
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:222
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:177
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:176
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
MailboxType
Supported mailbox formats.
Definition: mailbox.h:41
@ MUTT_MH
'MH' Mailbox type
Definition: mailbox.h:47
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:44
void maildir_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:38
struct MaildirEmailData * maildir_edata_new(void)
Create a new MaildirEmailData object.
Definition: edata.c:53
bool maildir_update_flags(struct Mailbox *m, struct Email *e_old, struct Email *e_new)
Update the mailbox flags.
Definition: shared.c:122
void maildir_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free()
Definition: mdata.c:37
struct MaildirMboxData * maildir_mdata_get(struct Mailbox *m)
Get the private data for this Mailbox.
Definition: mdata.c:58
struct MaildirMboxData * maildir_mdata_new(void)
Create a new MaildirMboxData object.
Definition: mdata.c:47
mode_t mh_umask(struct Mailbox *m)
Create a umask from the mailbox directory.
Definition: shared.c:52
int maildir_move_to_mailbox(struct Mailbox *m, struct MdEmailArray *mda)
Copy the Maildir list to the Mailbox.
Definition: shared.c:75
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:43
int mh_check_empty(const char *path)
Is mailbox empty.
Definition: mh.c:166
int mh_sync_message(struct Mailbox *m, int msgno)
Sync an email to an MH folder.
Definition: mh.c:451
int mh_sync_mailbox_message(struct Mailbox *m, int msgno, struct HeaderCache *hc)
Save changes to the mailbox.
Definition: mh.c:756
void mh_update_mtime(struct Mailbox *m)
Update our record of the Maildir modification time.
Definition: mh.c:477
void mh_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
This function does the second parsing pass.
Definition: mh.c:614
struct Email * mh_parse_message(const char *fname, struct Email *e)
Actually parse an MH message.
Definition: mh.c:574
bool mh_valid_message(const char *s)
Is this a valid MH message filename.
Definition: mh.c:149
void mh_update_maildir(struct MdEmailArray *mda, struct MhSequences *mhs)
Update our record of flags.
Definition: mh.c:260
int mh_commit_msg(struct Mailbox *m, struct Message *msg, struct Email *e, bool updseq)
Commit a message to an MH folder.
Definition: mh.c:293
bool mh_mkstemp(struct Mailbox *m, FILE **fp, char **tgt)
Create a temporary file.
Definition: mh.c:78
int mh_rewrite_message(struct Mailbox *m, int msgno)
Sync a message in an MH folder.
Definition: mh.c:373
static int mh_already_notified(struct Mailbox *m, int msgno)
Has the message changed.
Definition: mh.c:126
static bool mh_read_dir(struct Mailbox *m)
Read an MH mailbox.
Definition: mh.c:692
int mh_parse_dir(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
Read a Maildir mailbox.
Definition: mh.c:502
bool MonitorContextChanged
true after the current mailbox has changed
Definition: monitor.c:51
Monitor files for changes.
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
bool mutt_path_abbr_folder(char *buf, const char *folder)
Create a folder abbreviation.
Definition: path.c:490
bool mutt_path_pretty(char *buf, size_t buflen, const char *homedir, bool is_dir)
Tidy a filesystem path.
Definition: path.c:186
bool mutt_path_canon(char *buf, size_t buflen, const char *homedir, bool is_dir)
Create the canonical version of a path.
Definition: path.c:285
bool mutt_path_parent(char *buf)
Find the parent of a path.
Definition: path.c:458
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:652
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
#define PATH_MAX
Definition: mutt.h:40
Hundreds of global variables to back the user variables.
char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:50
SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:69
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1193
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1147
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1057
API for mailboxes.
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:42
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mxapi.h:60
#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:66
MxOpenReturns
Return values for mbox_open()
Definition: mxapi.h:97
@ MX_OPEN_ERROR
Open failed with an error.
Definition: mxapi.h:99
@ MX_OPEN_OK
Open succeeded.
Definition: mxapi.h:98
#define MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn't exist.
Definition: mxapi.h:70
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_snc(), and mbox_close()
Definition: mxapi.h:84
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:85
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:86
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition: mxapi.h:90
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:89
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:87
Notmuch-specific Mailbox data.
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1158
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
Pop-specific Email data.
Progress bar.
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: lib.h:49
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition: lib.h:50
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:86
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:73
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:118
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: random.c:129
void mh_seq_add_one(struct Mailbox *m, int n, bool unseen, bool flagged, bool replied)
Update the flags for one sequence.
Definition: sequence.c:107
MhSeqFlags mh_seq_check(struct MhSequences *mhs, int i)
Get the flags for a given sequence.
Definition: sequence.c:78
void mh_seq_free(struct MhSequences *mhs)
Free some sequences.
Definition: sequence.c:67
int mh_seq_changed(struct Mailbox *m)
Has the mailbox changed.
Definition: sequence.c:436
void mh_seq_update(struct Mailbox *m)
Update sequence numbers.
Definition: sequence.c:231
int mh_seq_read(struct MhSequences *mhs, const char *path)
Read a set of MH sequences.
Definition: sequence.c:375
MH Mailbox Sequences.
#define MH_SEQ_UNSEEN
Email hasn't been read.
Definition: sequence.h:33
#define MH_SEQ_REPLIED
Email has been replied to.
Definition: sequence.h:34
uint8_t MhSeqFlags
Flags, e.g. MH_SEQ_UNSEEN.
Definition: sequence.h:31
#define MH_SEQ_FLAGGED
Email is flagged.
Definition: sequence.h:35
GUI display the mailboxes in a side panel.
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:48
Key value store.
#define NONULL(x)
Definition: string2.h:37
A group of associated Mailboxes.
Definition: account.h:37
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
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:34
The envelope/body of an email.
Definition: email.h:37
bool read
Email is read.
Definition: email.h:48
struct Envelope * env
Envelope information.
Definition: email.h:66
void * edata
Driver-specific data.
Definition: email.h:72
int lines
How many lines in the body of this message?
Definition: email.h:60
struct Body * body
List of MIME parts.
Definition: email.h:67
bool active
Message is not to be removed.
Definition: email.h:74
bool old
Email is seen, but unread.
Definition: email.h:47
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:87
bool changed
Email has been edited.
Definition: email.h:75
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:99
bool flagged
Marked important?
Definition: email.h:45
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:58
bool replied
Email has been replied to.
Definition: email.h:49
int msgno
Number displayed to the user.
Definition: email.h:111
char * path
Path of Email (for local Mailboxes)
Definition: email.h:68
bool deleted
Email is deleted.
Definition: email.h:76
int index
The absolute (unsorted) message number.
Definition: email.h:110
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:59
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:92
Wrapper for Email retrieved from the header cache.
Definition: lib.h:98
uint32_t uidvalidity
IMAP-specific UIDVALIDITY.
Definition: lib.h:99
struct Email * email
Retrieved email.
Definition: lib.h:101
A Hash Table.
Definition: hash.h:97
Header cache structure.
Definition: lib.h:87
A mailbox.
Definition: mailbox.h:79
void(* mdata_free)(void **ptr)
Free the private data attached to the Mailbox.
Definition: mailbox.h:142
bool changed
Mailbox has been modified.
Definition: mailbox.h:110
bool has_new
Mailbox has new mail.
Definition: mailbox.h:85
struct timespec mtime
Time Mailbox was last changed.
Definition: mailbox.h:104
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
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:105
bool verbose
Display status messages?
Definition: mailbox.h:114
int msg_unread
Number of unread messages.
Definition: mailbox.h:89
Maildir-specific Mailbox data -.
Definition: mdata.h:35
mode_t mh_umask
umask to use when creating files
Definition: mdata.h:37
A Maildir Email helper.
Definition: mdemail.h:34
bool header_parsed
Definition: mdemail.h:37
char * canon_fname
Definition: mdemail.h:36
struct Email * email
Definition: mdemail.h:35
A local copy of an email.
Definition: mxapi.h:43
FILE * fp
pointer to the message data
Definition: mxapi.h:44
char * path
path to temp file
Definition: mxapi.h:45
bool replied
Message has been replied to.
Definition: mxapi.h:52
char * committed_path
the final path generated by mx_msg_commit()
Definition: mxapi.h:46
bool flagged
Message is flagged.
Definition: mxapi.h:51
bool read
Message has been read.
Definition: mxapi.h:50
struct Message::@0 flags
Flags for the Message.
Set of MH sequence numbers.
Definition: sequence.h:41
int max
Number of flags stored.
Definition: sequence.h:42
Definition: mxapi.h:112
enum MailboxType type
Mailbox type, e.g. MUTT_IMAP.
Definition: mxapi.h:113
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39