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