NeoMutt  2021-02-05-666-ge300cd
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 <stdint.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 "monitor.h"
#include "mutt_globals.h"
#include "mx.h"
#include "sequence.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() -This function handles arrival of new mail and reopening of mh/maildir folders. 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() -Open a new (temporary) message in an MH folder. 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 77 of file mh.c.

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 }
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
#define NONULL(x)
Definition: string2.h:37
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define mutt_perror(...)
Definition: logging.h:89
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: random.c:130
#define PATH_MAX
Definition: mutt.h:40
WHERE char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:46
mode_t mh_umask(struct Mailbox *m)
Create a umask from the mailbox directory.
Definition: shared.c:52
#define FREE(x)
Definition: memory.h:40
+ 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 125 of file mh.c.

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 }
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
struct timespec last_visited
Time of last exit from this mailbox.
Definition: mailbox.h:108
File/dir&#39;s mtime - last modified time.
Definition: file.h:63
#define PATH_MAX
Definition: mutt.h:40
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
+ Here is the call graph for this function:
+ Here is the caller 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 148 of file mh.c.

149 {
150  for (; *s; s++)
151  {
152  if (!isdigit((unsigned char) *s))
153  return false;
154  }
155  return true;
156 }
+ 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 165 of file mh.c.

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 }
bool mh_valid_message(const char *s)
Is this a valid MH message filename.
Definition: mh.c:148
+ 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(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 }
MhSeqFlags mh_seq_check(struct MhSequences *mhs, int i)
Get the flags for a given sequence.
Definition: sequence.c:78
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:252
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:206
uint8_t MhSeqFlags
Flags, e.g. MH_SEQ_UNSEEN.
Definition: sequence.h:29
bool read
Email is read.
Definition: email.h:51
A Maildir Email helper.
Definition: mdemail.h:33
#define MH_SEQ_REPLIED
Email has been replied to.
Definition: sequence.h:34
struct Email * email
Definition: mdemail.h:35
#define MH_SEQ_FLAGGED
Email is flagged.
Definition: sequence.h:35
bool flagged
Marked important?
Definition: email.h:43
bool replied
Email has been replied to.
Definition: email.h:54
char * path
Path of Email (for local Mailboxes)
Definition: email.h:92
#define MH_SEQ_UNSEEN
Email hasn&#39;t been read.
Definition: sequence.h:33
+ 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) < 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 }
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
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
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
#define _(a)
Definition: message.h:28
#define mutt_perror(...)
Definition: logging.h:89
Log at debug level 2.
Definition: logging.h:41
bool flagged
Definition: mxapi.h:50
#define PATH_MAX
Definition: mutt.h:40
struct Message::@1 flags
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:282
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
char * committed_path
the final path generated by mx_msg_commit()
Definition: mxapi.h:45
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
char * path
Path of Email (for local Mailboxes)
Definition: email.h:92
FILE * fp
pointer to the message data
Definition: mxapi.h:43
#define FREE(x)
Definition: memory.h:40
bool read
Definition: mxapi.h:49
char * path
path to temp file
Definition: mxapi.h:44
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:354
+ 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 *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 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:41
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
int lines
How many lines in the body of this message?
Definition: email.h:85
int msg_count
Total number of messages.
Definition: mailbox.h:91
The envelope/body of an email.
Definition: email.h:37
struct Body * body
List of MIME parts.
Definition: email.h:91
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:40
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:52
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1186
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1054
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
A local copy of an email.
Definition: mxapi.h:41
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
#define PATH_MAX
Definition: mutt.h:40
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
#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
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
char * path
Path of Email (for local Mailboxes)
Definition: email.h:92
FILE * fp
pointer to the message data
Definition: mxapi.h:43
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
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
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:354
+ 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 450 of file mh.c.

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 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
The envelope/body of an email.
Definition: email.h:37
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:88
struct Envelope * env
Envelope information.
Definition: email.h:90
int mh_rewrite_message(struct Mailbox *m, int msgno)
Sync a message in an MH folder.
Definition: mh.c:373
int msgno
Number displayed to the user.
Definition: email.h:87
+ 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 476 of file mh.c.

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 }
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
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
struct timespec mtime
Time Mailbox was last changed.
Definition: mailbox.h:107
File/dir&#39;s mtime - last modified time.
Definition: file.h:63
void * mdata
Driver specific data.
Definition: mailbox.h:136
#define PATH_MAX
Definition: mutt.h:40
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
struct timespec mtime_cur
Definition: mdata.h:36
Maildir-specific Mailbox data -.
Definition: mdata.h:34
struct MaildirMboxData * maildir_mdata_get(struct Mailbox *m)
Get the private data for this Mailbox.
Definition: mdata.c:58
+ 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 501 of file mh.c.

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 }
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
The envelope/body of an email.
Definition: email.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:67
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
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
A Maildir Email helper.
Definition: mdemail.h:33
Log at debug level 2.
Definition: logging.h:41
bool mh_valid_message(const char *s)
Is this a valid MH message filename.
Definition: mh.c:148
struct MdEmail * maildir_entry_new(void)
Create a new Maildir entry.
Definition: mdemail.c:39
struct Email * email
Definition: mdemail.h:35
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
bool verbose
Display status messages?
Definition: mailbox.h:118
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
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
void * edata
Driver-specific data.
Definition: email.h:111
char * path
Path of Email (for local Mailboxes)
Definition: email.h:92
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:152
void maildir_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:38
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:83
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_cmp_path()

int mh_cmp_path ( const void *  a,
const void *  b 
)

Compare two Maildirs by path - Implements sort_t.

Definition at line 557 of file mh.c.

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 }
A Maildir Email helper.
Definition: mdemail.h:33
+ 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 573 of file mh.c.

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 }
struct Body * body
List of MIME parts.
Definition: email.h:91
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
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
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:82
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
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
void * edata
Driver-specific data.
Definition: email.h:111
int index
The absolute (unsorted) message number.
Definition: email.h:86
void maildir_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:38
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
parses an RFC822 header
Definition: parse.c:1124
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:83
+ 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 607 of file mh.c.

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 }
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
Wrapper for Email retrieved from the header cache.
Definition: lib.h:95
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:206
uint32_t uidvalidity
IMAP-specific UIDVALIDITY.
Definition: lib.h:97
header cache structure
Definition: lib.h:84
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:332
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 Maildir Email helper.
Definition: mdemail.h:33
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
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
struct Email * email
Definition: mdemail.h:35
#define PATH_MAX
Definition: mutt.h:40
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
bool verbose
Display status messages?
Definition: mailbox.h:118
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
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
void progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:175
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:435
void * edata
Driver-specific data.
Definition: email.h:111
char * path
Path of Email (for local Mailboxes)
Definition: email.h:92
#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
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
bool header_parsed
Definition: mdemail.h:37
Log at debug level 3.
Definition: logging.h:42
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:83
+ 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 687 of file mh.c.

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 }
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
void maildir_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free()
Definition: mdata.c:37
void mh_seq_free(struct MhSequences *mhs)
Free some sequences.
Definition: sequence.c:67
int maildir_move_to_mailbox(struct Mailbox *m, struct MdEmailArray *mda)
Copy the Maildir list to the Mailbox.
Definition: shared.c:75
#define _(a)
Definition: message.h:28
Progress tracks elements, according to $read_inc
Definition: lib.h:46
int mh_seq_read(struct MhSequences *mhs, const char *path)
Read a set of MH sequences.
Definition: sequence.c:381
void maildirarray_clear(struct MdEmailArray *mda)
Free a Maildir array.
Definition: mdemail.c:64
Set of MH sequence numbers.
Definition: sequence.h:40
A Progress Bar.
Definition: progress.c:47
void(* mdata_free)(void **ptr)
Free the private data attached to the Mailbox.
Definition: mailbox.h:146
void mh_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
This function does the second parsing pass.
Definition: mh.c:607
void mh_update_mtime(struct Mailbox *m)
Update our record of the Maildir modification time.
Definition: mh.c:476
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:54
void * mdata
Driver specific data.
Definition: mailbox.h:136
mode_t mh_umask
Definition: mdata.h:37
#define PATH_MAX
Definition: mutt.h:40
void mh_update_maildir(struct MdEmailArray *mda, struct MhSequences *mhs)
Update our record of flags.
Definition: mh.c:260
char msg[1024]
Message to display.
Definition: progress.c:50
bool verbose
Display status messages?
Definition: mailbox.h:118
mode_t mh_umask(struct Mailbox *m)
Create a umask from the mailbox directory.
Definition: shared.c:52
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:228
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:246
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
Maildir-specific Mailbox data -.
Definition: mdata.h:34
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:83
struct MaildirMboxData * maildir_mdata_get(struct Mailbox *m)
Get the private data for this Mailbox.
Definition: mdata.c:58
+ Here is the call graph for this function:
+ Here is the caller 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 751 of file mh.c.

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 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
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
The envelope/body of an email.
Definition: email.h:37
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
bool changed
Email has been edited.
Definition: email.h:48
Container for Accounts, Notifications.
Definition: neomutt.h:36
int mh_sync_message(struct Mailbox *m, int msgno)
Sync an email to an MH folder.
Definition: mh.c:450
#define PATH_MAX
Definition: mutt.h:40
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:637
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
bool deleted
Email is deleted.
Definition: email.h:45
char * path
Path of Email (for local Mailboxes)
Definition: email.h:92
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
int msgno
Number displayed to the user.
Definition: email.h:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function: