NeoMutt  2021-02-05-89-gabe350
Teaching an old dog new tricks
DOXYGEN
mh.c
Go to the documentation of this file.
1 
32 #include "config.h"
33 #include <ctype.h>
34 #include <dirent.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <inttypes.h>
38 #include <limits.h>
39 #include <stdbool.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <sys/stat.h>
43 #include <unistd.h>
44 #include "private.h"
45 #include "mutt/lib.h"
46 #include "config/lib.h"
47 #include "email/lib.h"
48 #include "core/lib.h"
49 #include "maildir/lib.h"
50 #include "copy.h"
51 #include "edata.h"
52 #include "errno.h"
53 #include "mdata.h"
54 #include "mdemail.h"
55 #include "monitor.h"
56 #include "mutt_globals.h"
57 #include "mx.h"
58 #include "progress.h"
59 #include "sequence.h"
60 #include "sort.h"
61 #ifdef USE_HCACHE
62 #include "hcache/lib.h"
63 #endif
64 
73 bool mh_mkstemp(struct Mailbox *m, FILE **fp, char **tgt)
74 {
75  int fd;
76  char path[PATH_MAX];
77 
78  mode_t omask = umask(mh_umask(m));
79  while (true)
80  {
81  snprintf(path, sizeof(path), "%s/.neomutt-%s-%d-%" PRIu64, mailbox_path(m),
82  NONULL(ShortHostname), (int) getpid(), mutt_rand64());
83  fd = open(path, O_WRONLY | O_EXCL | O_CREAT, 0666);
84  if (fd == -1)
85  {
86  if (errno != EEXIST)
87  {
88  mutt_perror(path);
89  umask(omask);
90  return false;
91  }
92  }
93  else
94  {
95  *tgt = mutt_str_dup(path);
96  break;
97  }
98  }
99  umask(omask);
100 
101  *fp = fdopen(fd, "w");
102  if (!*fp)
103  {
104  FREE(tgt);
105  close(fd);
106  unlink(path);
107  return false;
108  }
109 
110  return true;
111 }
112 
121 static int mh_already_notified(struct Mailbox *m, int msgno)
122 {
123  char path[PATH_MAX];
124  struct stat sb;
125 
126  if ((snprintf(path, sizeof(path), "%s/%d", mailbox_path(m), msgno) < sizeof(path)) &&
127  (stat(path, &sb) == 0))
128  {
130  }
131  return -1;
132 }
133 
144 bool mh_valid_message(const char *s)
145 {
146  for (; *s; s++)
147  {
148  if (!isdigit((unsigned char) *s))
149  return false;
150  }
151  return true;
152 }
153 
161 int mh_check_empty(const char *path)
162 {
163  struct dirent *de = NULL;
164  int rc = 1; /* assume empty until we find a message */
165 
166  DIR *dp = opendir(path);
167  if (!dp)
168  return -1;
169  while ((de = readdir(dp)))
170  {
171  if (mh_valid_message(de->d_name))
172  {
173  rc = 0;
174  break;
175  }
176  }
177  closedir(dp);
178 
179  return rc;
180 }
181 
185 static enum MxStatus mh_mbox_check_stats(struct Mailbox *m, uint8_t flags)
186 {
187  struct MhSequences mhs = { 0 };
188  DIR *dirp = NULL;
189  struct dirent *de = NULL;
190 
191  /* when $mail_check_recent is set and the .mh_sequences file hasn't changed
192  * since the last m visit, there is no "new mail" */
193  if (C_MailCheckRecent && (mh_seq_changed(m) <= 0))
194  {
195  return MX_STATUS_OK;
196  }
197 
198  if (mh_seq_read(&mhs, mailbox_path(m)) < 0)
199  return MX_STATUS_ERROR;
200 
201  m->msg_count = 0;
202  m->msg_unread = 0;
203  m->msg_flagged = 0;
204 
205  enum MxStatus rc = MX_STATUS_OK;
206  bool check_new = true;
207  for (int i = mhs.max; i > 0; i--)
208  {
209  if ((mh_seq_check(&mhs, i) & MH_SEQ_FLAGGED))
210  m->msg_flagged++;
211  if (mh_seq_check(&mhs, i) & MH_SEQ_UNSEEN)
212  {
213  m->msg_unread++;
214  if (check_new)
215  {
216  /* if the first unseen message we encounter was in the m during the
217  * last visit, don't notify about it */
218  if (!C_MailCheckRecent || (mh_already_notified(m, i) == 0))
219  {
220  m->has_new = true;
221  rc = MX_STATUS_NEW_MAIL;
222  }
223  /* Because we are traversing from high to low, we can stop
224  * checking for new mail after the first unseen message.
225  * Whether it resulted in "new mail" or not. */
226  check_new = false;
227  }
228  }
229  }
230 
231  mh_seq_free(&mhs);
232 
233  dirp = opendir(mailbox_path(m));
234  if (dirp)
235  {
236  while ((de = readdir(dirp)))
237  {
238  if (*de->d_name == '.')
239  continue;
240  if (mh_valid_message(de->d_name))
241  m->msg_count++;
242  }
243  closedir(dirp);
244  }
245 
246  return rc;
247 }
248 
254 void mh_update_maildir(struct MdEmailArray *mda, struct MhSequences *mhs)
255 {
256  struct MdEmail *md = NULL;
257  struct MdEmail **mdp = NULL;
258  ARRAY_FOREACH(mdp, mda)
259  {
260  md = *mdp;
261  char *p = strrchr(md->email->path, '/');
262  if (p)
263  p++;
264  else
265  p = md->email->path;
266 
267  int i = 0;
268  if (mutt_str_atoi(p, &i) < 0)
269  continue;
270  MhSeqFlags flags = mh_seq_check(mhs, i);
271 
272  md->email->read = !(flags & MH_SEQ_UNSEEN);
273  md->email->flagged = (flags & MH_SEQ_FLAGGED);
274  md->email->replied = (flags & MH_SEQ_REPLIED);
275  }
276 }
277 
287 int mh_commit_msg(struct Mailbox *m, struct Message *msg, struct Email *e, bool updseq)
288 {
289  struct dirent *de = NULL;
290  char *cp = NULL, *dep = NULL;
291  unsigned int n, hi = 0;
292  char path[PATH_MAX];
293  char tmp[16];
294 
295  if (mutt_file_fsync_close(&msg->fp))
296  {
297  mutt_perror(_("Could not flush message to disk"));
298  return -1;
299  }
300 
301  DIR *dirp = opendir(mailbox_path(m));
302  if (!dirp)
303  {
305  return -1;
306  }
307 
308  /* figure out what the next message number is */
309  while ((de = readdir(dirp)))
310  {
311  dep = de->d_name;
312  if (*dep == ',')
313  dep++;
314  cp = dep;
315  while (*cp)
316  {
317  if (!isdigit((unsigned char) *cp))
318  break;
319  cp++;
320  }
321  if (*cp == '\0')
322  {
323  if (mutt_str_atoui(dep, &n) < 0)
324  mutt_debug(LL_DEBUG2, "Invalid MH message number '%s'\n", dep);
325  if (n > hi)
326  hi = n;
327  }
328  }
329  closedir(dirp);
330 
331  /* Now try to rename the file to the proper name.
332  * Note: We may have to try multiple times, until we find a free slot. */
333 
334  while (true)
335  {
336  hi++;
337  snprintf(tmp, sizeof(tmp), "%u", hi);
338  snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), tmp);
339  if (mutt_file_safe_rename(msg->path, path) == 0)
340  {
341  if (e)
342  mutt_str_replace(&e->path, tmp);
343  mutt_str_replace(&msg->committed_path, path);
344  FREE(&msg->path);
345  break;
346  }
347  else if (errno != EEXIST)
348  {
350  return -1;
351  }
352  }
353  if (updseq)
354  {
355  mh_seq_add_one(m, hi, !msg->flags.read, msg->flags.flagged, msg->flags.replied);
356  }
357  return 0;
358 }
359 
367 int mh_rewrite_message(struct Mailbox *m, int msgno)
368 {
369  if (!m || !m->emails || (msgno >= m->msg_count))
370  return -1;
371 
372  struct Email *e = m->emails[msgno];
373  if (!e)
374  return -1;
375 
376  bool restore = true;
377 
378  long old_body_offset = e->body->offset;
379  long old_body_length = e->body->length;
380  long old_hdr_lines = e->lines;
381 
382  struct Message *dest = mx_msg_open_new(m, e, MUTT_MSG_NO_FLAGS);
383  if (!dest)
384  return -1;
385 
386  int rc = mutt_copy_message(dest->fp, m, e, MUTT_CM_UPDATE, CH_UPDATE | CH_UPDATE_LEN, 0);
387  if (rc == 0)
388  {
389  char oldpath[PATH_MAX];
390  char partpath[PATH_MAX];
391  snprintf(oldpath, sizeof(oldpath), "%s/%s", mailbox_path(m), e->path);
392  mutt_str_copy(partpath, e->path, sizeof(partpath));
393 
394  rc = mh_commit_msg(m, dest, e, false);
395  mx_msg_close(m, &dest);
396 
397  if (rc == 0)
398  {
399  unlink(oldpath);
400  restore = false;
401  }
402 
403  /* Try to move the new message to the old place.
404  * (MH only.)
405  *
406  * This is important when we are just updating flags.
407  *
408  * Note that there is a race condition against programs which
409  * use the first free slot instead of the maximum message
410  * number. NeoMutt does _not_ behave like this.
411  *
412  * Anyway, if this fails, the message is in the folder, so
413  * all what happens is that a concurrently running neomutt will
414  * lose flag modifications. */
415  if (rc == 0)
416  {
417  char newpath[PATH_MAX];
418  snprintf(newpath, sizeof(newpath), "%s/%s", mailbox_path(m), e->path);
419  rc = mutt_file_safe_rename(newpath, oldpath);
420  if (rc == 0)
421  mutt_str_replace(&e->path, partpath);
422  }
423  }
424  else
425  mx_msg_close(m, &dest);
426 
427  if ((rc == -1) && restore)
428  {
429  e->body->offset = old_body_offset;
430  e->body->length = old_body_length;
431  e->lines = old_hdr_lines;
432  }
433 
434  mutt_body_free(&e->body->parts);
435  return rc;
436 }
437 
445 int mh_sync_message(struct Mailbox *m, int msgno)
446 {
447  if (!m || !m->emails)
448  return -1;
449 
450  struct Email *e = m->emails[msgno];
451  if (!e)
452  return -1;
453 
454  /* TODO: why the e->env check? */
455  if (e->attach_del || (e->env && e->env->changed))
456  {
457  if (mh_rewrite_message(m, msgno) != 0)
458  return -1;
459  /* TODO: why the env check? */
460  if (e->env)
461  e->env->changed = 0;
462  }
463 
464  return 0;
465 }
466 
471 void mh_update_mtime(struct Mailbox *m)
472 {
473  char buf[PATH_MAX];
474  struct stat st;
476 
477  snprintf(buf, sizeof(buf), "%s/.mh_sequences", mailbox_path(m));
478  if (stat(buf, &st) == 0)
480 
481  mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
482 
483  if (stat(buf, &st) == 0)
485 }
486 
496 int mh_parse_dir(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
497 {
498  struct dirent *de = NULL;
499  int rc = 0;
500  struct MdEmail *entry = NULL;
501  struct Email *e = NULL;
502 
503  struct Buffer *buf = mutt_buffer_pool_get();
505 
506  DIR *dirp = opendir(mutt_buffer_string(buf));
507  if (!dirp)
508  {
509  rc = -1;
510  goto cleanup;
511  }
512 
513  while (((de = readdir(dirp))) && (SigInt != 1))
514  {
515  if (!mh_valid_message(de->d_name))
516  continue;
517 
518  /* FOO - really ignore the return value? */
519  mutt_debug(LL_DEBUG2, "queueing %s\n", de->d_name);
520 
521  e = email_new();
522  e->edata = maildir_edata_new();
524 
525  if (m->verbose && progress)
526  mutt_progress_update(progress, ARRAY_SIZE(mda) + 1, -1);
527 
528  e->path = mutt_str_dup(de->d_name);
529 
530  entry = maildir_entry_new();
531  entry->email = e;
532  ARRAY_ADD(mda, entry);
533  }
534 
535  closedir(dirp);
536 
537  if (SigInt == 1)
538  {
539  SigInt = 0;
540  return -2; /* action aborted */
541  }
542 
543 cleanup:
545 
546  return rc;
547 }
548 
552 int mh_cmp_path(const void *a, const void *b)
553 {
554  struct MdEmail const *const *pa = (struct MdEmail const *const *) a;
555  struct MdEmail const *const *pb = (struct MdEmail const *const *) b;
556  return strcmp((*pa)->email->path, (*pb)->email->path);
557 }
558 
568 struct Email *mh_parse_message(const char *fname, struct Email *e)
569 {
570  FILE *fp = fopen(fname, "r");
571  if (!fp)
572  return NULL;
573 
574  if (!e)
575  {
576  e = email_new();
577  e->edata = maildir_edata_new();
579  }
580  e->env = mutt_rfc822_read_header(fp, e, false, false);
581 
582  struct stat st;
583  fstat(fileno(fp), &st);
584 
585  if (!e->received)
586  e->received = e->date_sent;
587 
588  /* always update the length since we have fresh information available. */
589  e->body->length = st.st_size - e->body->offset;
590  e->index = -1;
591 
592  mutt_file_fclose(&fp);
593  return e;
594 }
595 
602 void mh_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
603 {
604  char fn[PATH_MAX];
605 
606 #ifdef USE_HCACHE
607  struct HeaderCache *hc = mutt_hcache_open(C_HeaderCache, mailbox_path(m), NULL);
608 #endif
609 
610  struct MdEmail *md = NULL;
611  struct MdEmail **mdp = NULL;
612  ARRAY_FOREACH(mdp, mda)
613  {
614  md = *mdp;
615  if (!md || !md->email || md->header_parsed)
616  continue;
617 
618  if (m->verbose && progress)
619  mutt_progress_update(progress, ARRAY_FOREACH_IDX, -1);
620 
621  snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
622 
623 #ifdef USE_HCACHE
624  struct stat lastchanged = { 0 };
625  int rc = 0;
627  {
628  rc = stat(fn, &lastchanged);
629  }
630 
631  const char *key = md->email->path;
632  size_t keylen = strlen(key);
633  struct HCacheEntry hce = mutt_hcache_fetch(hc, key, keylen, 0);
634 
635  if (hce.email && (rc == 0) && (lastchanged.st_mtime <= hce.uidvalidity))
636  {
637  hce.email->edata = maildir_edata_new();
639  hce.email->old = md->email->old;
640  hce.email->path = mutt_str_dup(md->email->path);
641  email_free(&md->email);
642  md->email = hce.email;
643  }
644  else
645 #endif
646  {
647  if (mh_parse_message(fn, md->email))
648  {
649  md->header_parsed = true;
650 #ifdef USE_HCACHE
651  key = md->email->path;
652  keylen = strlen(key);
653  mutt_hcache_store(hc, key, keylen, md->email, 0);
654 #endif
655  }
656  else
657  email_free(&md->email);
658  }
659  }
660 #ifdef USE_HCACHE
661  mutt_hcache_close(hc);
662 #endif
663 
664  if (m && mda && (ARRAY_SIZE(mda) > 0) && (C_Sort == SORT_ORDER))
665  {
666  mutt_debug(LL_DEBUG3, "maildir: sorting %s into natural order\n", mailbox_path(m));
667  ARRAY_SORT(mda, mh_cmp_path);
668  }
669 }
670 
677 static bool mh_read_dir(struct Mailbox *m)
678 {
679  if (!m)
680  return false;
681 
682  struct MhSequences mhs = { 0 };
683  struct Progress progress;
684 
685  if (m->verbose)
686  {
687  char msg[PATH_MAX];
688  snprintf(msg, sizeof(msg), _("Scanning %s..."), mailbox_path(m));
689  mutt_progress_init(&progress, msg, MUTT_PROGRESS_READ, 0);
690  }
691 
693  if (!mdata)
694  {
696  m->mdata = mdata;
698  }
699 
700  mh_update_mtime(m);
701 
702  struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
703  if (mh_parse_dir(m, &mda, &progress) < 0)
704  return false;
705 
706  if (m->verbose)
707  {
708  char msg[PATH_MAX];
709  snprintf(msg, sizeof(msg), _("Reading %s..."), mailbox_path(m));
710  mutt_progress_init(&progress, msg, MUTT_PROGRESS_READ, ARRAY_SIZE(&mda));
711  }
712  mh_delayed_parsing(m, &mda, &progress);
713 
714  if (mh_seq_read(&mhs, mailbox_path(m)) < 0)
715  {
716  maildirarray_clear(&mda);
717  return false;
718  }
719  mh_update_maildir(&mda, &mhs);
720  mh_seq_free(&mhs);
721 
722  maildir_move_to_mailbox(m, &mda);
723 
724  if (!mdata->mh_umask)
725  mdata->mh_umask = mh_umask(m);
726 
727  return true;
728 }
729 
738 int mh_sync_mailbox_message(struct Mailbox *m, int msgno, struct HeaderCache *hc)
739 {
740  if (!m || !m->emails || (msgno >= m->msg_count))
741  return -1;
742 
743  struct Email *e = m->emails[msgno];
744  if (!e)
745  return -1;
746 
747  if (e->deleted)
748  {
749  char path[PATH_MAX];
750  snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
751  if (C_MhPurge)
752  {
753 #ifdef USE_HCACHE
754  if (hc)
755  {
756  const char *key = e->path;
757  size_t keylen = strlen(key);
758  mutt_hcache_delete_record(hc, key, keylen);
759  }
760 #endif
761  unlink(path);
762  }
763  else
764  {
765  /* MH just moves files out of the way when you delete them */
766  if (*e->path != ',')
767  {
768  char tmp[PATH_MAX];
769  snprintf(tmp, sizeof(tmp), "%s/,%s", mailbox_path(m), e->path);
770  unlink(tmp);
771  rename(path, tmp);
772  }
773  }
774  }
775  else if (e->changed || e->attach_del)
776  {
777  if (mh_sync_message(m, msgno) == -1)
778  return -1;
779  }
780 
781 #ifdef USE_HCACHE
782  if (hc && e->changed)
783  {
784  const char *key = e->path;
785  size_t keylen = strlen(key);
786  mutt_hcache_store(hc, key, keylen, e, 0);
787  }
788 #endif
789 
790  return 0;
791 }
792 
796 int mh_msg_save_hcache(struct Mailbox *m, struct Email *e)
797 {
798  int rc = 0;
799 #ifdef USE_HCACHE
800  struct HeaderCache *hc = mutt_hcache_open(C_HeaderCache, mailbox_path(m), NULL);
801  rc = mutt_hcache_store(hc, e->path, strlen(e->path), e, 0);
802  mutt_hcache_close(hc);
803 #endif
804  return rc;
805 }
806 
810 bool mh_ac_owns_path(struct Account *a, const char *path)
811 {
812  return true;
813 }
814 
818 bool mh_ac_add(struct Account *a, struct Mailbox *m)
819 {
820  return true;
821 }
822 
826 static enum MxOpenReturns mh_mbox_open(struct Mailbox *m)
827 {
828  return mh_read_dir(m) ? MX_OPEN_OK : MX_OPEN_ERROR;
829 }
830 
834 static bool mh_mbox_open_append(struct Mailbox *m, OpenMailboxFlags flags)
835 {
836  if (!(flags & (MUTT_APPENDNEW | MUTT_NEWFOLDER)))
837  return true;
838 
839  if (mutt_file_mkdir(mailbox_path(m), S_IRWXU))
840  {
842  return false;
843  }
844 
845  char tmp[PATH_MAX];
846  snprintf(tmp, sizeof(tmp), "%s/.mh_sequences", mailbox_path(m));
847  const int i = creat(tmp, S_IRWXU);
848  if (i == -1)
849  {
850  mutt_perror(tmp);
851  rmdir(mailbox_path(m));
852  return false;
853  }
854  close(i);
855 
856  return true;
857 }
858 
870 {
871  char buf[PATH_MAX];
872  struct stat st, st_cur;
873  bool modified = false, occult = false, flags_changed = false;
874  int num_new = 0;
875  struct MhSequences mhs = { 0 };
876  struct HashTable *fnames = NULL;
878 
879  if (!C_CheckNew)
880  return MX_STATUS_OK;
881 
882  mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
883  if (stat(buf, &st) == -1)
884  return MX_STATUS_ERROR;
885 
886  /* create .mh_sequences when there isn't one. */
887  snprintf(buf, sizeof(buf), "%s/.mh_sequences", mailbox_path(m));
888  int rc = stat(buf, &st_cur);
889  if ((rc == -1) && (errno == ENOENT))
890  {
891  char *tmp = NULL;
892  FILE *fp = NULL;
893 
894  if (mh_mkstemp(m, &fp, &tmp))
895  {
896  mutt_file_fclose(&fp);
897  if (mutt_file_safe_rename(tmp, buf) == -1)
898  unlink(tmp);
899  FREE(&tmp);
900  }
901  }
902 
903  if ((rc == -1) && (stat(buf, &st_cur) == -1))
904  modified = true;
905 
907  (mutt_file_stat_timespec_compare(&st_cur, MUTT_STAT_MTIME, &mdata->mtime_cur) > 0))
908  {
909  modified = true;
910  }
911 
912  if (!modified)
913  return MX_STATUS_OK;
914 
915  /* Update the modification times on the mailbox.
916  *
917  * The monitor code notices changes in the open mailbox too quickly.
918  * In practice, this sometimes leads to all the new messages not being
919  * noticed during the SAME group of mtime stat updates. To work around
920  * the problem, don't update the stat times for a monitor caused check. */
921 #ifdef USE_INOTIFY
923  MonitorContextChanged = false;
924  else
925 #endif
926  {
927  mutt_file_get_stat_timespec(&mdata->mtime_cur, &st_cur, MUTT_STAT_MTIME);
929  }
930 
931  struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
932 
933  mh_parse_dir(m, &mda, NULL);
934  mh_delayed_parsing(m, &mda, NULL);
935 
936  if (mh_seq_read(&mhs, mailbox_path(m)) < 0)
937  return MX_STATUS_ERROR;
938  mh_update_maildir(&mda, &mhs);
939  mh_seq_free(&mhs);
940 
941  /* check for modifications and adjust flags */
943 
944  struct MdEmail *md = NULL;
945  struct MdEmail **mdp = NULL;
946  ARRAY_FOREACH(mdp, &mda)
947  {
948  md = *mdp;
949  /* the hash key must survive past the header, which is freed below. */
950  md->canon_fname = mutt_str_dup(md->email->path);
951  mutt_hash_insert(fnames, md->canon_fname, md);
952  }
953 
954  for (int i = 0; i < m->msg_count; i++)
955  {
956  struct Email *e = m->emails[i];
957  if (!e)
958  break;
959 
960  e->active = false;
961 
962  md = mutt_hash_find(fnames, e->path);
963  if (md && md->email && email_cmp_strict(e, md->email))
964  {
965  e->active = true;
966  /* found the right message */
967  if (!e->changed)
968  if (maildir_update_flags(m, e, md->email))
969  flags_changed = true;
970 
971  email_free(&md->email);
972  }
973  else /* message has disappeared */
974  occult = true;
975  }
976 
977  /* destroy the file name hash */
978 
979  mutt_hash_free(&fnames);
980 
981  /* If we didn't just get new mail, update the tables. */
982  if (occult)
984 
985  /* Incorporate new messages */
986  num_new = maildir_move_to_mailbox(m, &mda);
987  if (num_new > 0)
988  {
990  m->changed = true;
991  }
992 
993  ARRAY_FREE(&mda);
994  if (occult)
995  return MX_STATUS_REOPENED;
996  if (num_new > 0)
997  return MX_STATUS_NEW_MAIL;
998  if (flags_changed)
999  return MX_STATUS_FLAGS;
1000  return MX_STATUS_OK;
1001 }
1002 
1013 {
1014  enum MxStatus check = mh_mbox_check(m);
1015  if (check == MX_STATUS_ERROR)
1016  return check;
1017 
1018  struct HeaderCache *hc = NULL;
1019 #ifdef USE_HCACHE
1020  if (m->type == MUTT_MH)
1022 #endif
1023 
1024  struct Progress progress;
1025  if (m->verbose)
1026  {
1027  char msg[PATH_MAX];
1028  snprintf(msg, sizeof(msg), _("Writing %s..."), mailbox_path(m));
1030  }
1031 
1032  for (int i = 0; i < m->msg_count; i++)
1033  {
1034  if (m->verbose)
1035  mutt_progress_update(&progress, i, -1);
1036 
1037  if (mh_sync_mailbox_message(m, i, hc) == -1)
1038  goto err;
1039  }
1040 
1041 #ifdef USE_HCACHE
1042  if (m->type == MUTT_MH)
1043  mutt_hcache_close(hc);
1044 #endif
1045 
1046  mh_seq_update(m);
1047 
1048  /* XXX race condition? */
1049 
1050  mh_update_mtime(m);
1051 
1052  /* adjust indices */
1053 
1054  if (m->msg_deleted)
1055  {
1056  for (int i = 0, j = 0; i < m->msg_count; i++)
1057  {
1058  struct Email *e = m->emails[i];
1059  if (!e)
1060  break;
1061 
1062  if (!e->deleted)
1063  e->index = j++;
1064  }
1065  }
1066 
1067  return check;
1068 
1069 err:
1070 #ifdef USE_HCACHE
1071  if (m->type == MUTT_MH)
1072  mutt_hcache_close(hc);
1073 #endif
1074  return MX_STATUS_ERROR;
1075 }
1076 
1082 {
1083  return MX_STATUS_OK;
1084 }
1085 
1089 static bool mh_msg_open(struct Mailbox *m, struct Message *msg, int msgno)
1090 {
1091  if (!m || !m->emails || (msgno >= m->msg_count))
1092  return false;
1093 
1094  struct Email *e = m->emails[msgno];
1095  if (!e)
1096  return false;
1097 
1098  char path[PATH_MAX];
1099 
1100  snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
1101 
1102  msg->fp = fopen(path, "r");
1103  if (!msg->fp)
1104  {
1105  mutt_perror(path);
1106  mutt_debug(LL_DEBUG1, "fopen: %s: %s (errno %d)\n", path, strerror(errno), errno);
1107  return false;
1108  }
1109 
1110  return true;
1111 }
1112 
1118 static bool mh_msg_open_new(struct Mailbox *m, struct Message *msg, const struct Email *e)
1119 {
1120  return mh_mkstemp(m, &msg->fp, &msg->path);
1121 }
1122 
1126 static int mh_msg_commit(struct Mailbox *m, struct Message *msg)
1127 {
1128  return mh_commit_msg(m, msg, NULL, true);
1129 }
1130 
1136 int mh_msg_close(struct Mailbox *m, struct Message *msg)
1137 {
1138  return mutt_file_fclose(&msg->fp);
1139 }
1140 
1144 int mh_path_canon(char *buf, size_t buflen)
1145 {
1146  mutt_path_canon(buf, buflen, HomeDir, true);
1147  return 0;
1148 }
1149 
1153 int mh_path_parent(char *buf, size_t buflen)
1154 {
1155  if (mutt_path_parent(buf, buflen))
1156  return 0;
1157 
1158  if (buf[0] == '~')
1159  mutt_path_canon(buf, buflen, HomeDir, true);
1160 
1161  if (mutt_path_parent(buf, buflen))
1162  return 0;
1163 
1164  return -1;
1165 }
1166 
1170 int mh_path_pretty(char *buf, size_t buflen, const char *folder)
1171 {
1172  if (mutt_path_abbr_folder(buf, buflen, folder))
1173  return 0;
1174 
1175  if (mutt_path_pretty(buf, buflen, HomeDir, false))
1176  return 0;
1177 
1178  return -1;
1179 }
1180 
1184 static enum MailboxType mh_path_probe(const char *path, const struct stat *st)
1185 {
1186  if (!st || !S_ISDIR(st->st_mode))
1187  return MUTT_UNKNOWN;
1188 
1189  char tmp[PATH_MAX];
1190 
1191  snprintf(tmp, sizeof(tmp), "%s/.mh_sequences", path);
1192  if (access(tmp, F_OK) == 0)
1193  return MUTT_MH;
1194 
1195  snprintf(tmp, sizeof(tmp), "%s/.xmhcache", path);
1196  if (access(tmp, F_OK) == 0)
1197  return MUTT_MH;
1198 
1199  snprintf(tmp, sizeof(tmp), "%s/.mew_cache", path);
1200  if (access(tmp, F_OK) == 0)
1201  return MUTT_MH;
1202 
1203  snprintf(tmp, sizeof(tmp), "%s/.mew-cache", path);
1204  if (access(tmp, F_OK) == 0)
1205  return MUTT_MH;
1206 
1207  snprintf(tmp, sizeof(tmp), "%s/.sylpheed_cache", path);
1208  if (access(tmp, F_OK) == 0)
1209  return MUTT_MH;
1210 
1211  /* ok, this isn't an mh folder, but mh mode can be used to read
1212  * Usenet news from the spool. */
1213 
1214  snprintf(tmp, sizeof(tmp), "%s/.overview", path);
1215  if (access(tmp, F_OK) == 0)
1216  return MUTT_MH;
1217 
1218  return MUTT_UNKNOWN;
1219 }
1220 
1221 // clang-format off
1225 struct MxOps MxMhOps = {
1226  .type = MUTT_MH,
1227  .name = "mh",
1228  .is_local = true,
1229  .ac_owns_path = mh_ac_owns_path,
1230  .ac_add = mh_ac_add,
1231  .mbox_open = mh_mbox_open,
1232  .mbox_open_append = mh_mbox_open_append,
1233  .mbox_check = mh_mbox_check,
1234  .mbox_check_stats = mh_mbox_check_stats,
1235  .mbox_sync = mh_mbox_sync,
1236  .mbox_close = mh_mbox_close,
1237  .msg_open = mh_msg_open,
1238  .msg_open_new = mh_msg_open_new,
1239  .msg_commit = mh_msg_commit,
1240  .msg_close = mh_msg_close,
1241  .msg_padding_size = NULL,
1242  .msg_save_hcache = mh_msg_save_hcache,
1243  .tags_edit = NULL,
1244  .tags_commit = NULL,
1245  .path_probe = mh_path_probe,
1246  .path_canon = mh_path_canon,
1247  .path_pretty = mh_path_pretty,
1248  .path_parent = mh_path_parent,
1249  .path_is_empty = mh_check_empty,
1250 };
1251 // clang-format on
Mailbox::mdata_free
void(* mdata_free)(void **ptr)
Free the private data attached to the Mailbox.
Definition: mailbox.h:142
MaildirMboxData::mh_umask
mode_t mh_umask
Definition: mdata.h:37
Email::date_sent
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:82
Message::flags
struct Message::@1 flags
Email::msgno
int msgno
Number displayed to the user.
Definition: email.h:87
MH_SEQ_REPLIED
#define MH_SEQ_REPLIED
Email has been replied to.
Definition: sequence.h:34
mutt_hcache_open
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:322
SigInt
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:74
mh_path_parent
int mh_path_parent(char *buf, size_t buflen)
Find the parent of a Mailbox path - Implements MxOps::path_parent()
Definition: mh.c:1153
mh_ac_owns_path
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:810
lib.h
MUTT_MSG_NO_FLAGS
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:64
mh_mbox_sync
enum MxStatus mh_mbox_sync(struct Mailbox *m)
Save changes to the Mailbox - Implements MxOps::mbox_sync()
Definition: mh.c:1012
mutt_hash_new
struct HashTable * mutt_hash_new(size_t num_elems, HashFlags flags)
Create a new Hash Table (with string keys)
Definition: hash.c:251
MxStatus
MxStatus
Return values from mx_mbox_check(), mx_mbox_sync(), and mx_mbox_close()
Definition: mx.h:71
MxOps::type
enum MailboxType type
Mailbox type, e.g. MUTT_IMAP.
Definition: mx.h:118
_
#define _(a)
Definition: message.h:28
NONULL
#define NONULL(x)
Definition: string2.h:37
Mailbox
A mailbox.
Definition: mailbox.h:81
Email::lines
int lines
How many lines in the body of this message?
Definition: email.h:85
C_MhPurge
bool C_MhPurge
Config: Really delete files in MH mailboxes.
Definition: config.c:43
ARRAY_ADD
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:152
restore
static struct Email * restore(const unsigned char *d)
Restore an Email from data retrieved from the cache.
Definition: hcache.c:146
Mailbox::emails
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
mh_ac_add
bool mh_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Implements MxOps::ac_add()
Definition: mh.c:818
mh_seq_read
int mh_seq_read(struct MhSequences *mhs, const char *path)
Read a set of MH sequences.
Definition: sequence.c:375
mh_rewrite_message
int mh_rewrite_message(struct Mailbox *m, int msgno)
Sync a message in an MH folder.
Definition: mh.c:367
NT_MAILBOX_INVALID
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:173
Buffer
String manipulation buffer.
Definition: buffer.h:33
mutt_path_abbr_folder
bool mutt_path_abbr_folder(char *buf, size_t buflen, const char *folder)
Create a folder abbreviation.
Definition: path.c:492
LL_DEBUG3
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
Body::offset
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
Mailbox::msg_deleted
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:96
mutt_file_fclose
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
mh_path_canon
int mh_path_canon(char *buf, size_t buflen)
Canonicalise a Mailbox path - Implements MxOps::path_canon()
Definition: mh.c:1144
MdEmail::canon_fname
char * canon_fname
Definition: mdemail.h:36
MdEmail::email
struct Email * email
Definition: mdemail.h:35
MUTT_STAT_MTIME
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:64
MxOpenReturns
MxOpenReturns
Return values for mbox_open()
Definition: mx.h:84
MUTT_PROGRESS_WRITE
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition: progress.h:43
MaildirMboxData
Maildir-specific Mailbox data -.
Definition: mdata.h:34
mdemail.h
mh_mbox_check_stats
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:185
MxOps
The Mailbox API.
Definition: mx.h:116
maildir_mdata_get
struct MaildirMboxData * maildir_mdata_get(struct Mailbox *m)
Get the private data for this Mailbox.
Definition: mdata.c:61
monitor.h
lib.h
MH_SEQ_FLAGGED
#define MH_SEQ_FLAGGED
Email is flagged.
Definition: sequence.h:35
mh_read_dir
static bool mh_read_dir(struct Mailbox *m)
Read an MH mailbox.
Definition: mh.c:677
MUTT_NEWFOLDER
#define MUTT_NEWFOLDER
Create a new folder - same as MUTT_APPEND,.
Definition: mx.h:56
maildirarray_clear
void maildirarray_clear(struct MdEmailArray *mda)
Free a Maildir array.
Definition: mdemail.c:66
mutt_str_dup
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
mutt_globals.h
LL_DEBUG1
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
ARRAY_SORT
#define ARRAY_SORT(head, fn)
Sort an array.
Definition: array.h:271
Mailbox::has_new
bool has_new
Mailbox has new mail.
Definition: mailbox.h:88
FREE
#define FREE(x)
Definition: memory.h:40
mutt_perror
#define mutt_perror(...)
Definition: logging.h:85
maildir_mdata_free
void maildir_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free()
Definition: mdata.c:37
MX_OPEN_OK
@ MX_OPEN_OK
Open succeeded.
Definition: mx.h:86
mutt_path_canon
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
mh_msg_open_new
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:1118
maildir_mdata_new
struct MaildirMboxData * maildir_mdata_new(void)
Create a new MaildirMboxData object.
Definition: mdata.c:50
Email::path
char * path
Path of Email (for local Mailboxes)
Definition: email.h:92
Email::edata_free
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:117
PATH_MAX
#define PATH_MAX
Definition: mutt.h:44
ARRAY_SIZE
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:83
copy.h
mutt_buffer_pool_release
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
C_MaildirHeaderCacheVerify
bool C_MaildirHeaderCacheVerify
Config: (hcache) Check for maildir changes when opening mailbox.
Definition: config.c:40
email_new
struct Email * email_new(void)
Create a new Email.
Definition: email.c:72
mutt_body_free
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
mh_parse_dir
int mh_parse_dir(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
Read a Maildir mailbox.
Definition: mh.c:496
mutt_str_atoi
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:252
sequence.h
MX_STATUS_REOPENED
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mx.h:77
mh_check_empty
int mh_check_empty(const char *path)
Is mailbox empty.
Definition: mh.c:161
mutt_hash_find
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:354
MX_STATUS_NEW_MAIL
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mx.h:75
lib.h
Email::old
bool old
Email is seen, but unread.
Definition: email.h:50
Email::received
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:83
Message::committed_path
char * committed_path
the final path generated by mx_msg_commit()
Definition: mx.h:98
mutt_progress_init
void mutt_progress_init(struct Progress *progress, const char *msg, enum ProgressType type, size_t size)
Set up a progress bar.
Definition: progress.c:153
Email::active
bool active
Message is not to be removed.
Definition: email.h:59
mutt_buffer_pool_get
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
edata.h
maildir_update_flags
bool maildir_update_flags(struct Mailbox *m, struct Email *e_old, struct Email *e_new)
Update the mailbox flags.
Definition: shared.c:124
Mailbox::type
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
Mailbox::mdata
void * mdata
Driver specific data.
Definition: mailbox.h:136
Envelope::changed
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:88
ARRAY_FOREACH
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:206
lib.h
Account
A group of associated Mailboxes.
Definition: account.h:36
Message::path
char * path
path to temp file
Definition: mx.h:97
ARRAY_HEAD_INITIALIZER
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:54
Progress
A progress bar.
Definition: progress.h:50
mh_seq_check
MhSeqFlags mh_seq_check(struct MhSequences *mhs, int i)
Get the flags for a given sequence.
Definition: sequence.c:84
mh_msg_save_hcache
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:796
Body::length
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
Mailbox::changed
bool changed
Mailbox has been modified.
Definition: mailbox.h:114
mh_sync_message
int mh_sync_message(struct Mailbox *m, int msgno)
Sync an email to an MH folder.
Definition: mh.c:445
lib.h
Mailbox::msg_count
int msg_count
Total number of messages.
Definition: mailbox.h:91
mh_cmp_path
int mh_cmp_path(const void *a, const void *b)
Compare two Maildirs by path - Implements sort_t.
Definition: mh.c:552
Message::read
bool read
Definition: mx.h:102
Mailbox::mtime
struct timespec mtime
Time Mailbox was last changed.
Definition: mailbox.h:107
MUTT_UNKNOWN
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:47
C_CheckNew
bool C_CheckNew
Config: (maildir,mh) Check for new mail while the mailbox is open.
Definition: config.c:37
mutt_hash_insert
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:327
MUTT_APPENDNEW
#define MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn't exist.
Definition: mx.h:60
mh_parse_message
struct Email * mh_parse_message(const char *fname, struct Email *e)
Actually parse an MH message.
Definition: mh.c:568
ARRAY_FREE
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:198
Body::parts
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
MUTT_PROGRESS_READ
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: progress.h:42
HCacheEntry::email
struct Email * email
Retrieved email.
Definition: lib.h:100
MxMhOps
struct MxOps MxMhOps
MH Mailbox - Implements MxOps.
Definition: mh.c:1225
MUTT_MH
@ MUTT_MH
'MH' Mailbox type
Definition: mailbox.h:50
Email::env
struct Envelope * env
Envelope information.
Definition: email.h:90
mutt_rand64
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: random.c:129
mutt_debug
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
mh_mbox_open_append
static bool mh_mbox_open_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a Mailbox for appending - Implements MxOps::mbox_open_append()
Definition: mh.c:834
MdEmail
A Maildir Email helper.
Definition: mdemail.h:33
CH_UPDATE
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:51
Message::replied
bool replied
Definition: mx.h:104
HCacheEntry
Wrapper for Email retrieved from the header cache.
Definition: lib.h:96
Mailbox::msg_flagged
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:93
Message::fp
FILE * fp
pointer to the message data
Definition: mx.h:96
MX_STATUS_ERROR
@ MX_STATUS_ERROR
An error occurred.
Definition: mx.h:73
Email::flagged
bool flagged
Marked important?
Definition: email.h:43
mutt_buffer_string
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
Mailbox::verbose
bool verbose
Display status messages?
Definition: mailbox.h:118
maildir_entry_new
struct MdEmail * maildir_entry_new(void)
Create a new Maildir entry.
Definition: mdemail.c:41
mh_update_mtime
void mh_update_mtime(struct Mailbox *m)
Update our record of the Maildir modification time.
Definition: mh.c:471
SORT_ORDER
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:50
MhSequences
Set of MH sequence numbers.
Definition: sequence.h:40
mh_mbox_open
static enum MxOpenReturns mh_mbox_open(struct Mailbox *m)
Open a Mailbox - Implements MxOps::mbox_open()
Definition: mh.c:826
mh_seq_add_one
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:113
MhSequences::max
int max
Number of flags stored.
Definition: sequence.h:42
mutt_str_replace
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
mh_valid_message
bool mh_valid_message(const char *s)
Is this a valid MH message filename.
Definition: mh.c:144
mh_delayed_parsing
void mh_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
This function does the second parsing pass.
Definition: mh.c:602
lib.h
Message::flagged
bool flagged
Definition: mx.h:103
mutt_hcache_store
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:527
Email::deleted
bool deleted
Email is deleted.
Definition: email.h:45
mutt_file_mkdir
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:875
MUTT_HASH_NO_FLAGS
#define MUTT_HASH_NO_FLAGS
No flags are set.
Definition: hash.h:97
HeaderCache
header cache structure
Definition: lib.h:85
mutt_path_parent
bool mutt_path_parent(char *buf, size_t buflen)
Find the parent of a path.
Definition: path.c:459
OpenMailboxFlags
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mx.h:50
mh_commit_msg
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:287
HomeDir
char * HomeDir
User's home directory.
Definition: mutt_globals.h:49
C_MailCheckRecent
WHERE bool C_MailCheckRecent
Config: Notify the user about new mail since the last time the mailbox was opened.
Definition: mutt_globals.h:150
C_Sort
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:60
Progress::msg
char msg[1024]
Definition: progress.h:52
sort.h
Email::edata
void * edata
Driver-specific data.
Definition: email.h:111
MdEmail::header_parsed
bool header_parsed
Definition: mdemail.h:37
ShortHostname
WHERE char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:50
mh_sync_mailbox_message
int mh_sync_mailbox_message(struct Mailbox *m, int msgno, struct HeaderCache *hc)
Save changes to the mailbox.
Definition: mh.c:738
MH_SEQ_UNSEEN
#define MH_SEQ_UNSEEN
Email hasn't been read.
Definition: sequence.h:33
mh_msg_open
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:1089
Mailbox::last_visited
struct timespec last_visited
Time of last exit from this mailbox.
Definition: mailbox.h:108
mutt_file_safe_rename
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:354
progress.h
mutt_hcache_delete_record
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:604
MUTT_CM_UPDATE
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:39
C_HeaderCache
char * C_HeaderCache
Config: (hcache) Directory/file for the header cache database.
Definition: config.c:40
mailbox_changed
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:186
mutt_file_get_stat_timespec
void mutt_file_get_stat_timespec(struct timespec *dest, struct stat *sb, enum MuttStatType type)
Read the stat() time into a time value.
Definition: file.c:1537
MailboxType
MailboxType
Supported mailbox formats.
Definition: mailbox.h:43
MhSeqFlags
uint8_t MhSeqFlags
Flags, e.g. MH_SEQ_UNSEEN.
Definition: sequence.h:29
Email::index
int index
The absolute (unsorted) message number.
Definition: email.h:86
mdata.h
mutt_rfc822_read_header
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
parses an RFC822 header
Definition: parse.c:1112
email_cmp_strict
bool email_cmp_strict(const struct Email *e1, const struct Email *e2)
Strictly compare message emails.
Definition: email.c:92
email_free
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:43
mutt_progress_update
void mutt_progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:212
Mailbox::msg_unread
int msg_unread
Number of unread messages.
Definition: mailbox.h:92
mh_mbox_check
enum MxStatus mh_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check()
Definition: mh.c:869
mh_seq_update
void mh_seq_update(struct Mailbox *m)
Update sequence numbers.
Definition: sequence.c:234
mh_msg_close
int mh_msg_close(struct Mailbox *m, struct Message *msg)
Close an email - Implements MxOps::msg_close()
Definition: mh.c:1136
MX_STATUS_FLAGS
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition: mx.h:78
private.h
Email::attach_del
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
mailbox_path
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:206
mx.h
mutt_path_pretty
bool mutt_path_pretty(char *buf, size_t buflen, const char *homedir, bool is_dir)
Tidy a filesystem path.
Definition: path.c:186
HCacheEntry::uidvalidity
uint32_t uidvalidity
IMAP-specific UIDVALIDITY.
Definition: lib.h:98
mx_msg_close
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1204
mutt_str_atoui
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:282
mutt_hcache_close
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:419
mh_path_pretty
int mh_path_pretty(char *buf, size_t buflen, const char *folder)
Abbreviate a Mailbox path - Implements MxOps::path_pretty()
Definition: mh.c:1170
mh_msg_commit
static int mh_msg_commit(struct Mailbox *m, struct Message *msg)
Save changes to an email - Implements MxOps::msg_commit()
Definition: mh.c:1126
Email::replied
bool replied
Email has been replied to.
Definition: email.h:54
mh_update_maildir
void mh_update_maildir(struct MdEmailArray *mda, struct MhSequences *mhs)
Update our record of flags.
Definition: mh.c:254
Email
The envelope/body of an email.
Definition: email.h:37
HashTable
A Hash Table.
Definition: hash.h:84
mx_msg_open_new
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1072
MX_OPEN_ERROR
@ MX_OPEN_ERROR
Open failed with an error.
Definition: mx.h:87
mutt_file_stat_timespec_compare
int mutt_file_stat_timespec_compare(struct stat *sba, enum MuttStatType type, struct timespec *b)
Compare stat info with a time value.
Definition: file.c:1577
mutt_copy_message
int mutt_copy_message(FILE *fp_out, struct Mailbox *m, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:835
mh_umask
mode_t mh_umask(struct Mailbox *m)
Create a umask from the mailbox directory.
Definition: shared.c:54
mutt_file_fsync_close
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:169
MonitorContextChanged
bool MonitorContextChanged
true after the current mailbox has changed
Definition: monitor.c:52
NT_MAILBOX_RESORT
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:174
CH_UPDATE_LEN
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
Email::read
bool read
Email is read.
Definition: email.h:51
mh_already_notified
static int mh_already_notified(struct Mailbox *m, int msgno)
Has the message changed.
Definition: mh.c:121
mh_seq_changed
int mh_seq_changed(struct Mailbox *m)
Has the mailbox changed.
Definition: sequence.c:433
mh_seq_free
void mh_seq_free(struct MhSequences *mhs)
Free some sequences.
Definition: sequence.c:73
mutt_buffer_strcpy
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
maildir_edata_free
void maildir_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:38
mh_mkstemp
bool mh_mkstemp(struct Mailbox *m, FILE **fp, char **tgt)
Create a temporary file.
Definition: mh.c:73
mh_mbox_close
enum MxStatus mh_mbox_close(struct Mailbox *m)
Close a Mailbox - Implements MxOps::mbox_close()
Definition: mh.c:1081
LL_DEBUG2
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
maildir_edata_new
struct MaildirEmailData * maildir_edata_new(void)
Create a new MaildirEmailData object.
Definition: edata.c:53
mutt_hash_free
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:447
Email::changed
bool changed
Email has been edited.
Definition: email.h:48
Message
A local copy of an email.
Definition: mx.h:94
MX_STATUS_OK
@ MX_STATUS_OK
No changes.
Definition: mx.h:74
Email::body
struct Body * body
List of MIME parts.
Definition: email.h:91
mh_path_probe
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:1184
maildir_move_to_mailbox
int maildir_move_to_mailbox(struct Mailbox *m, struct MdEmailArray *mda)
Copy the Maildir list to the Mailbox.
Definition: shared.c:77
mutt_hcache_fetch
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:438
mutt_str_copy
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:716