NeoMutt  2022-04-29-145-g9b6a0e
Teaching an old dog new tricks
DOXYGEN
mh.c File Reference

MH local mailbox type. More...

#include "config.h"
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "private.h"
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "lib.h"
#include "progress/lib.h"
#include "copy.h"
#include "edata.h"
#include "mdata.h"
#include "mdemail.h"
#include "mutt_globals.h"
#include "mx.h"
#include "sequence.h"
#include "monitor.h"
#include "hcache/lib.h"
+ Include dependency graph for mh.c:

Go to the source code of this file.

Functions

bool mh_mkstemp (struct Mailbox *m, FILE **fp, char **tgt)
 Create a temporary file. More...
 
static int mh_already_notified (struct Mailbox *m, int msgno)
 Has the message changed. More...
 
bool mh_valid_message (const char *s)
 Is this a valid MH message filename. More...
 
int mh_check_empty (const char *path)
 Is mailbox empty. More...
 
static enum MxStatus mh_mbox_check_stats (struct Mailbox *m, uint8_t flags)
 Check the Mailbox statistics - Implements MxOps::mbox_check_stats() -. More...
 
void mh_update_maildir (struct MdEmailArray *mda, struct MhSequences *mhs)
 Update our record of flags. More...
 
int mh_commit_msg (struct Mailbox *m, struct Message *msg, struct Email *e, bool updseq)
 Commit a message to an MH folder. More...
 
int mh_rewrite_message (struct Mailbox *m, int msgno)
 Sync a message in an MH folder. More...
 
int mh_sync_message (struct Mailbox *m, int msgno)
 Sync an email to an MH folder. More...
 
void mh_update_mtime (struct Mailbox *m)
 Update our record of the Maildir modification time. More...
 
