NeoMutt  2024-11-14-138-ge5ca67
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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 "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 "copy.h"
53#include "errno.h"
54#include "globals.h"
55#include "mdata.h"
56#include "mhemail.h"
57#include "mx.h"
58#include "protos.h"
59#include "sequence.h"
60#include "shared.h"
61#ifdef USE_INOTIFY
62#include "monitor.h"
63#endif
64#ifdef USE_HCACHE
65#include "hcache/lib.h"
66#else
67struct HeaderCache;
68#endif
69
70struct Progress;
71
80static int mh_already_notified(struct Mailbox *m, int msgno)
81{
82 char path[PATH_MAX] = { 0 };
83 struct stat st = { 0 };
84
85 if ((snprintf(path, sizeof(path), "%s/%d", mailbox_path(m), msgno) < sizeof(path)) &&
86 (stat(path, &st) == 0))
87 {
89 }
90 return -1;
91}
92
102static bool mh_valid_message(const char *s)
103{
104 for (; *s; s++)
105 {
106 if (!isdigit((unsigned char) *s))
107 return false;
108 }
109 return true;
110}
111
119int mh_check_empty(struct Buffer *path)
120{
121 struct dirent *de = NULL;
122 int rc = 1; /* assume empty until we find a message */
123
125 if (!dir)
126 return -1;
127 while ((de = readdir(dir)))
128 {
129 if (mh_valid_message(de->d_name))
130 {
131 rc = 0;
132 break;
133 }
134 }
135 closedir(dir);
136
137 return rc;
138}
139
143static enum MxStatus mh_mbox_check_stats(struct Mailbox *m, uint8_t flags)
144{
145 struct MhSequences mhs = { 0 };
146 DIR *dir = NULL;
147 struct dirent *de = NULL;
148
149 /* when $mail_check_recent is set and the .mh_sequences file hasn't changed
150 * since the last m visit, there is no "new mail" */
151 const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
152 if (c_mail_check_recent && (mh_seq_changed(m) <= 0))
153 {
154 return MX_STATUS_OK;
155 }
156
157 if (mh_seq_read(&mhs, mailbox_path(m)) < 0)
158 return MX_STATUS_ERROR;
159
160 m->msg_count = 0;
161 m->msg_unread = 0;
162 m->msg_flagged = 0;
163
164 enum MxStatus rc = MX_STATUS_OK;
165 bool check_new = true;
166 for (int i = mhs.max; i > 0; i--)
167 {
168 if ((mh_seq_check(&mhs, i) & MH_SEQ_FLAGGED))
169 m->msg_flagged++;
170 if (mh_seq_check(&mhs, i) & MH_SEQ_UNSEEN)
171 {
172 m->msg_unread++;
173 if (check_new)
174 {
175 /* if the first unseen message we encounter was in the m during the
176 * last visit, don't notify about it */
177 if (!c_mail_check_recent || (mh_already_notified(m, i) == 0))
178 {
179 m->has_new = true;
181 }
182 /* Because we are traversing from high to low, we can stop
183 * checking for new mail after the first unseen message.
184 * Whether it resulted in "new mail" or not. */
185 check_new = false;
186 }
187 }
188 }
189
190 mh_seq_free(&mhs);
191
193 if (dir)
194 {
195 while ((de = readdir(dir)))
196 {
197 if (*de->d_name == '.')
198 continue;
199 if (mh_valid_message(de->d_name))
200 m->msg_count++;
201 }
202 closedir(dir);
203 }
204
205 return rc;
206}
207
213static void mh_update_emails(struct MhEmailArray *mha, struct MhSequences *mhs)
214{
215 struct MhEmail *md = NULL;
216 struct MhEmail **mdp = NULL;
217 ARRAY_FOREACH(mdp, mha)
218 {
219 md = *mdp;
220 char *p = strrchr(md->email->path, '/');
221 if (p)
222 p++;
223 else
224 p = md->email->path;
225
226 int i = 0;
227 if (!mutt_str_atoi_full(p, &i))
228 continue;
229 MhSeqFlags flags = mh_seq_check(mhs, i);
230
231 md->email->read = !(flags & MH_SEQ_UNSEEN);
232 md->email->flagged = (flags & MH_SEQ_FLAGGED);
233 md->email->replied = (flags & MH_SEQ_REPLIED);
234 }
235}
236
246static int mh_commit_msg(struct Mailbox *m, struct Message *msg, struct Email *e, bool updseq)
247{
248 struct dirent *de = NULL;
249 char *cp = NULL, *dep = NULL;
250 unsigned int n, hi = 0;
251 char path[PATH_MAX] = { 0 };
252 char tmp[16] = { 0 };
253
254 if (mutt_file_fsync_close(&msg->fp))
255 {
256 mutt_perror(_("Could not flush message to disk"));
257 return -1;
258 }
259
261 if (!dir)
262 {
263 mutt_perror("%s", mailbox_path(m));
264 return -1;
265 }
266
267 /* figure out what the next message number is */
268 while ((de = readdir(dir)))
269 {
270 dep = de->d_name;
271 if (*dep == ',')
272 dep++;
273 cp = dep;
274 while (*cp)
275 {
276 if (!isdigit((unsigned char) *cp))
277 break;
278 cp++;
279 }
280 if (*cp == '\0')
281 {
282 if (!mutt_str_atoui(dep, &n))
283 mutt_debug(LL_DEBUG2, "Invalid MH message number '%s'\n", dep);
284 if (n > hi)
285 hi = n;
286 }
287 }
288 closedir(dir);
289
290 /* Now try to rename the file to the proper name.
291 * Note: We may have to try multiple times, until we find a free slot. */
292
293 while (true)
294 {
295 hi++;
296 snprintf(tmp, sizeof(tmp), "%u", hi);
297 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), tmp);
298 if (mutt_file_safe_rename(msg->path, path) == 0)
299 {
300 if (e)
301 mutt_str_replace(&e->path, tmp);
302 mutt_str_replace(&msg->committed_path, path);
303 FREE(&msg->path);
304 break;
305 }
306 else if (errno != EEXIST)
307 {
308 mutt_perror("%s", mailbox_path(m));
309 return -1;
310 }
311 }
312 if (updseq)
313 {
314 mh_seq_add_one(m, hi, !msg->flags.read, msg->flags.flagged, msg->flags.replied);
315 }
316 return 0;
317}
318
326static int mh_rewrite_message(struct Mailbox *m, struct Email *e)
327{
328 if (!m || !e)
329 return -1;
330
331 bool restore = true;
332
333 long old_body_offset = e->body->offset;
334 long old_body_length = e->body->length;
335 long old_hdr_lines = e->lines;
336
337 struct Message *src = mx_msg_open(m, e);
338 struct Message *dest = mx_msg_open_new(m, e, MUTT_MSG_NO_FLAGS);
339 if (!src || !dest)
340 return -1;
341
342 int rc = mutt_copy_message(dest->fp, e, src, MUTT_CM_UPDATE, CH_UPDATE | CH_UPDATE_LEN, 0);
343 if (rc == 0)
344 {
345 char oldpath[PATH_MAX] = { 0 };
346 char partpath[PATH_MAX] = { 0 };
347 snprintf(oldpath, sizeof(oldpath), "%s/%s", mailbox_path(m), e->path);
348 mutt_str_copy(partpath, e->path, sizeof(partpath));
349
350 rc = mh_commit_msg(m, dest, e, false);
351
352 if (rc == 0)
353 {
354 unlink(oldpath);
355 restore = false;
356 }
357
358 /* Try to move the new message to the old place.
359 * (MH only.)
360 *
361 * This is important when we are just updating flags.
362 *
363 * Note that there is a race condition against programs which
364 * use the first free slot instead of the maximum message
365 * number. NeoMutt does _not_ behave like this.
366 *
367 * Anyway, if this fails, the message is in the folder, so
368 * all what happens is that a concurrently running neomutt will
369 * lose flag modifications. */
370 if (rc == 0)
371 {
372 char newpath[PATH_MAX] = { 0 };
373 snprintf(newpath, sizeof(newpath), "%s/%s", mailbox_path(m), e->path);
374 rc = mutt_file_safe_rename(newpath, oldpath);
375 if (rc == 0)
376 mutt_str_replace(&e->path, partpath);
377 }
378 }
379 mx_msg_close(m, &src);
380 mx_msg_close(m, &dest);
381
382 if ((rc == -1) && restore)
383 {
384 e->body->offset = old_body_offset;
385 e->body->length = old_body_length;
386 e->lines = old_hdr_lines;
387 }
388
390 return rc;
391}
392
400static int mh_sync_message(struct Mailbox *m, struct Email *e)
401{
402 if (!m || !e)
403 return -1;
404
405 if (e->attach_del || e->env->changed)
406 {
407 if (mh_rewrite_message(m, e) != 0)
408 return -1;
409 e->env->changed = false;
410 }
411
412 return 0;
413}
414
419static void mh_update_mtime(struct Mailbox *m)
420{
421 char buf[PATH_MAX] = { 0 };
422 struct stat st = { 0 };
423 struct MhMboxData *mdata = mh_mdata_get(m);
424
425 snprintf(buf, sizeof(buf), "%s/.mh_sequences", mailbox_path(m));
426 if (stat(buf, &st) == 0)
428
429 mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
430
431 if (stat(buf, &st) == 0)
433}
434
444static int mh_parse_dir(struct Mailbox *m, struct MhEmailArray *mha, struct Progress *progress)
445{
446 struct dirent *de = NULL;
447 int rc = 0;
448 struct MhEmail *entry = NULL;
449 struct Email *e = NULL;
450
451 struct Buffer *buf = buf_pool_get();
452 buf_strcpy(buf, mailbox_path(m));
453
455 if (!dir)
456 {
457 rc = -1;
458 goto cleanup;
459 }
460
461 while (((de = readdir(dir))) && !SigInt)
462 {
463 if (!mh_valid_message(de->d_name))
464 continue;
465
466 mutt_debug(LL_DEBUG2, "queueing %s\n", de->d_name);
467
468 e = email_new();
469
470 progress_update(progress, ARRAY_SIZE(mha) + 1, -1);
471
472 e->path = mutt_str_dup(de->d_name);
473
474 entry = mh_entry_new();
475 entry->email = e;
476 ARRAY_ADD(mha, entry);
477 }
478
479 closedir(dir);
480
481 if (SigInt)
482 {
483 SigInt = false;
484 return -2; /* action aborted */
485 }
486
487cleanup:
488 buf_pool_release(&buf);
489
490 return rc;
491}
492
496static int mh_sort_path(const void *a, const void *b, void *sdata)
497{
498 struct MhEmail const *pa = *(struct MhEmail const *const *) a;
499 struct MhEmail const *pb = *(struct MhEmail const *const *) b;
500 return mutt_str_cmp(pa->email->path, pb->email->path);
501}
502
512static struct Email *mh_parse_message(const char *fname, struct Email *e)
513{
514 FILE *fp = mutt_file_fopen(fname, "r");
515 if (!fp)
516 {
517 return NULL;
518 }
519
520 const long size = mutt_file_get_size_fp(fp);
521 if (size == 0)
522 {
523 mutt_file_fclose(&fp);
524 return NULL;
525 }
526
527 if (!e)
528 e = email_new();
529
530 e->env = mutt_rfc822_read_header(fp, e, false, false);
531
532 if (e->received != 0)
533 e->received = e->date_sent;
534
535 /* always update the length since we have fresh information available. */
536 e->body->length = size - e->body->offset;
537 e->index = -1;
538
539 mutt_file_fclose(&fp);
540 return e;
541}
542
549static void mh_delayed_parsing(struct Mailbox *m, struct MhEmailArray *mha,
550 struct Progress *progress)
551{
552 char fn[PATH_MAX] = { 0 };
553
554#ifdef USE_HCACHE
555 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
556 struct HeaderCache *hc = hcache_open(c_header_cache, mailbox_path(m), NULL, true);
557#endif
558
559 struct MhEmail *md = NULL;
560 struct MhEmail **mdp = NULL;
561 ARRAY_FOREACH(mdp, mha)
562 {
563 md = *mdp;
564 if (!md || !md->email || md->header_parsed)
565 continue;
566
567 progress_update(progress, ARRAY_FOREACH_IDX, -1);
568
569#ifdef USE_HCACHE
570 const char *key = md->email->path;
571 size_t keylen = strlen(key);
572 struct HCacheEntry hce = hcache_fetch_email(hc, key, keylen, 0);
573
574 if (hce.email)
575 {
576 hce.email->old = md->email->old;
577 hce.email->path = mutt_str_dup(md->email->path);
578 email_free(&md->email);
579 md->email = hce.email;
580 }
581 else
582#endif
583 {
584 snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
585
586 if (mh_parse_message(fn, md->email))
587 {
588 md->header_parsed = true;
589#ifdef USE_HCACHE
590 key = md->email->path;
591 keylen = strlen(key);
592 hcache_store_email(hc, key, keylen, md->email, 0);
593#endif
594 }
595 else
596 {
597 email_free(&md->email);
598 }
599 }
600 }
601#ifdef USE_HCACHE
602 hcache_close(&hc);
603#endif
604
605 const enum EmailSortType c_sort = cs_subset_sort(NeoMutt->sub, "sort");
606 if (m && mha && (ARRAY_SIZE(mha) > 0) && (c_sort == EMAIL_SORT_UNSORTED))
607 {
608 mutt_debug(LL_DEBUG3, "mh: sorting %s into natural order\n", mailbox_path(m));
609 ARRAY_SORT(mha, mh_sort_path, NULL);
610 }
611}
612
620static int mh_move_to_mailbox(struct Mailbox *m, const struct MhEmailArray *mha)
621{
622 if (!m)
623 return 0;
624
625 int oldmsgcount = m->msg_count;
626
627 struct MhEmail *md = NULL;
628 struct MhEmail **mdp = NULL;
629 ARRAY_FOREACH(mdp, mha)
630 {
631 md = *mdp;
632 mutt_debug(LL_DEBUG2, "Considering %s\n", NONULL(md->canon_fname));
633 if (!md->email)
634 continue;
635
636 mutt_debug(LL_DEBUG2, "Adding header structure. Flags: %s%s%s%s%s\n",
637 md->email->flagged ? "f" : "", md->email->deleted ? "D" : "",
638 md->email->replied ? "r" : "", md->email->old ? "O" : "",
639 md->email->read ? "R" : "");
641
642 m->emails[m->msg_count] = md->email;
643 m->emails[m->msg_count]->index = m->msg_count;
644 mailbox_size_add(m, md->email);
645
646 md->email = NULL;
647 m->msg_count++;
648 }
649
650 int num = 0;
651 if (m->msg_count > oldmsgcount)
652 num = m->msg_count - oldmsgcount;
653
654 return num;
655}
656
663static bool mh_read_dir(struct Mailbox *m)
664{
665 if (!m)
666 return false;
667
668 mutt_path_tidy(&m->pathbuf, true);
669
670 struct MhSequences mhs = { 0 };
671 struct Progress *progress = NULL;
672
673 if (m->verbose)
674 {
675 progress = progress_new(MUTT_PROGRESS_READ, 0);
676 progress_set_message(progress, _("Scanning %s..."), mailbox_path(m));
677 }
678
679 struct MhMboxData *mdata = mh_mdata_get(m);
680 if (!mdata)
681 {
683 m->mdata = mdata;
685 }
686
688
689 struct MhEmailArray mha = ARRAY_HEAD_INITIALIZER;
690 int rc = mh_parse_dir(m, &mha, progress);
691 progress_free(&progress);
692 if (rc < 0)
693 return false;
694
695 if (m->verbose)
696 {
697 progress = progress_new(MUTT_PROGRESS_READ, ARRAY_SIZE(&mha));
698 progress_set_message(progress, _("Reading %s..."), mailbox_path(m));
699 }
700 mh_delayed_parsing(m, &mha, progress);
701 progress_free(&progress);
702
703 if (mh_seq_read(&mhs, mailbox_path(m)) < 0)
704 {
705 mharray_clear(&mha);
706 return false;
707 }
708 mh_update_emails(&mha, &mhs);
709 mh_seq_free(&mhs);
710
711 mh_move_to_mailbox(m, &mha);
712 mharray_clear(&mha);
713
714 if (!mdata->umask)
715 mdata->umask = mh_umask(m);
716
717 return true;
718}
719
728int mh_sync_mailbox_message(struct Mailbox *m, struct Email *e, struct HeaderCache *hc)
729{
730 if (!m || !e)
731 return -1;
732
733 if (e->deleted)
734 {
735 char path[PATH_MAX] = { 0 };
736 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
737 const bool c_mh_purge = cs_subset_bool(NeoMutt->sub, "mh_purge");
738 if (c_mh_purge)
739 {
740#ifdef USE_HCACHE
741 if (hc)
742 {
743 const char *key = e->path;
744 size_t keylen = strlen(key);
745 hcache_delete_email(hc, key, keylen);
746 }
747#endif
748 unlink(path);
749 }
750 else
751 {
752 /* MH just moves files out of the way when you delete them */
753 if (*e->path != ',')
754 {
755 char tmp[PATH_MAX] = { 0 };
756 snprintf(tmp, sizeof(tmp), "%s/,%s", mailbox_path(m), e->path);
757 unlink(tmp);
758 if (rename(path, tmp) != 0)
759 {
760 return -1;
761 }
762 }
763 }
764 }
765 else if (e->changed || e->attach_del)
766 {
767 if (mh_sync_message(m, e) == -1)
768 return -1;
769 }
770
771#ifdef USE_HCACHE
772 if (hc && e->changed)
773 {
774 const char *key = e->path;
775 size_t keylen = strlen(key);
776 hcache_store_email(hc, key, keylen, e, 0);
777 }
778#endif
779
780 return 0;
781}
782
786static int mh_msg_save_hcache(struct Mailbox *m, struct Email *e)
787{
788 int rc = 0;
789#ifdef USE_HCACHE
790 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
791 struct HeaderCache *hc = hcache_open(c_header_cache, mailbox_path(m), NULL, true);
792 rc = hcache_store_email(hc, e->path, strlen(e->path), e, 0);
793 hcache_close(&hc);
794#endif
795 return rc;
796}
797
801static bool mh_ac_owns_path(struct Account *a, const char *path)
802{
803 return true;
804}
805
809static bool mh_ac_add(struct Account *a, struct Mailbox *m)
810{
811 return true;
812}
813
817static enum MxOpenReturns mh_mbox_open(struct Mailbox *m)
818{
820}
821
825static bool mh_mbox_open_append(struct Mailbox *m, OpenMailboxFlags flags)
826{
827 if (!(flags & (MUTT_APPENDNEW | MUTT_NEWFOLDER)))
828 return true;
829
830 if (mutt_file_mkdir(mailbox_path(m), S_IRWXU))
831 {
832 mutt_perror("%s", mailbox_path(m));
833 return false;
834 }
835
836 char tmp[PATH_MAX] = { 0 };
837 snprintf(tmp, sizeof(tmp), "%s/.mh_sequences", mailbox_path(m));
838 const int i = creat(tmp, S_IRWXU);
839 if (i == -1)
840 {
841 mutt_perror("%s", tmp);
842 rmdir(mailbox_path(m));
843 return false;
844 }
845 close(i);
846
847 return true;
848}
849
858static bool mh_update_flags(struct Mailbox *m, struct Email *e_old, struct Email *e_new)
859{
860 if (!m)
861 return false;
862
863 /* save the global state here so we can reset it at the
864 * end of list block if required. */
865 bool context_changed = m->changed;
866
867 /* user didn't modify this message. alter the flags to match the
868 * current state on disk. This may not actually do
869 * anything. mutt_set_flag() will just ignore the call if the status
870 * bits are already properly set, but it is still faster not to pass
871 * through it */
872 if (e_old->flagged != e_new->flagged)
873 mutt_set_flag(m, e_old, MUTT_FLAG, e_new->flagged, true);
874 if (e_old->replied != e_new->replied)
875 mutt_set_flag(m, e_old, MUTT_REPLIED, e_new->replied, true);
876 if (e_old->read != e_new->read)
877 mutt_set_flag(m, e_old, MUTT_READ, e_new->read, true);
878 if (e_old->old != e_new->old)
879 mutt_set_flag(m, e_old, MUTT_OLD, e_new->old, true);
880
881 /* mutt_set_flag() will set this, but we don't need to
882 * sync the changes we made because we just updated the
883 * context to match the current on-disk state of the
884 * message. */
885 bool header_changed = e_old->changed;
886 e_old->changed = false;
887
888 /* if the mailbox was not modified before we made these
889 * changes, unset the changed flag since nothing needs to
890 * be synchronized. */
891 if (!context_changed)
892 m->changed = false;
893
894 return header_changed;
895}
896
909static enum MxStatus mh_check(struct Mailbox *m)
910{
911 char buf[PATH_MAX] = { 0 };
912 struct stat st = { 0 };
913 struct stat st_cur = { 0 };
914 bool modified = false, occult = false, flags_changed = false;
915 int num_new = 0;
916 struct MhSequences mhs = { 0 };
917 struct HashTable *fnames = NULL;
918 struct MhMboxData *mdata = mh_mdata_get(m);
919
920 const bool c_check_new = cs_subset_bool(NeoMutt->sub, "check_new");
921 if (!c_check_new)
922 return MX_STATUS_OK;
923
924 mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
925 if (stat(buf, &st) == -1)
926 return MX_STATUS_ERROR;
927
928 /* create .mh_sequences when there isn't one. */
929 snprintf(buf, sizeof(buf), "%s/.mh_sequences", mailbox_path(m));
930 int rc = stat(buf, &st_cur);
931 if ((rc == -1) && (errno == ENOENT))
932 {
933 char *tmp = NULL;
934 FILE *fp = NULL;
935
936 if (mh_mkstemp(m, &fp, &tmp))
937 {
938 mutt_file_fclose(&fp);
939 if (mutt_file_safe_rename(tmp, buf) == -1)
940 unlink(tmp);
941 FREE(&tmp);
942 }
943 }
944
945 if ((rc == -1) && (stat(buf, &st_cur) == -1))
946 modified = true;
947
948 if ((mutt_file_stat_timespec_compare(&st, MUTT_STAT_MTIME, &mdata->mtime) > 0) ||
949 (mutt_file_stat_timespec_compare(&st_cur, MUTT_STAT_MTIME, &mdata->mtime_seq) > 0))
950 {
951 modified = true;
952 }
953
954 if (!modified)
955 return MX_STATUS_OK;
956
957 /* Update the modification times on the mailbox.
958 *
959 * The monitor code notices changes in the open mailbox too quickly.
960 * In practice, this sometimes leads to all the new messages not being
961 * noticed during the SAME group of mtime stat updates. To work around
962 * the problem, don't update the stat times for a monitor caused check. */
963#ifdef USE_INOTIFY
965 {
966 MonitorCurMboxChanged = false;
967 }
968 else
969#endif
970 {
973 }
974
975 struct MhEmailArray mha = ARRAY_HEAD_INITIALIZER;
976
977 mh_parse_dir(m, &mha, NULL);
978 mh_delayed_parsing(m, &mha, NULL);
979
980 if (mh_seq_read(&mhs, mailbox_path(m)) < 0)
981 return MX_STATUS_ERROR;
982 mh_update_emails(&mha, &mhs);
983 mh_seq_free(&mhs);
984
985 /* check for modifications and adjust flags */
987
988 struct MhEmail *md = NULL;
989 struct MhEmail **mdp = NULL;
990 ARRAY_FOREACH(mdp, &mha)
991 {
992 md = *mdp;
993 /* the hash key must survive past the header, which is freed below. */
995 mutt_hash_insert(fnames, md->canon_fname, md);
996 }
997
998 for (int i = 0; i < m->msg_count; i++)
999 {
1000 struct Email *e = m->emails[i];
1001 if (!e)
1002 break;
1003
1004 md = mutt_hash_find(fnames, e->path);
1005 if (md && md->email && email_cmp_strict(e, md->email))
1006 {
1007 /* found the right message */
1008 if (!e->changed)
1009 if (mh_update_flags(m, e, md->email))
1010 flags_changed = true;
1011
1012 email_free(&md->email);
1013 }
1014 else /* message has disappeared */
1015 {
1016 occult = true;
1017 }
1018 }
1019
1020 /* destroy the file name hash */
1021
1022 mutt_hash_free(&fnames);
1023
1024 /* If we didn't just get new mail, update the tables. */
1025 if (occult)
1027
1028 /* Incorporate new messages */
1029 num_new = mh_move_to_mailbox(m, &mha);
1030 mharray_clear(&mha);
1031
1032 if (num_new > 0)
1033 {
1035 m->changed = true;
1036 }
1037
1038 ARRAY_FREE(&mha);
1039 if (occult)
1040 return MX_STATUS_REOPENED;
1041 if (num_new > 0)
1042 return MX_STATUS_NEW_MAIL;
1043 if (flags_changed)
1044 return MX_STATUS_FLAGS;
1045 return MX_STATUS_OK;
1046}
1047
1051static enum MxStatus mh_mbox_check(struct Mailbox *m)
1052{
1053 return mh_check(m);
1054}
1055
1065static enum MxStatus mh_mbox_sync(struct Mailbox *m)
1066{
1067 enum MxStatus check = mh_check(m);
1068 if (check == MX_STATUS_ERROR)
1069 return check;
1070
1071 struct HeaderCache *hc = NULL;
1072#ifdef USE_HCACHE
1073 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
1074 hc = hcache_open(c_header_cache, mailbox_path(m), NULL, true);
1075#endif
1076
1077 struct Progress *progress = NULL;
1078 if (m->verbose)
1079 {
1081 progress_set_message(progress, _("Writing %s..."), mailbox_path(m));
1082 }
1083
1084 for (int i = 0; i < m->msg_count; i++)
1085 {
1086 progress_update(progress, i, -1);
1087
1088 struct Email *e = m->emails[i];
1089 if (mh_sync_mailbox_message(m, e, hc) == -1)
1090 {
1091 progress_free(&progress);
1092 goto err;
1093 }
1094 }
1095 progress_free(&progress);
1096
1097#ifdef USE_HCACHE
1098 hcache_close(&hc);
1099#endif
1100
1101 mh_seq_update(m);
1102
1103 /* XXX race condition? */
1104
1105 mh_update_mtime(m);
1106
1107 /* adjust indices */
1108
1109 if (m->msg_deleted)
1110 {
1111 for (int i = 0, j = 0; i < m->msg_count; i++)
1112 {
1113 struct Email *e = m->emails[i];
1114 if (!e)
1115 break;
1116
1117 if (!e->deleted)
1118 e->index = j++;
1119 }
1120 }
1121
1122 return check;
1123
1124err:
1125#ifdef USE_HCACHE
1126 hcache_close(&hc);
1127#endif
1128 return MX_STATUS_ERROR;
1129}
1130
1135static enum MxStatus mh_mbox_close(struct Mailbox *m)
1136{
1137 return MX_STATUS_OK;
1138}
1139
1143static bool mh_msg_open(struct Mailbox *m, struct Message *msg, struct Email *e)
1144{
1145 char path[PATH_MAX] = { 0 };
1146
1147 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
1148
1149 msg->fp = mutt_file_fopen(path, "r");
1150 if (!msg->fp)
1151 {
1152 mutt_perror("%s", path);
1153 return false;
1154 }
1155
1156 return true;
1157}
1158
1164static bool mh_msg_open_new(struct Mailbox *m, struct Message *msg, const struct Email *e)
1165{
1166 return mh_mkstemp(m, &msg->fp, &msg->path);
1167}
1168
1172static int mh_msg_commit(struct Mailbox *m, struct Message *msg)
1173{
1174 return mh_commit_msg(m, msg, NULL, true);
1175}
1176
1182static int mh_msg_close(struct Mailbox *m, struct Message *msg)
1183{
1184 return mutt_file_fclose(&msg->fp);
1185}
1186
1190static int mh_path_canon(struct Buffer *path)
1191{
1193 return 0;
1194}
1195
1199static enum MailboxType mh_path_probe(const char *path, const struct stat *st)
1200{
1201 if (!st || !S_ISDIR(st->st_mode))
1202 return MUTT_UNKNOWN;
1203
1204 char tmp[PATH_MAX] = { 0 };
1205
1206 snprintf(tmp, sizeof(tmp), "%s/.mh_sequences", path);
1207 if (access(tmp, F_OK) == 0)
1208 return MUTT_MH;
1209
1210 snprintf(tmp, sizeof(tmp), "%s/.xmhcache", path);
1211 if (access(tmp, F_OK) == 0)
1212 return MUTT_MH;
1213
1214 snprintf(tmp, sizeof(tmp), "%s/.mew_cache", 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/.sylpheed_cache", path);
1223 if (access(tmp, F_OK) == 0)
1224 return MUTT_MH;
1225
1226 /* ok, this isn't an mh folder, but mh mode can be used to read
1227 * Usenet news from the spool. */
1228
1229 snprintf(tmp, sizeof(tmp), "%s/.overview", path);
1230 if (access(tmp, F_OK) == 0)
1231 return MUTT_MH;
1232
1233 return MUTT_UNKNOWN;
1234}
1235
1239const struct MxOps MxMhOps = {
1240 // clang-format off
1241 .type = MUTT_MH,
1242 .name = "mh",
1243 .is_local = true,
1244 .ac_owns_path = mh_ac_owns_path,
1245 .ac_add = mh_ac_add,
1246 .mbox_open = mh_mbox_open,
1247 .mbox_open_append = mh_mbox_open_append,
1248 .mbox_check = mh_mbox_check,
1249 .mbox_check_stats = mh_mbox_check_stats,
1250 .mbox_sync = mh_mbox_sync,
1251 .mbox_close = mh_mbox_close,
1252 .msg_open = mh_msg_open,
1253 .msg_open_new = mh_msg_open_new,
1254 .msg_commit = mh_msg_commit,
1255 .msg_close = mh_msg_close,
1256 .msg_padding_size = NULL,
1257 .msg_save_hcache = mh_msg_save_hcache,
1258 .tags_edit = NULL,
1259 .tags_commit = NULL,
1260 .path_probe = mh_path_probe,
1261 .path_canon = mh_path_canon,
1262 .path_is_empty = mh_check_empty,
1263 // clang-format on
1264};
#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
const char * mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: atoi.c:218
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
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.
char * HomeDir
User's home directory.
Definition: globals.c:37
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:906
Duplicate the structure of an entire email.
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:42
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:54
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:64
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:249
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:233
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:190
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:189
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:223
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 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:1205
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:1579
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:371
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:974
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1537
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:642
int mutt_file_stat_timespec_compare(struct stat *st, enum MuttStatType type, struct timespec *b)
Compare stat info with a time value.
Definition: file.c:1619
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:193
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:63
#define mutt_file_fclose(FP)
Definition: file.h:138
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:137
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:54
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:57
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
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:809
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:801
const struct MxOps MxMhOps
MH Mailbox - Implements MxOps -.
Definition: mh.c:1239
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:143
static enum MxStatus mh_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition: mh.c:1051
static enum MxStatus mh_mbox_close(struct Mailbox *m)
Close a Mailbox - Implements MxOps::mbox_close() -.
Definition: mh.c:1135
static bool mh_mbox_open_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a Mailbox for appending - Implements MxOps::mbox_open_append() -.
Definition: mh.c:825
static enum MxOpenReturns mh_mbox_open(struct Mailbox *m)
Open a Mailbox - Implements MxOps::mbox_open() -.
Definition: mh.c:817
static enum MxStatus mh_mbox_sync(struct Mailbox *m)
Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
Definition: mh.c:1065
static int mh_msg_close(struct Mailbox *m, struct Message *msg)
Close an email - Implements MxOps::msg_close() -.
Definition: mh.c:1182
static int mh_msg_commit(struct Mailbox *m, struct Message *msg)
Save changes to an email - Implements MxOps::msg_commit() -.
Definition: mh.c:1172
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:1164
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:1143
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:786
static int mh_path_canon(struct Buffer *path)
Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
Definition: mh.c:1190
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:1199
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:496
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
struct HeaderCache * hcache_open(const char *path, const char *folder, hcache_namer_t namer, bool create)
Multiplexor for StoreOps::open.
Definition: hcache.c:471
int hcache_delete_email(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:739
void hcache_close(struct HeaderCache **ptr)
Multiplexor for StoreOps::close.
Definition: hcache.c:542
struct HCacheEntry hcache_fetch_email(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:562
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:670
Header cache multiplexor.
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
#define FREE(x)
Definition: memory.h:55
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
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:858
static void mh_update_mtime(struct Mailbox *m)
Update our record of the mailbox modification time.
Definition: mh.c:419
int mh_check_empty(struct Buffer *path)
Is mailbox empty.
Definition: mh.c:119
static bool mh_valid_message(const char *s)
Is this a valid MH message filename.
Definition: mh.c:102
static int mh_parse_dir(struct Mailbox *m, struct MhEmailArray *mha, struct Progress *progress)
Read an Mh mailbox.
Definition: mh.c:444
static int mh_sync_message(struct Mailbox *m, struct Email *e)
Sync an email to an MH folder.
Definition: mh.c:400
static enum MxStatus mh_check(struct Mailbox *m)
Check for new mail.
Definition: mh.c:909
int mh_sync_mailbox_message(struct Mailbox *m, struct Email *e, struct HeaderCache *hc)
Save changes to the mailbox.
Definition: mh.c:728
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:246
static int mh_already_notified(struct Mailbox *m, int msgno)
Has the message changed.
Definition: mh.c:80
static void mh_delayed_parsing(struct Mailbox *m, struct MhEmailArray *mha, struct Progress *progress)
This function does the second parsing pass.
Definition: mh.c:549
static void mh_update_emails(struct MhEmailArray *mha, struct MhSequences *mhs)
Update our record of flags.
Definition: mh.c:213
static bool mh_read_dir(struct Mailbox *m)
Read an MH mailbox.
Definition: mh.c:663
static int mh_move_to_mailbox(struct Mailbox *m, const struct MhEmailArray *mha)
Copy the Mh list to the Mailbox.
Definition: mh.c:620
static struct Email * mh_parse_message(const char *fname, struct Email *e)
Actually parse an MH message.
Definition: mh.c:512
static int mh_rewrite_message(struct Mailbox *m, struct Email *e)
Sync a message in an MH folder.
Definition: mh.c:326
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:399
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
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:581
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:280
Many unsorted constants and some structs.
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:73
@ MUTT_OLD
Old messages.
Definition: mutt.h:71
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:79
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:72
#define PATH_MAX
Definition: mutt.h:42
void mx_alloc_memory(struct Mailbox *m, int req_size)
Create storage for the emails.
Definition: mx.c:1206
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1180
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1134
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1040
API for mailboxes.
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:38
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
MxOpenReturns
Return values for mbox_open()
Definition: mxapi.h:76
@ MX_OPEN_ERROR
Open failed with an error.
Definition: mxapi.h:78
@ MX_OPEN_OK
Open succeeded.
Definition: mxapi.h:77
#define MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn't exist.
Definition: mxapi.h:49
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition: mxapi.h:63
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:64
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:65
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition: mxapi.h:69
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:68
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:66
Notmuch-specific Mailbox data.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
Progress Bar.
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: lib.h:83
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition: lib.h:84
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:139
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:110
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:80
Prototypes for many functions.
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:108
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:439
void mh_seq_update(struct Mailbox *m)
Update sequence numbers.
Definition: sequence.c:234
int mh_seq_read(struct MhSequences *mhs, const char *path)
Read a set of MH sequences.
Definition: sequence.c:378
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
volatile sig_atomic_t SigInt
true after SIGINT is received
Definition: signal.c:66
#define NONULL(x)
Definition: string2.h:37
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:99
struct Email * email
Retrieved email.
Definition: lib.h:102
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_count
Total number of messages.
Definition: mailbox.h:88
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
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
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
struct Message::@0 flags
Flags for the Message.
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:41
int max
Number of flags stored.
Definition: sequence.h:42
Definition: mxapi.h:91
enum MailboxType type
Mailbox type, e.g. MUTT_IMAP.
Definition: mxapi.h:92
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46