NeoMutt  2025-12-11-980-ge38c27
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
mh.c
Go to the documentation of this file.
1
26
34
35#include "config.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 "mutt/lib.h"
47#include "config/lib.h"
48#include "email/lib.h"
49#include "core/lib.h"
50#include "mutt.h"
51#include "progress/lib.h"
52#include "errno.h"
53#include "mdata.h"
54#include "mhemail.h"
55#include "mx.h"
56#include "sequence.h"
57#include "shared.h"
58#ifdef USE_INOTIFY
59#include "monitor.h"
60#endif
61#ifdef USE_HCACHE
62#include "hcache/lib.h"
63#else
64struct HeaderCache;
65#endif
66
67struct Progress;
68
77static int mh_already_notified(struct Mailbox *m, int msgno)
78{
79 char path[PATH_MAX] = { 0 };
80 struct stat st = { 0 };
81
82 if ((snprintf(path, sizeof(path), "%s/%d", mailbox_path(m), msgno) < sizeof(path)) &&
83 (stat(path, &st) == 0))
84 {
86 }
87 return -1;
88}
89
99static bool mh_valid_message(const char *s)
100{
101 for (; *s; s++)
102 {
103 if (!mutt_isdigit(*s))
104 return false;
105 }
106 return true;
107}
108
116int mh_check_empty(struct Buffer *path)
117{
118 struct dirent *de = NULL;
119 int rc = 1; /* assume empty until we find a message */
120
122 if (!dir)
123 return -1;
124 while ((de = readdir(dir)))
125 {
126 if (mh_valid_message(de->d_name))
127 {
128 rc = 0;
129 break;
130 }
131 }
132 closedir(dir);
133
134 return rc;
135}
136
140static enum MxStatus mh_mbox_check_stats(struct Mailbox *m, uint8_t flags)
141{
142 struct MhSequences mhs = { 0 };
143 DIR *dir = NULL;
144 struct dirent *de = NULL;
145
146 /* when $mail_check_recent is set and the .mh_sequences file hasn't changed
147 * since the last m visit, there is no "new mail" */
148 const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
149 if (c_mail_check_recent && (mh_seq_changed(m) <= 0))
150 {
151 return MX_STATUS_OK;
152 }
153
154 if (mh_seq_read(&mhs, mailbox_path(m)) < 0)
155 return MX_STATUS_ERROR;
156
157 m->msg_count = 0;
158 m->msg_unread = 0;
159 m->msg_flagged = 0;
160
161 enum MxStatus rc = MX_STATUS_OK;
162 bool check_new = true;
163 for (int i = mhs.max; i > 0; i--)
164 {
165 if ((mh_seq_check(&mhs, i) & MH_SEQ_FLAGGED))
166 m->msg_flagged++;
167 if (mh_seq_check(&mhs, i) & MH_SEQ_UNSEEN)
168 {
169 m->msg_unread++;
170 if (check_new)
171 {
172 /* if the first unseen message we encounter was in the m during the
173 * last visit, don't notify about it */
174 if (!c_mail_check_recent || (mh_already_notified(m, i) == 0))
175 {
176 m->has_new = true;
178 }
179 /* Because we are traversing from high to low, we can stop
180 * checking for new mail after the first unseen message.
181 * Whether it resulted in "new mail" or not. */
182 check_new = false;
183 }
184 }
185 }
186
187 mh_seq_free(&mhs);
188
190 if (dir)
191 {
192 while ((de = readdir(dir)))
193 {
194 if (*de->d_name == '.')
195 continue;
196 if (mh_valid_message(de->d_name))
197 m->msg_count++;
198 }
199 closedir(dir);
200 }
201
202 return rc;
203}
204
210static void mh_update_emails(struct MhEmailArray *mha, struct MhSequences *mhs)
211{
212 struct MhEmail *md = NULL;
213 struct MhEmail **mdp = NULL;
214 ARRAY_FOREACH(mdp, mha)
215 {
216 md = *mdp;
217 char *p = strrchr(md->email->path, '/');
218 if (p)
219 p++;
220 else
221 p = md->email->path;
222
223 int i = 0;
224 if (!mutt_str_atoi_full(p, &i))
225 continue;
226 MhSeqFlags flags = mh_seq_check(mhs, i);
227
228 md->email->read = !(flags & MH_SEQ_UNSEEN);
229 md->email->flagged = (flags & MH_SEQ_FLAGGED);
230 md->email->replied = (flags & MH_SEQ_REPLIED);
231 }
232}
233
243static int mh_commit_msg(struct Mailbox *m, struct Message *msg, struct Email *e, bool updseq)
244{
245 struct dirent *de = NULL;
246 char *cp = NULL;
247 char *dep = NULL;
248 unsigned int n = 0;
249 unsigned int hi = 0;
250 char path[PATH_MAX] = { 0 };
251 char tmp[16] = { 0 };
252
253 if (mutt_file_fsync_close(&msg->fp))
254 {
255 mutt_perror(_("Could not flush message to disk"));
256 return -1;
257 }
258
260 if (!dir)
261 {
262 mutt_perror("%s", mailbox_path(m));
263 return -1;
264 }
265
266 /* figure out what the next message number is */
267 while ((de = readdir(dir)))
268 {
269 dep = de->d_name;
270 if (*dep == ',')
271 dep++;
272 cp = dep;
273 while (*cp)
274 {
275 if (!mutt_isdigit(*cp))
276 break;
277 cp++;
278 }
279 if (*cp == '\0')
280 {
281 if (!mutt_str_atoui(dep, &n))
282 {
283 mutt_debug(LL_DEBUG2, "Invalid MH message number '%s'\n", dep);
284 }
285 else if (n > hi)
286 {
287 hi = n;
288 }
289 }
290 }
291 closedir(dir);
292
293 /* Now try to rename the file to the proper name.
294 * Note: We may have to try multiple times, until we find a free slot. */
295
296 while (true)
297 {
298 hi++;
299 snprintf(tmp, sizeof(tmp), "%u", hi);
300 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), tmp);
301 if (mutt_file_safe_rename(msg->path, path) == 0)
302 {
303 if (e)
304 mutt_str_replace(&e->path, tmp);
305 mutt_str_replace(&msg->committed_path, path);
306 FREE(&msg->path);
307 break;
308 }
309 else if (errno != EEXIST)
310 {
311 mutt_perror("%s", mailbox_path(m));
312 return -1;
313 }
314 }
315 if (updseq)
316 {
317 mh_seq_add_one(m, hi, !msg->flags.read, msg->flags.flagged, msg->flags.replied);
318 }
319 return 0;
320}
321
329static int mh_rewrite_message(struct Mailbox *m, struct Email *e)
330{
331 if (!m || !e)
332 return -1;
333
334 bool restore = true;
335
336 long old_body_offset = e->body->offset;
337 long old_body_length = e->body->length;
338 long old_hdr_lines = e->lines;
339
340 struct Message *src = mx_msg_open(m, e);
341 struct Message *dest = mx_msg_open_new(m, e, MUTT_MSG_NONE);
342 if (!src || !dest)
343 return -1;
344
345 int rc = mutt_copy_message(dest->fp, e, src, MUTT_CM_UPDATE, CH_UPDATE | CH_UPDATE_LEN, 0);
346 if (rc == 0)
347 {
348 char oldpath[PATH_MAX] = { 0 };
349 char partpath[PATH_MAX] = { 0 };
350 snprintf(oldpath, sizeof(oldpath), "%s/%s", mailbox_path(m), e->path);
351 mutt_str_copy(partpath, e->path, sizeof(partpath));
352
353 rc = mh_commit_msg(m, dest, e, false);
354
355 if (rc == 0)
356 {
357 unlink(oldpath);
358 restore = false;
359 }
360
361 /* Try to move the new message to the old place.
362 * (MH only.)
363 *
364 * This is important when we are just updating flags.
365 *
366 * Note that there is a race condition against programs which
367 * use the first free slot instead of the maximum message
368 * number. NeoMutt does _not_ behave like this.
369 *
370 * Anyway, if this fails, the message is in the folder, so
371 * all what happens is that a concurrently running neomutt will
372 * lose flag modifications. */
373 if (rc == 0)
374 {
375 char newpath[PATH_MAX] = { 0 };
376 snprintf(newpath, sizeof(newpath), "%s/%s", mailbox_path(m), e->path);
377 rc = mutt_file_safe_rename(newpath, oldpath);
378 if (rc == 0)
379 mutt_str_replace(&e->path, partpath);
380 }
381 }
382 mx_msg_close(m, &src);
383 mx_msg_close(m, &dest);
384
385 if ((rc == -1) && restore)
386 {
387 e->body->offset = old_body_offset;
388 e->body->length = old_body_length;
389 e->lines = old_hdr_lines;
390 }
391
393 return rc;
394}
395
403static int mh_sync_message(struct Mailbox *m, struct Email *e)
404{
405 if (!m || !e)
406 return -1;
407
408 if (e->attach_del || e->env->changed)
409 {
410 if (mh_rewrite_message(m, e) != 0)
411 return -1;
412 e->env->changed = false;
413 }
414
415 return 0;
416}
417
422static void mh_update_mtime(struct Mailbox *m)
423{
424 char buf[PATH_MAX] = { 0 };
425 struct stat st = { 0 };
426 struct MhMboxData *mdata = mh_mdata_get(m);
427
428 snprintf(buf, sizeof(buf), "%s/.mh_sequences", mailbox_path(m));
429 if (stat(buf, &st) == 0)
431
432 mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
433
434 if (stat(buf, &st) == 0)
436}
437
447static int mh_parse_dir(struct Mailbox *m, struct MhEmailArray *mha, struct Progress *progress)
448{
449 struct dirent *de = NULL;
450 int rc = 0;
451 struct MhEmail *entry = NULL;
452 struct Email *e = NULL;
453
454 struct Buffer *buf = buf_pool_get();
455 buf_strcpy(buf, mailbox_path(m));
456
458 if (!dir)
459 {
460 rc = -1;
461 goto cleanup;
462 }
463
464 while (((de = readdir(dir))) && !SigInt)
465 {
466 if (!mh_valid_message(de->d_name))
467 continue;
468
469 mutt_debug(LL_DEBUG2, "queueing %s\n", de->d_name);
470
471 e = email_new();
472
473 progress_update(progress, ARRAY_SIZE(mha) + 1, -1);
474
475 e->path = mutt_str_dup(de->d_name);
476
477 entry = mh_entry_new();
478 entry->email = e;
479 ARRAY_ADD(mha, entry);
480 }
481
482 closedir(dir);
483
484 if (SigInt)
485 {
486 SigInt = false;
487 rc = -2; /* action aborted */
488 goto cleanup;
489 }
490
491cleanup:
492 buf_pool_release(&buf);
493
494 return rc;
495}
496
500static int mh_sort_path(const void *a, const void *b, void *sdata)
501{
502 struct MhEmail const *pa = *(struct MhEmail const *const *) a;
503 struct MhEmail const *pb = *(struct MhEmail const *const *) b;
504 return mutt_str_cmp(pa->email->path, pb->email->path);
505}
506
516static struct Email *mh_parse_message(const char *fname, struct Email *e)
517{
518 FILE *fp = mutt_file_fopen(fname, "r");
519 if (!fp)
520 {
521 return NULL;
522 }
523
524 const long size = mutt_file_get_size_fp(fp);
525 if (size == 0)
526 {
527 mutt_file_fclose(&fp);
528 return NULL;
529 }
530
531 if (!e)
532 e = email_new();
533
534 e->env = mutt_rfc822_read_header(fp, e, false, false);
535
536 if (e->received == 0)
537 e->received = e->date_sent;
538
539 /* always update the length since we have fresh information available. */
540 e->body->length = size - e->body->offset;
541 e->index = -1;
542
543 mutt_file_fclose(&fp);
544 return e;
545}
546
553static void mh_delayed_parsing(struct Mailbox *m, struct MhEmailArray *mha,
554 struct Progress *progress)
555{
556 char fn[PATH_MAX] = { 0 };
557
558#ifdef USE_HCACHE
559 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
560 struct HeaderCache *hc = hcache_open(c_header_cache, mailbox_path(m), NULL, true);
561#endif
562
563 struct MhEmail *md = NULL;
564 struct MhEmail **mdp = NULL;
565 ARRAY_FOREACH(mdp, mha)
566 {
567 md = *mdp;
568 if (!md || !md->email || md->header_parsed)
569 continue;
570
571 progress_update(progress, ARRAY_FOREACH_IDX_mdp, -1);
572
573#ifdef USE_HCACHE
574 const char *key = md->email->path;
575 size_t keylen = strlen(key);
576 struct HCacheEntry hce = hcache_fetch_email(hc, key, keylen, 0);
577
578 if (hce.email)
579 {
580 hce.email->old = md->email->old;
581 hce.email->path = mutt_str_dup(md->email->path);
582 email_free(&md->email);
583 md->email = hce.email;
584 }
585 else
586#endif
587 {
588 snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
589
590 if (mh_parse_message(fn, md->email))
591 {
592 md->header_parsed = true;
593#ifdef USE_HCACHE
594 key = md->email->path;
595 keylen = strlen(key);
596 hcache_store_email(hc, key, keylen, md->email, 0);
597#endif
598 }
599 else
600 {
601 email_free(&md->email);
602 }
603 }
604 }
605#ifdef USE_HCACHE
606 hcache_close(&hc);
607#endif
608
609 const enum EmailSortType c_sort = cs_subset_sort(NeoMutt->sub, "sort");
610 if (m && mha && (ARRAY_SIZE(mha) > 0) && (c_sort == EMAIL_SORT_UNSORTED))
611 {
612 mutt_debug(LL_DEBUG3, "mh: sorting %s into natural order\n", mailbox_path(m));
613 ARRAY_SORT(mha, mh_sort_path, NULL);
614 }
615}
616
624static int mh_move_to_mailbox(struct Mailbox *m, const struct MhEmailArray *mha)
625{
626 if (!m)
627 return 0;
628
629 int oldmsgcount = m->msg_count;
630
631 struct MhEmail *md = NULL;
632 struct MhEmail **mdp = NULL;
633 ARRAY_FOREACH(mdp, mha)
634 {
635 md = *mdp;
636 mutt_debug(LL_DEBUG2, "Considering %s\n", NONULL(md->canon_fname));
637 if (!md->email)
638 continue;
639
640 mutt_debug(LL_DEBUG2, "Adding header structure. Flags: %s%s%s%s%s\n",
641 md->email->flagged ? "f" : "", md->email->deleted ? "D" : "",
642 md->email->replied ? "r" : "", md->email->old ? "O" : "",
643 md->email->read ? "R" : "");
645
646 m->emails[m->msg_count] = md->email;
647 m->emails[m->msg_count]->index = m->msg_count;
648 mailbox_size_add(m, md->email);
649
650 md->email = NULL;
651 m->msg_count++;
652 }
653
654 int num = 0;
655 if (m->msg_count > oldmsgcount)
656 num = m->msg_count - oldmsgcount;
657
658 return num;
659}
660
667static bool mh_read_dir(struct Mailbox *m)
668{
669 if (!m)
670 return false;
671
672 mutt_path_tidy(&m->pathbuf, true);
673
674 struct MhSequences mhs = { 0 };
675 struct Progress *progress = NULL;
676
677 if (m->verbose)
678 {
679 progress = progress_new(MUTT_PROGRESS_READ, 0);
680 progress_set_message(progress, _("Scanning %s..."), mailbox_path(m));
681 }
682
683 struct MhMboxData *mdata = mh_mdata_get(m);
684 if (!mdata)
685 {
687 m->mdata = mdata;
689 }
690
692
693 struct MhEmailArray mha = ARRAY_HEAD_INITIALIZER;
694 int rc = mh_parse_dir(m, &mha, progress);
695 progress_free(&progress);
696 if (rc < 0)
697 return false;
698
699 if (m->verbose)
700 {
701 progress = progress_new(MUTT_PROGRESS_READ, ARRAY_SIZE(&mha));
702 progress_set_message(progress, _("Reading %s..."), mailbox_path(m));
703 }
704 mh_delayed_parsing(m, &mha, progress);
705 progress_free(&progress);
706
707 if (mh_seq_read(&mhs, mailbox_path(m)) < 0)
708 {
709 mharray_clear(&mha);
710 return false;
711 }
712 mh_update_emails(&mha, &mhs);
713 mh_seq_free(&mhs);
714
715 mh_move_to_mailbox(m, &mha);
716 mharray_clear(&mha);
717
718 if (!mdata->umask)
719 mdata->umask = mh_umask(m);
720
721 return true;
722}
723
732int mh_sync_mailbox_message(struct Mailbox *m, struct Email *e, struct HeaderCache *hc)
733{
734 if (!m || !e)
735 return -1;
736
737 if (e->deleted)
738 {
739 char path[PATH_MAX] = { 0 };
740 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
741 const bool c_mh_purge = cs_subset_bool(NeoMutt->sub, "mh_purge");
742 if (c_mh_purge)
743 {
744#ifdef USE_HCACHE
745 if (hc)
746 {
747 const char *key = e->path;
748 size_t keylen = strlen(key);
749 hcache_delete_email(hc, key, keylen);
750 }
751#endif
752 unlink(path);
753 }
754 else
755 {
756 /* MH just moves files out of the way when you delete them */
757 if (*e->path != ',')
758 {
759 char tmp[PATH_MAX] = { 0 };
760 snprintf(tmp, sizeof(tmp), "%s/,%s", mailbox_path(m), e->path);
761 unlink(tmp);
762 if (rename(path, tmp) != 0)
763 {
764 return -1;
765 }
766 }
767 }
768 }
769 else if (e->changed || e->attach_del)
770 {
771 if (mh_sync_message(m, e) == -1)
772 return -1;
773 }
774
775#ifdef USE_HCACHE
776 if (hc && e->changed)
777 {
778 const char *key = e->path;
779 size_t keylen = strlen(key);
780 hcache_store_email(hc, key, keylen, e, 0);
781 }
782#endif
783
784 return 0;
785}
786
790static int mh_msg_save_hcache(struct Mailbox *m, struct Email *e)
791{
792 int rc = 0;
793#ifdef USE_HCACHE
794 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
795 struct HeaderCache *hc = hcache_open(c_header_cache, mailbox_path(m), NULL, true);
796 rc = hcache_store_email(hc, e->path, strlen(e->path), e, 0);
797 hcache_close(&hc);
798#endif
799 return rc;
800}
801
805static bool mh_ac_owns_path(struct Account *a, const char *path)
806{
807 return true;
808}
809
813static bool mh_ac_add(struct Account *a, struct Mailbox *m)
814{
815 return true;
816}
817
821static enum MxOpenReturns mh_mbox_open(struct Mailbox *m)
822{
824}
825
829static bool mh_mbox_open_append(struct Mailbox *m, OpenMailboxFlags flags)
830{
831 if (!(flags & MUTT_APPENDNEW))
832 return true;
833
834 if (mutt_file_mkdir(mailbox_path(m), S_IRWXU) != 0)
835 {
836 mutt_perror("%s", mailbox_path(m));
837 return false;
838 }
839
840 char tmp[PATH_MAX] = { 0 };
841 snprintf(tmp, sizeof(tmp), "%s/.mh_sequences", mailbox_path(m));
842 const int i = creat(tmp, S_IRUSR | S_IWUSR);
843 if (i == -1)
844 {
845 mutt_perror("%s", tmp);
846 rmdir(mailbox_path(m));
847 return false;
848 }
849 close(i);
850
851 return true;
852}
853
862static bool mh_update_flags(struct Mailbox *m, struct Email *e_old, struct Email *e_new)
863{
864 if (!m)
865 return false;
866
867 /* save the global state here so we can reset it at the
868 * end of list block if required. */
869 bool context_changed = m->changed;
870
871 /* user didn't modify this message. alter the flags to match the
872 * current state on disk. This may not actually do
873 * anything. mutt_set_flag() will just ignore the call if the status
874 * bits are already properly set, but it is still faster not to pass
875 * through it */
876 if (e_old->flagged != e_new->flagged)
877 mutt_set_flag(m, e_old, MUTT_FLAG, e_new->flagged, true);
878 if (e_old->replied != e_new->replied)
879 mutt_set_flag(m, e_old, MUTT_REPLIED, e_new->replied, true);
880 if (e_old->read != e_new->read)
881 mutt_set_flag(m, e_old, MUTT_READ, e_new->read, true);
882 if (e_old->old != e_new->old)
883 mutt_set_flag(m, e_old, MUTT_OLD, e_new->old, true);
884
885 /* mutt_set_flag() will set this, but we don't need to
886 * sync the changes we made because we just updated the
887 * context to match the current on-disk state of the
888 * message. */
889 bool header_changed = e_old->changed;
890 e_old->changed = false;
891
892 /* if the mailbox was not modified before we made these
893 * changes, unset the changed flag since nothing needs to
894 * be synchronized. */
895 if (!context_changed)
896 m->changed = false;
897
898 return header_changed;
899}
900
913static enum MxStatus mh_check(struct Mailbox *m)
914{
915 char buf[PATH_MAX] = { 0 };
916 struct stat st = { 0 };
917 struct stat st_cur = { 0 };
918 bool modified = false, occult = false, flags_changed = false;
919 int num_new = 0;
920 struct MhSequences mhs = { 0 };
921 struct HashTable *fnames = NULL;
922 struct MhMboxData *mdata = mh_mdata_get(m);
923
924 const bool c_check_new = cs_subset_bool(NeoMutt->sub, "check_new");
925 if (!c_check_new)
926 return MX_STATUS_OK;
927
928 mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
929 if (stat(buf, &st) == -1)
930 return MX_STATUS_ERROR;
931
932 /* create .mh_sequences when there isn't one. */
933 snprintf(buf, sizeof(buf), "%s/.mh_sequences", mailbox_path(m));
934 int rc = stat(buf, &st_cur);
935 if ((rc == -1) && (errno == ENOENT))
936 {
937 char *tmp = NULL;
938 FILE *fp = NULL;
939
940 if (mh_mkstemp(m, &fp, &tmp))
941 {
942 mutt_file_fclose(&fp);
943 if (mutt_file_safe_rename(tmp, buf) == -1)
944 unlink(tmp);
945 FREE(&tmp);
946 }
947 }
948
949 if ((rc == -1) && (stat(buf, &st_cur) == -1))
950 modified = true;
951
952 if ((mutt_file_stat_timespec_compare(&st, MUTT_STAT_MTIME, &mdata->mtime) > 0) ||
953 (mutt_file_stat_timespec_compare(&st_cur, MUTT_STAT_MTIME, &mdata->mtime_seq) > 0))
954 {
955 modified = true;
956 }
957
958 if (!modified)
959 return MX_STATUS_OK;
960
961 /* Update the modification times on the mailbox.
962 *
963 * The monitor code notices changes in the open mailbox too quickly.
964 * In practice, this sometimes leads to all the new messages not being
965 * noticed during the SAME group of mtime stat updates. To work around
966 * the problem, don't update the stat times for a monitor caused check. */
967#ifdef USE_INOTIFY
969 {
970 MonitorCurMboxChanged = false;
971 }
972 else
973#endif
974 {
977 }
978
979 struct MhEmailArray mha = ARRAY_HEAD_INITIALIZER;
980
981 mh_parse_dir(m, &mha, NULL);
982 mh_delayed_parsing(m, &mha, NULL);
983
984 if (mh_seq_read(&mhs, mailbox_path(m)) < 0)
985 return MX_STATUS_ERROR;
986 mh_update_emails(&mha, &mhs);
987 mh_seq_free(&mhs);
988
989 /* check for modifications and adjust flags */
990 fnames = mutt_hash_new(ARRAY_SIZE(&mha), MUTT_HASH_NONE);
991
992 struct MhEmail *md = NULL;
993 struct MhEmail **mdp = NULL;
994 ARRAY_FOREACH(mdp, &mha)
995 {
996 md = *mdp;
997 /* the hash key must survive past the header, which is freed below. */
999 mutt_hash_insert(fnames, md->canon_fname, md);
1000 }
1001
1002 for (int i = 0; i < m->msg_count; i++)
1003 {
1004 struct Email *e = m->emails[i];
1005 if (!e)
1006 break;
1007
1008 md = mutt_hash_find(fnames, e->path);
1009 if (md && md->email && email_cmp_strict(e, md->email))
1010 {
1011 /* found the right message */
1012 if (!e->changed)
1013 if (mh_update_flags(m, e, md->email))
1014 flags_changed = true;
1015
1016 email_free(&md->email);
1017 }
1018 else /* message has disappeared */
1019 {
1020 occult = true;
1021 }
1022 }
1023
1024 /* destroy the file name hash */
1025
1026 mutt_hash_free(&fnames);
1027
1028 /* If we didn't just get new mail, update the tables. */
1029 if (occult)
1031
1032 /* Incorporate new messages */
1033 num_new = mh_move_to_mailbox(m, &mha);
1034 mharray_clear(&mha);
1035
1036 if (num_new > 0)
1037 {
1039 m->changed = true;
1040 }
1041
1042 ARRAY_FREE(&mha);
1043 if (occult)
1044 return MX_STATUS_REOPENED;
1045 if (num_new > 0)
1046 return MX_STATUS_NEW_MAIL;
1047 if (flags_changed)
1048 return MX_STATUS_FLAGS;
1049 return MX_STATUS_OK;
1050}
1051
1055static enum MxStatus mh_mbox_check(struct Mailbox *m)
1056{
1057 return mh_check(m);
1058}
1059
1069static enum MxStatus mh_mbox_sync(struct Mailbox *m)
1070{
1071 enum MxStatus check = mh_check(m);
1072 if (check == MX_STATUS_ERROR)
1073 return check;
1074
1075 struct HeaderCache *hc = NULL;
1076#ifdef USE_HCACHE
1077 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
1078 hc = hcache_open(c_header_cache, mailbox_path(m), NULL, true);
1079#endif
1080
1081 struct Progress *progress = NULL;
1082 if (m->verbose)
1083 {
1085 progress_set_message(progress, _("Writing %s..."), mailbox_path(m));
1086 }
1087
1088 for (int i = 0; i < m->msg_count; i++)
1089 {
1090 progress_update(progress, i, -1);
1091
1092 struct Email *e = m->emails[i];
1093 if (mh_sync_mailbox_message(m, e, hc) == -1)
1094 {
1095 progress_free(&progress);
1096 goto err;
1097 }
1098 }
1099 progress_free(&progress);
1100
1101#ifdef USE_HCACHE
1102 hcache_close(&hc);
1103#endif
1104
1105 mh_seq_update(m);
1106
1107 /* XXX race condition? */
1108
1109 mh_update_mtime(m);
1110
1111 /* adjust indices */
1112
1113 if (m->msg_deleted)
1114 {
1115 for (int i = 0, j = 0; i < m->msg_count; i++)
1116 {
1117 struct Email *e = m->emails[i];
1118 if (!e)
1119 break;
1120
1121 if (!e->deleted)
1122 e->index = j++;
1123 }
1124 }
1125
1126 return check;
1127
1128err:
1129#ifdef USE_HCACHE
1130 hcache_close(&hc);
1131#endif
1132 return MX_STATUS_ERROR;
1133}
1134
1139static enum MxStatus mh_mbox_close(struct Mailbox *m)
1140{
1141 return MX_STATUS_OK;
1142}
1143
1147static bool mh_msg_open(struct Mailbox *m, struct Message *msg, struct Email *e)
1148{
1149 char path[PATH_MAX] = { 0 };
1150
1151 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
1152
1153 msg->fp = mutt_file_fopen(path, "r");
1154 if (!msg->fp)
1155 {
1156 mutt_perror("%s", path);
1157 return false;
1158 }
1159
1160 return true;
1161}
1162
1168static bool mh_msg_open_new(struct Mailbox *m, struct Message *msg, const struct Email *e)
1169{
1170 return mh_mkstemp(m, &msg->fp, &msg->path);
1171}
1172
1176static int mh_msg_commit(struct Mailbox *m, struct Message *msg)
1177{
1178 return mh_commit_msg(m, msg, NULL, true);
1179}
1180
1186static int mh_msg_close(struct Mailbox *m, struct Message *msg)
1187{
1188 return mutt_file_fclose(&msg->fp);
1189}
1190
1194static int mh_path_canon(struct Buffer *path)
1195{
1197 return 0;
1198}
1199
1203static enum MailboxType mh_path_probe(const char *path, const struct stat *st)
1204{
1205 if (!st || !S_ISDIR(st->st_mode))
1206 return MUTT_UNKNOWN;
1207
1208 char tmp[PATH_MAX] = { 0 };
1209
1210 snprintf(tmp, sizeof(tmp), "%s/.mh_sequences", path);
1211 if (access(tmp, F_OK) == 0)
1212 return MUTT_MH;
1213
1214 snprintf(tmp, sizeof(tmp), "%s/.xmhcache", path);
1215 if (access(tmp, F_OK) == 0)
1216 return MUTT_MH;
1217
1218 snprintf(tmp, sizeof(tmp), "%s/.mew_cache", path);
1219 if (access(tmp, F_OK) == 0)
1220 return MUTT_MH;
1221
1222 snprintf(tmp, sizeof(tmp), "%s/.mew-cache", path);
1223 if (access(tmp, F_OK) == 0)
1224 return MUTT_MH;
1225
1226 snprintf(tmp, sizeof(tmp), "%s/.sylpheed_cache", path);
1227 if (access(tmp, F_OK) == 0)
1228 return MUTT_MH;
1229
1230 /* ok, this isn't an mh folder, but mh mode can be used to read
1231 * Usenet news from the spool. */
1232
1233 snprintf(tmp, sizeof(tmp), "%s/.overview", path);
1234 if (access(tmp, F_OK) == 0)
1235 return MUTT_MH;
1236
1237 return MUTT_UNKNOWN;
1238}
1239
1243const struct MxOps MxMhOps = {
1244 // clang-format off
1245 .type = MUTT_MH,
1246 .name = "mh",
1247 .is_local = true,
1248 .ac_owns_path = mh_ac_owns_path,
1249 .ac_add = mh_ac_add,
1250 .mbox_open = mh_mbox_open,
1251 .mbox_open_append = mh_mbox_open_append,
1252 .mbox_check = mh_mbox_check,
1253 .mbox_check_stats = mh_mbox_check_stats,
1254 .mbox_sync = mh_mbox_sync,
1255 .mbox_close = mh_mbox_close,
1256 .msg_open = mh_msg_open,
1257 .msg_open_new = mh_msg_open_new,
1258 .msg_commit = mh_msg_commit,
1259 .msg_close = mh_msg_close,
1260 .msg_padding_size = NULL,
1261 .msg_save_hcache = mh_msg_save_hcache,
1262 .tags_edit = NULL,
1263 .tags_commit = NULL,
1264 .path_probe = mh_path_probe,
1265 .path_canon = mh_path_canon,
1266 .path_is_empty = mh_check_empty,
1267 // clang-format on
1268};
#define ARRAY_SORT(head, fn, sdata)
Sort an array.
Definition array.h:373
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
const char * mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition atoi.c:217
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition helpers.c:266
Convenience wrapper for the config headers.
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_email.c:920
@ MUTT_CM_UPDATE
Update structs on sync.
Definition copy_email.h:46
@ CH_UPDATE
Update the status and x-status fields?
Definition copy_email.h:66
@ CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition copy_email.h:76
Convenience wrapper for the core headers.
void mailbox_size_add(struct Mailbox *m, const struct Email *e)
Add an email's size to the total size of a Mailbox.
Definition mailbox.c:248
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition mailbox.c:232
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition mailbox.h:183
@ NT_MAILBOX_INVALID
Email list was changed.
Definition mailbox.h:182
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:216
MailboxType
Supported mailbox formats.
Definition mailbox.h:40
@ MUTT_MH
'MH' Mailbox type
Definition mailbox.h:46
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition mailbox.h:43
bool mutt_isdigit(int arg)
Wrapper for isdigit(3)
Definition ctype.c:66
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
bool email_cmp_strict(const struct Email *e1, const struct Email *e2)
Strictly compare message emails.
Definition email.c:96
struct Email * email_new(void)
Create a new Email.
Definition email.c:77
void email_free(struct Email **ptr)
Free an Email.
Definition email.c:46
Structs that make up an email.
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition parse.c:1325
EmailSortType
Methods for sorting Emails.
Definition sort.h:53
@ EMAIL_SORT_UNSORTED
Sort by the order the messages appear in the mailbox.
Definition sort.h:64
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:1475
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition file.c:310
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition file.c:844
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1433
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition file.c:535
int mutt_file_stat_timespec_compare(struct stat *st, enum MuttStatType type, struct timespec *b)
Compare stat info with a time value.
Definition file.c:1515
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition file.c:128
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition file.h:68
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition file.h:59
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition flags.c:54
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
void mh_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free() -.
Definition mdata.c:37
static bool mh_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Implements MxOps::ac_add() -.
Definition mh.c:813
static bool mh_ac_owns_path(struct Account *a, const char *path)
Check whether an Account owns a Mailbox path - Implements MxOps::ac_owns_path() -.
Definition mh.c:805
const struct MxOps MxMhOps
MH Mailbox - Implements MxOps -.
Definition mh.c:1243
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:140
static enum MxStatus mh_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition mh.c:1055
static enum MxStatus mh_mbox_close(struct Mailbox *m)
Close a Mailbox - Implements MxOps::mbox_close() -.
Definition mh.c:1139
static bool mh_mbox_open_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a Mailbox for appending - Implements MxOps::mbox_open_append() -.
Definition mh.c:829
static enum MxOpenReturns mh_mbox_open(struct Mailbox *m)
Open a Mailbox - Implements MxOps::mbox_open() -.
Definition mh.c:821
static enum MxStatus mh_mbox_sync(struct Mailbox *m)
Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
Definition mh.c:1069
static int mh_msg_close(struct Mailbox *m, struct Message *msg)
Close an email - Implements MxOps::msg_close() -.
Definition mh.c:1186
static int mh_msg_commit(struct Mailbox *m, struct Message *msg)
Save changes to an email - Implements MxOps::msg_commit() -.
Definition mh.c:1176
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:1168
static bool mh_msg_open(struct Mailbox *m, struct Message *msg, struct Email *e)
Open an email message in a Mailbox - Implements MxOps::msg_open() -.
Definition mh.c:1147
static 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:790
static int mh_path_canon(struct Buffer *path)
Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
Definition mh.c:1194
static enum MailboxType mh_path_probe(const char *path, const struct stat *st)
Is this an mh Mailbox?
Definition mh.c:1203
static int mh_sort_path(const void *a, const void *b, void *sdata)
Compare two Mh Mailboxes by path - Implements sort_t -.
Definition mh.c:500
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:338
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:365
struct HashTable * mutt_hash_new(size_t num_elems, HashFlags flags)
Create a new Hash Table (with string keys)
Definition hash.c:262
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition hash.c:460
@ MUTT_HASH_NONE
No flags are set.
Definition hash.h:115
struct HeaderCache * hcache_open(const char *path, const char *folder, hcache_namer_t namer, bool create)
Multiplexor for StoreOps::open.
Definition hcache.c:492
int hcache_delete_email(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition hcache.c:769
void hcache_close(struct HeaderCache **ptr)
Multiplexor for StoreOps::close.
Definition hcache.c:564
struct HCacheEntry hcache_fetch_email(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition hcache.c:584
int hcache_store_email(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition hcache.c:700
Header cache multiplexor.
@ LL_DEBUG3
Log at debug level 3.
Definition logging2.h:47
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
struct MhMboxData * mh_mdata_get(struct Mailbox *m)
Get the private data for this Mailbox.
Definition mdata.c:59
struct MhMboxData * mh_mdata_new(void)
Create a new MhMboxData object.
Definition mdata.c:49
Mh-specific Mailbox data.
bool mh_mkstemp(struct Mailbox *m, FILE **fp, char **tgt)
Create a temporary file.
Definition shared.c:73
mode_t mh_umask(struct Mailbox *m)
Create a umask from the mailbox directory.
Definition shared.c:49
MH shared functions.
static bool mh_update_flags(struct Mailbox *m, struct Email *e_old, struct Email *e_new)
Update the mailbox flags.
Definition mh.c:862
static void mh_update_mtime(struct Mailbox *m)
Update our record of the mailbox modification time.
Definition mh.c:422
int mh_check_empty(struct Buffer *path)
Is mailbox empty.
Definition mh.c:116
static bool mh_valid_message(const char *s)
Is this a valid MH message filename.
Definition mh.c:99
static int mh_parse_dir(struct Mailbox *m, struct MhEmailArray *mha, struct Progress *progress)
Read an Mh mailbox.
Definition mh.c:447
static int mh_sync_message(struct Mailbox *m, struct Email *e)
Sync an email to an MH folder.
Definition mh.c:403
static enum MxStatus mh_check(struct Mailbox *m)
Check for new mail.
Definition mh.c:913
int mh_sync_mailbox_message(struct Mailbox *m, struct Email *e, struct HeaderCache *hc)
Save changes to the mailbox.
Definition mh.c:732
static 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:243
static int mh_already_notified(struct Mailbox *m, int msgno)
Has the message changed.
Definition mh.c:77
static void mh_delayed_parsing(struct Mailbox *m, struct MhEmailArray *mha, struct Progress *progress)
This function does the second parsing pass.
Definition mh.c:553
static void mh_update_emails(struct MhEmailArray *mha, struct MhSequences *mhs)
Update our record of flags.
Definition mh.c:210
static bool mh_read_dir(struct Mailbox *m)
Read an MH mailbox.
Definition mh.c:667
static int mh_move_to_mailbox(struct Mailbox *m, const struct MhEmailArray *mha)
Copy the Mh list to the Mailbox.
Definition mh.c:624
static struct Email * mh_parse_message(const char *fname, struct Email *e)
Actually parse an MH message.
Definition mh.c:516
static int mh_rewrite_message(struct Mailbox *m, struct Email *e)
Sync a message in an MH folder.
Definition mh.c:329
struct MhEmail * mh_entry_new(void)
Create a new Mh entry.
Definition mhemail.c:39
void mharray_clear(struct MhEmailArray *mha)
Free a Mh array.
Definition mhemail.c:64
Mh Email helper.
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_path_canon(struct Buffer *path, const char *homedir, bool is_dir)
Create the canonical version of a path.
Definition path.c:248
int mutt_str_cmp(const char *a, const char *b)
Compare two strings, safely.
Definition string.c:403
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
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:587
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
Many unsorted constants and some structs.
@ MUTT_READ
Messages that have been read.
Definition mutt.h:92
@ MUTT_OLD
Old messages.
Definition mutt.h:90
@ MUTT_FLAG
Flagged messages.
Definition mutt.h:98
@ MUTT_REPLIED
Messages that have been replied to.
Definition mutt.h:91
#define PATH_MAX
Definition mutt.h:49
void mx_alloc_memory(struct Mailbox *m, int req_size)
Create storage for the emails.
Definition mx.c:1211
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1185
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition mx.c:1139
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition mx.c:1044
API for mailboxes.
@ MUTT_MSG_NONE
No flags are set.
Definition mx.h:42
uint8_t OpenMailboxFlags
Definition mxapi.h:51
@ MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn't exist.
Definition mxapi.h:48
MxOpenReturns
Return values for mbox_open()
Definition mxapi.h:83
@ MX_OPEN_ERROR
Open failed with an error.
Definition mxapi.h:85
@ MX_OPEN_OK
Open succeeded.
Definition mxapi.h:84
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition mxapi.h:70
@ MX_STATUS_ERROR
An error occurred.
Definition mxapi.h:71
@ MX_STATUS_OK
No changes.
Definition mxapi.h:72
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition mxapi.h:76
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition mxapi.h:75
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition mxapi.h:73
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
Progress Bar.
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition lib.h:84
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition lib.h:85
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition progress.c:139
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition progress.c:110
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition progress.c:80
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:110
MhSeqFlags mh_seq_check(struct MhSequences *mhs, int i)
Get the flags for a given sequence.
Definition sequence.c:79
void mh_seq_free(struct MhSequences *mhs)
Free some sequences.
Definition sequence.c:68
int mh_seq_changed(struct Mailbox *m)
Has the mailbox changed.
Definition sequence.c:443
void mh_seq_update(struct Mailbox *m)
Update sequence numbers.
Definition sequence.c:236
int mh_seq_read(struct MhSequences *mhs, const char *path)
Read a set of MH sequences.
Definition sequence.c:380
MH Mailbox Sequences.
@ MH_SEQ_UNSEEN
Email hasn't been read.
Definition sequence.h:37
@ MH_SEQ_FLAGGED
Email is flagged.
Definition sequence.h:39
@ MH_SEQ_REPLIED
Email has been replied to.
Definition sequence.h:38
uint8_t MhSeqFlags
Definition sequence.h:41
volatile sig_atomic_t SigInt
true after SIGINT is received
Definition signal.c:68
#define NONULL(x)
Definition string2.h:44
A group of associated Mailboxes.
Definition account.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
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
struct Envelope * env
Envelope information.
Definition email.h:68
int lines
How many lines in the body of this message?
Definition email.h:62
struct Body * body
List of MIME parts.
Definition email.h:69
bool old
Email is seen, but unread.
Definition email.h:49
bool changed
Email has been edited.
Definition email.h:77
bool attach_del
Has an attachment marked for deletion.
Definition email.h:99
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
time_t received
Time when the message was placed in the mailbox.
Definition email.h:61
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition envelope.h:90
Wrapper for Email retrieved from the header cache.
Definition lib.h:100
struct Email * email
Retrieved email.
Definition lib.h:103
A Hash Table.
Definition hash.h:99
Header Cache.
Definition lib.h:87
A mailbox.
Definition mailbox.h:81
void(* mdata_free)(void **ptr)
Definition mailbox.h:145
bool changed
Mailbox has been modified.
Definition mailbox.h:112
bool has_new
Mailbox has new mail.
Definition mailbox.h:87
int msg_count
Total number of messages.
Definition mailbox.h:90
void * mdata
Driver specific data.
Definition mailbox.h:134
struct Email ** emails
Array of Emails.
Definition mailbox.h:98
struct Buffer pathbuf
Path of the Mailbox.
Definition mailbox.h:82
int msg_deleted
Number of deleted messages.
Definition mailbox.h:95
int msg_flagged
Number of flagged messages.
Definition mailbox.h:92
struct timespec last_visited
Time of last exit from this mailbox.
Definition mailbox.h:106
bool verbose
Display status messages?
Definition mailbox.h:119
int msg_unread
Number of unread messages.
Definition mailbox.h:91
A local copy of an email.
Definition message.h:34
FILE * fp
pointer to the message data
Definition message.h:35
char * path
path to temp file
Definition message.h:36
struct Message::@264267271004327071125374067057142037276212342100 flags
Flags for the Message.
bool replied
Message has been replied to.
Definition message.h:43
char * committed_path
the final path generated by mx_msg_commit()
Definition message.h:37
bool flagged
Message is flagged.
Definition message.h:42
bool read
Message has been read.
Definition message.h:41
A Mh Email helper.
Definition mhemail.h:36
bool header_parsed
Has the Email header been parsed?
Definition mhemail.h:39
struct Email * email
Temporary Email.
Definition mhemail.h:37
char * canon_fname
Canonical filename for hashing.
Definition mhemail.h:38
Mh-specific Mailbox data -.
Definition mdata.h:35
mode_t umask
umask to use when creating files
Definition mdata.h:38
Set of MH sequence numbers.
Definition sequence.h:47
int max
Number of flags stored.
Definition sequence.h:48
Definition mxapi.h:98
Container for Accounts, Notifications.
Definition neomutt.h:41
char * home_dir
User's home directory.
Definition neomutt.h:55
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49