int mh_parse_dir (struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
 Read a Maildir mailbox. More...
 
int mh_cmp_path (const void *a, const void *b)
 Compare two Maildirs by path - Implements sort_t -. More...
 
struct Emailmh_parse_message (const char *fname, struct Email *e)
 Actually parse an MH message. More...
 
void mh_delayed_parsing (struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
 This function does the second parsing pass. More...
 
static bool mh_read_dir (struct Mailbox *m)
 Read an MH mailbox. More...
 
int mh_sync_mailbox_message (struct Mailbox *m, int msgno, struct HeaderCache *hc)
 Save changes to the mailbox. More...
 
int mh_msg_save_hcache (struct Mailbox *m, struct Email *e)
 Save message to the header cache - Implements MxOps::msg_save_hcache() -. More...
 
bool mh_ac_owns_path (struct Account *a, const char *path)
 Check whether an Account own a Mailbox path - Implements MxOps::ac_owns_path() -. More...
 
bool mh_ac_add (struct Account *a, struct Mailbox *m)
 Add a Mailbox to an Account - Implements MxOps::ac_add() -. More...
 
static enum MxOpenReturns mh_mbox_open (struct Mailbox *m)
 Open a Mailbox - Implements MxOps::mbox_open() -. More...
 
static bool mh_mbox_open_append (struct Mailbox *m, OpenMailboxFlags flags)
 Open a Mailbox for appending - Implements MxOps::mbox_open_append() -. More...
 
enum MxStatus mh_mbox_check (struct Mailbox *m)
 Check for new mail - Implements MxOps::mbox_check() -. More...
 
enum MxStatus mh_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -. More...
 
enum MxStatus mh_mbox_close (struct Mailbox *m)
 Close a Mailbox - Implements MxOps::mbox_close() -. More...
 
static bool mh_msg_open (struct Mailbox *m, struct Message *msg, int msgno)
 Open an email message in a Mailbox - Implements MxOps::msg_open() -. More...
 
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() -. More...
 
static int mh_msg_commit (struct Mailbox *m, struct Message *msg)
 Save changes to an email - Implements MxOps::msg_commit() -. More...
 
int mh_msg_close (struct Mailbox *m, struct Message *msg)
 Close an email - Implements MxOps::msg_close() -. More...
 
int mh_path_canon (char *buf, size_t buflen)
 Canonicalise a Mailbox path - Implements MxOps::path_canon() -. More...
 
int mh_path_parent (char *buf, size_t buflen)
 Find the parent of a Mailbox path - Implements MxOps::path_parent() -. More...
 
int mh_path_pretty (char *buf, size_t buflen, const char *folder)
 Abbreviate a Mailbox path - Implements MxOps::path_pretty() -. More...
 
static enum MailboxType mh_path_probe (const char *path, const struct stat *st)
 Is this an mh Mailbox? - Implements MxOps::path_probe() -. More...
 

Variables

struct MxOps MxMhOps
 MH Mailbox - Implements MxOps -. More...
 

Detailed Description

MH local mailbox type.

Authors
  • Michael R. Elkins
  • Thomas Roessler
  • Michael R. Elkins
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file mh.c.

Function Documentation

◆ mh_mkstemp()

bool mh_mkstemp ( struct Mailbox m,
FILE **  fp,
char **  tgt 
)

Create a temporary file.

Parameters
[in]mMailbox to create the file in
[out]fpFile handle
[out]tgtFile name
Return values
trueSuccess
falseFailure

Definition at line 78 of file mh.c.

79 {
80  int fd;
81  char path[PATH_MAX];
82 
83  mode_t omask = umask(mh_umask(m));
84  while (true)
85  {
86  snprintf(path, sizeof(path), "%s/.neomutt-%s-%d-%" PRIu64, mailbox_path(m),
87  NONULL(ShortHostname), (int) getpid(), mutt_rand64());
88  fd = open(path, O_WRONLY | O_EXCL | O_CREAT, 0666);
89  if (fd == -1)
90  {
91  if (errno != EEXIST)
92  {
93  mutt_perror(path);
94  umask(omask);
95  return false;
96  }
97  }
98  else
99  {
100  *tgt = mutt_str_dup(path);
101  break;
102  }
103  }
104  umask(omask);
105 
106  *fp = fdopen(fd, "w");
107  if (!*fp)
108  {
109  FREE(tgt);
110  close(fd);
111  unlink(path);
112  return false;
113  }
114 
115  return true;
116 }
#define mutt_perror(...)
Definition: logging.h:88
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:211
mode_t mh_umask(struct Mailbox *m)
Create a umask from the mailbox directory.
Definition: shared.c:52
#define FREE(x)
Definition: memory.h:43
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
#define PATH_MAX
Definition: mutt.h:40
char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:50
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: random.c:129
#define NONULL(x)
Definition: string2.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_already_notified()

static int mh_already_notified ( struct Mailbox m,
int  msgno 
)
static

Has the message changed.

Parameters
mMailbox
msgnoMessage number
Return values
1Modification time on the message file is older than the last visit to this mailbox
0Modification time on the message file is newer
-1Error

Definition at line 126 of file mh.c.

127 {
128  char path[PATH_MAX];
129  struct stat st = { 0 };
130 
131  if ((snprintf(path, sizeof(path), "%s/%d", mailbox_path(m), msgno) < sizeof(path)) &&
132  (stat(path, &st) == 0))
133  {
135  }
136  return -1;
137 }
int mutt_file_stat_timespec_compare(struct stat *st, enum MuttStatType type, struct timespec *b)
Compare stat info with a time value.
Definition: file.c:1651
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:63
struct timespec last_visited
Time of last exit from this mailbox.
Definition: mailbox.h:105
+ Here is the call graph for this function:

◆ mh_valid_message()

bool mh_valid_message ( const char *  s)

Is this a valid MH message filename.

Parameters
sPathname to examine
Return values
truename is valid
falsename is invalid

Ignore the garbage files. A valid MH message consists of only digits. Deleted message get moved to a filename with a comma before it.

Definition at line 149 of file mh.c.

150 {
151  for (; *s; s++)
152  {
153  if (!isdigit((unsigned char) *s))
154  return false;
155  }
156  return true;
157 }
+ Here is the caller graph for this function:

◆ mh_check_empty()

int mh_check_empty ( const char *  path)

Is mailbox empty.

Parameters
pathMailbox to check
Return values
1Mailbox is empty
0Mailbox contains mail
-1Error

Definition at line 166 of file mh.c.

167 {
168  struct dirent *de = NULL;
169  int rc = 1; /* assume empty until we find a message */
170 
171  DIR *dp = opendir(path);
172  if (!dp)
173  return -1;
174  while ((de = readdir(dp)))
175  {
176  if (mh_valid_message(de->d_name))
177  {
178  rc = 0;
179  break;
180  }
181  }
182  closedir(dp);
183 
184  return rc;
185 }
bool mh_valid_message(const char *s)
Is this a valid MH message filename.
Definition: mh.c:149
+ Here is the call graph for this function:

◆ mh_update_maildir()

void mh_update_maildir ( struct MdEmailArray *  mda,
struct MhSequences mhs 
)

Update our record of flags.

Parameters
mdaMaildir array to update
mhsSequences

Definition at line 260 of file mh.c.

261 {
262  struct MdEmail *md = NULL;
263  struct MdEmail **mdp = NULL;
264  ARRAY_FOREACH(mdp, mda)
265  {
266  md = *mdp;
267  char *p = strrchr(md->email->path, '/');
268  if (p)
269  p++;
270  else
271  p = md->email->path;
272 
273  int i = 0;
274  if (!mutt_str_atoi_full(p, &i))
275  continue;
276  MhSeqFlags flags = mh_seq_check(mhs, i);
277 
278  md->email->read = !(flags & MH_SEQ_UNSEEN);
279  md->email->flagged = (flags & MH_SEQ_FLAGGED);
280  md->email->replied = (flags & MH_SEQ_REPLIED);
281  }
282 }
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:211
MhSeqFlags mh_seq_check(struct MhSequences *mhs, int i)
Get the flags for a given sequence.
Definition: sequence.c:78
#define MH_SEQ_UNSEEN
Email hasn't been read.
Definition: sequence.h:33
#define MH_SEQ_REPLIED
Email has been replied to.
Definition: sequence.h:34
uint8_t MhSeqFlags
Flags, e.g. MH_SEQ_UNSEEN.
Definition: sequence.h:29
#define MH_SEQ_FLAGGED
Email is flagged.
Definition: sequence.h:35
bool read
Email is read.
Definition: email.h:48
bool flagged
Marked important?
Definition: email.h:45
bool replied
Email has been replied to.
Definition: email.h:49
char * path
Path of Email (for local Mailboxes)
Definition: email.h:68
A Maildir Email helper.
Definition: mdemail.h:34
struct Email * email
Definition: mdemail.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ 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.

Parameters
mMailbox
msgMessage to commit
eEmail
updseqIf true, update the sequence number
Return values
0Success
-1Failure

Definition at line 293 of file mh.c.

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))
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 }
const char * mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: atoi.c:202
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:344
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:168
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
#define _(a)
Definition: message.h:28
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
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
FILE * fp
pointer to the message data
Definition: mxapi.h:44
char * path
path to temp file
Definition: mxapi.h:45
bool replied
Message has been replied to.
Definition: mxapi.h:52
char * committed_path
the final path generated by mx_msg_commit()
Definition: mxapi.h:46
bool flagged
Message is flagged.
Definition: mxapi.h:51
bool read
Message has been read.
Definition: mxapi.h:50
struct Message::@0 flags
Flags for the Message.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_rewrite_message()

int mh_rewrite_message ( struct Mailbox m,
int  msgno 
)

Sync a message in an MH folder.

Parameters
mMailbox
msgnoIndex number
Return values
0Success
-1Error

Definition at line 373 of file mh.c.

374 {
375  if (!m || !m->emails || (msgno >= m->msg_count))
376  return -1;
377 
378  struct Email *e = m->emails[msgno];
379  if (!e)
380  return -1;
381 
382  bool restore = true;
383 
384  long old_body_offset = e->body->offset;
385  long old_body_length = e->body->length;
386  long old_hdr_lines = e->lines;
387 
388  struct Message *src = mx_msg_open(m, msgno);
389  struct Message *dest = mx_msg_open_new(m, e, MUTT_MSG_NO_FLAGS);
390  if (!src || !dest)
391  return -1;
392 
393  int rc = mutt_copy_message(dest->fp, e, src, MUTT_CM_UPDATE, CH_UPDATE | CH_UPDATE_LEN, 0);
394  if (rc == 0)
395  {
396  char oldpath[PATH_MAX];
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, &src);
431  mx_msg_close(m, &dest);
432 
433  if ((rc == -1) && restore)
434  {
435  e->body->offset = old_body_offset;
436  e->body->length = old_body_length;
437  e->lines = old_hdr_lines;
438  }
439 
440  mutt_body_free(&e->body->parts);
441  return rc;
442 }
int mutt_copy_message(FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:864
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:40
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:52
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
static struct Email * restore(const unsigned char *d)
Restore an Email from data retrieved from the cache.
Definition: hcache.c:143
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
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:629
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1193
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1147
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1057
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:42
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
The envelope/body of an email.
Definition: email.h:37
int lines
How many lines in the body of this message?
Definition: email.h:60
struct Body * body
List of MIME parts.
Definition: email.h:67
int msgno
Number displayed to the user.
Definition: email.h:111
int msg_count
Total number of messages.
Definition: mailbox.h:88
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
A local copy of an email.
Definition: mxapi.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_sync_message()

int mh_sync_message ( struct Mailbox m,
int  msgno 
)

Sync an email to an MH folder.

Parameters
mMailbox
msgnoIndex number
Return values
0Success
-1Error

Definition at line 451 of file mh.c.

452 {
453  if (!m || !m->emails)
454  return -1;
455 
456  struct Email *e = m->emails[msgno];
457  if (!e)
458  return -1;
459 
460  /* TODO: why the e->env check? */
461  if (e->attach_del || (e->env && e->env->changed))
462  {
463  if (mh_rewrite_message(m, msgno) != 0)
464  return -1;
465  /* TODO: why the env check? */
466  if (e->env)
467  e->env->changed = 0;
468  }
469 
470  return 0;
471 }
int mh_rewrite_message(struct Mailbox *m, int msgno)
Sync a message in an MH folder.
Definition: mh.c:373
struct Envelope * env
Envelope information.
Definition: email.h:66
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:99
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:92
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_update_mtime()

void mh_update_mtime ( struct Mailbox m)

Update our record of the Maildir modification time.

Parameters
mMailbox

Definition at line 477 of file mh.c.

478 {
479  char buf[PATH_MAX];
480  struct stat st = { 0 };
482 
483  snprintf(buf, sizeof(buf), "%s/.mh_sequences", mailbox_path(m));
484  if (stat(buf, &st) == 0)
486 
487  mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
488 
489  if (stat(buf, &st) == 0)
491 }
void mutt_file_get_stat_timespec(struct timespec *dest, struct stat *st, enum MuttStatType type)
Read the stat() time into a time value.
Definition: file.c:1611
struct MaildirMboxData * maildir_mdata_get(struct Mailbox *m)
Get the private data for this Mailbox.
Definition: mdata.c:58
struct timespec mtime
Time Mailbox was last changed.
Definition: mailbox.h:104
void * mdata
Driver specific data.
Definition: mailbox.h:133
Maildir-specific Mailbox data -.
Definition: mdata.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_parse_dir()

int mh_parse_dir ( struct Mailbox m,
struct MdEmailArray *  mda,
struct Progress *  progress 
)

Read a Maildir mailbox.

Parameters
[in]mMailbox
[out]mdaArray for results
[in]progressProgress bar
Return values
0Success
-1Error
-2Aborted

Definition at line 502 of file mh.c.

503 {
504  struct dirent *de = NULL;
505  int rc = 0;
506  struct MdEmail *entry = NULL;
507  struct Email *e = NULL;
508 
509  struct Buffer *buf = mutt_buffer_pool_get();
511 
512  DIR *dirp = opendir(mutt_buffer_string(buf));
513  if (!dirp)
514  {
515  rc = -1;
516  goto cleanup;
517  }
518 
519  while (((de = readdir(dirp))) && !SigInt)
520  {
521  if (!mh_valid_message(de->d_name))
522  continue;
523 
524  /* FOO - really ignore the return value? */
525  mutt_debug(LL_DEBUG2, "queueing %s\n", de->d_name);
526 
527  e = email_new();
528  e->edata = maildir_edata_new();
530 
531  if (m->verbose && progress)
532  progress_update(progress, ARRAY_SIZE(mda) + 1, -1);
533 
534  e->path = mutt_str_dup(de->d_name);
535 
536  entry = maildir_entry_new();
537  entry->email = e;
538  ARRAY_ADD(mda, entry);
539  }
540 
541  closedir(dirp);
542 
543  if (SigInt)
544  {
545  SigInt = false;
546  return -2; /* action aborted */
547  }
548 
549 cleanup:
551 
552  return rc;
553 }
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:155
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:86
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:310
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
struct MaildirEmailData * maildir_edata_new(void)
Create a new MaildirEmailData object.
Definition: edata.c:53
void maildir_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:38
struct MdEmail * maildir_entry_new(void)
Create a new Maildir entry.
Definition: mdemail.c:39
SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:69
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:73
String manipulation buffer.
Definition: buffer.h:34
void * edata
Driver-specific data.
Definition: email.h:72
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:87
bool verbose
Display status messages?
Definition: mailbox.h:115
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_parse_message()

struct Email* mh_parse_message ( const char *  fname,
struct Email e 
)

Actually parse an MH message.

Parameters
fnameMessage filename
eEmail to populate (OPTIONAL)
Return values
ptrPopulated Email

This may also be used to fill out a fake header structure generated by lazy maildir parsing.

Definition at line 574 of file mh.c.

575 {
576  FILE *fp = fopen(fname, "r");
577  if (!fp)
578  {
579  return NULL;
580  }
581 
582  const long size = mutt_file_get_size_fp(fp);
583  if (size == 0)
584  {
585  mutt_file_fclose(&fp);
586  return NULL;
587  }
588 
589  if (!e)
590  {
591  e = email_new();
592  e->edata = maildir_edata_new();
594  }
595  e->env = mutt_rfc822_read_header(fp, e, false, false);
596 
597  if (e->received != 0)
598  e->received = e->date_sent;
599 
600  /* always update the length since we have fresh information available. */
601  e->body->length = size - e->body->offset;
602  e->index = -1;
603 
604  mutt_file_fclose(&fp);
605  return e;
606 }
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1569
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1158
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:58
int index
The absolute (unsorted) message number.
Definition: email.h:110
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_delayed_parsing()

void mh_delayed_parsing ( struct Mailbox m,
struct MdEmailArray *  mda,
struct Progress *  progress 
)

This function does the second parsing pass.

Parameters
[in]mMailbox
[out]mdaMaildir array to parse
[in]progressProgress bar

Definition at line 614 of file mh.c.

615 {
616  char fn[PATH_MAX];
617 
618 #ifdef USE_HCACHE
619  const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
620  struct HeaderCache *hc = mutt_hcache_open(c_header_cache, mailbox_path(m), NULL);
621 #endif
622 
623  struct MdEmail *md = NULL;
624  struct MdEmail **mdp = NULL;
625  ARRAY_FOREACH(mdp, mda)
626  {
627  md = *mdp;
628  if (!md || !md->email || md->header_parsed)
629  continue;
630 
631  if (m->verbose && progress)
632  progress_update(progress, ARRAY_FOREACH_IDX, -1);
633 
634  snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
635 
636 #ifdef USE_HCACHE
637  struct stat st_lastchanged = { 0 };
638  int rc = 0;
639  const bool c_maildir_header_cache_verify = cs_subset_bool(NeoMutt->sub, "maildir_header_cache_verify");
640  if (c_maildir_header_cache_verify)
641  {
642  rc = stat(fn, &st_lastchanged);
643  }
644 
645  const char *key = md->email->path;
646  size_t keylen = strlen(key);
647  struct HCacheEntry hce = mutt_hcache_fetch(hc, key, keylen, 0);
648 
649  if (hce.email && (rc == 0) && (st_lastchanged.st_mtime <= hce.uidvalidity))
650  {
651  hce.email->edata = maildir_edata_new();
653  hce.email->old = md->email->old;
654  hce.email->path = mutt_str_dup(md->email->path);
655  email_free(&md->email);
656  md->email = hce.email;
657  }
658  else
659 #endif
660  {
661  if (mh_parse_message(fn, md->email))
662  {
663  md->header_parsed = true;
664 #ifdef USE_HCACHE
665  key = md->email->path;
666  keylen = strlen(key);
667  mutt_hcache_store(hc, key, keylen, md->email, 0);
668 #endif
669  }
670  else
671  email_free(&md->email);
672  }
673  }
674 #ifdef USE_HCACHE
675  mutt_hcache_close(hc);
676 #endif
677 
678  const short c_sort = cs_subset_sort(NeoMutt->sub, "sort");
679  if (m && mda && (ARRAY_SIZE(mda) > 0) && (c_sort == SORT_ORDER))
680  {
681  mutt_debug(LL_DEBUG3, "maildir: sorting %s into natural order\n", mailbox_path(m));
682  ARRAY_SORT(mda, mh_cmp_path);
683  }
684 }
#define ARRAY_SORT(head, fn)
Sort an array.
Definition: array.h:277
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
int mh_cmp_path(const void *a, const void *b)
Compare two Maildirs by path - Implements sort_t -.
Definition: mh.c:558
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:548
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:332
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:432
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:456
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
struct Email * mh_parse_message(const char *fname, struct Email *e)
Actually parse an MH message.
Definition: mh.c:574
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:48
bool old
Email is seen, but unread.
Definition: email.h:47
Wrapper for Email retrieved from the header cache.
Definition: lib.h:98
uint32_t uidvalidity
IMAP-specific UIDVALIDITY.
Definition: lib.h:99
struct Email * email
Retrieved email.
Definition: lib.h:101
Header cache structure.
Definition: lib.h:87
bool header_parsed
Definition: mdemail.h:37
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_read_dir()

static bool mh_read_dir ( struct Mailbox m)
static

Read an MH mailbox.

Parameters
mMailbox
Return values
trueSuccess
falseError

Definition at line 692 of file mh.c.

693 {
694  if (!m)
695  return false;
696 
697  struct MhSequences mhs = { 0 };
698  struct Progress *progress = NULL;
699 
700  if (m->verbose)
701  {
702  char msg[PATH_MAX];
703  snprintf(msg, sizeof(msg), _("Scanning %s..."), mailbox_path(m));
704  progress = progress_new(msg, MUTT_PROGRESS_READ, 0);
705  }
706 
708  if (!mdata)
709  {
711  m->mdata = mdata;
713  }
714 
715  mh_update_mtime(m);
716 
717  struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
718  int rc = mh_parse_dir(m, &mda, progress);
719  progress_free(&progress);
720  if (rc < 0)
721  return false;
722 
723  if (m->verbose)
724  {
725  char msg[PATH_MAX];
726  snprintf(msg, sizeof(msg), _("Reading %s..."), mailbox_path(m));
727  progress = progress_new(msg, MUTT_PROGRESS_READ, ARRAY_SIZE(&mda));
728  }
729  mh_delayed_parsing(m, &mda, progress);
730  progress_free(&progress);
731 
732  if (mh_seq_read(&mhs, mailbox_path(m)) < 0)
733  {
734  maildirarray_clear(&mda);
735  return false;
736  }
737  mh_update_maildir(&mda, &mhs);
738  mh_seq_free(&mhs);
739 
740  maildir_move_to_mailbox(m, &mda);
741 
742  if (!mdata->mh_umask)
743  mdata->mh_umask = mh_umask(m);
744 
745  return true;
746 }
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:57
void maildir_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free()
Definition: mdata.c:37
struct MaildirMboxData * maildir_mdata_new(void)
Create a new MaildirMboxData object.
Definition: mdata.c:47
int maildir_move_to_mailbox(struct Mailbox *m, struct MdEmailArray *mda)
Copy the Maildir list to the Mailbox.
Definition: shared.c:75
void maildirarray_clear(struct MdEmailArray *mda)
Free a Maildir array.
Definition: mdemail.c:64
void mh_update_mtime(struct Mailbox *m)
Update our record of the Maildir modification time.
Definition: mh.c:477
void mh_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
This function does the second parsing pass.
Definition: mh.c:614
void mh_update_maildir(struct MdEmailArray *mda, struct MhSequences *mhs)
Update our record of flags.
Definition: mh.c:260
int mh_parse_dir(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
Read a Maildir mailbox.
Definition: mh.c:502
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: lib.h:49
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:86
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:118
void mh_seq_free(struct MhSequences *mhs)
Free some sequences.
Definition: sequence.c:67
int mh_seq_read(struct MhSequences *mhs, const char *path)
Read a set of MH sequences.
Definition: sequence.c:375
void(* mdata_free)(void **ptr)
Free the private data attached to the Mailbox.
Definition: mailbox.h:143
mode_t mh_umask
umask to use when creating files
Definition: mdata.h:37
Set of MH sequence numbers.
Definition: sequence.h:41
+ Here is the call graph for this function:

◆ mh_sync_mailbox_message()

int mh_sync_mailbox_message ( struct Mailbox m,
int  msgno,
struct HeaderCache hc 
)

Save changes to the mailbox.

Parameters
mMailbox
msgnoIndex number
hcHeader cache handle
Return values
0Success
-1Error

Definition at line 756 of file mh.c.

757 {
758  if (!m || !m->emails || (msgno >= m->msg_count))
759  return -1;
760 
761  struct Email *e = m->emails[msgno];
762  if (!e)
763  return -1;
764 
765  if (e->deleted)
766  {
767  char path[PATH_MAX];
768  snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
769  const bool c_mh_purge = cs_subset_bool(NeoMutt->sub, "mh_purge");
770  if (c_mh_purge)
771  {
772 #ifdef USE_HCACHE
773  if (hc)
774  {
775  const char *key = e->path;
776  size_t keylen = strlen(key);
777  mutt_hcache_delete_record(hc, key, keylen);
778  }
779 #endif
780  unlink(path);
781  }
782  else
783  {
784  /* MH just moves files out of the way when you delete them */
785  if (*e->path != ',')
786  {
787  char tmp[PATH_MAX];
788  snprintf(tmp, sizeof(tmp), "%s/,%s", mailbox_path(m), e->path);
789  unlink(tmp);
790  if (rename(path, tmp) != 0)
791  {
792  return -1;
793  }
794  }
795  }
796  }
797  else if (e->changed || e->attach_del)
798  {
799  if (mh_sync_message(m, msgno) == -1)
800  return -1;
801  }
802 
803 #ifdef USE_HCACHE
804  if (hc && e->changed)
805  {
806  const char *key = e->path;
807  size_t keylen = strlen(key);
808  mutt_hcache_store(hc, key, keylen, e, 0);
809  }
810 #endif
811 
812  return 0;
813 }
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:627
int mh_sync_message(struct Mailbox *m, int msgno)
Sync an email to an MH folder.
Definition: mh.c:451
bool changed
Email has been edited.
Definition: email.h:75
bool deleted
Email is deleted.
Definition: email.h:76
+ Here is the call graph for this function: