NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
maildir.c File Reference

Maildir local mailbox type. More...

#include "config.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 <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <utime.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 "hcache/lib.h"
#include "notmuch/lib.h"
+ Include dependency graph for maildir.c:

Go to the source code of this file.

Macros

#define MMC_NO_DIRS   0
 No directories changed. More...
 
#define MMC_NEW_DIR   (1 << 0)
 'new' directory changed More...
 
#define MMC_CUR_DIR   (1 << 1)
 'cur' directory changed More...
 

Functions

static void maildir_check_dir (struct Mailbox *m, const char *dir_name, bool check_new, bool check_stats)
 Check for new mail / mail counts. More...
 
static int ch_compare (const void *a, const void *b)
 qsort callback to sort characters More...
 
void maildir_gen_flags (char *dest, size_t destlen, struct Email *e)
 Generate the Maildir flags for an email. More...
 
int maildir_commit_message (struct Mailbox *m, struct Message *msg, struct Email *e)
 Commit a message to a maildir folder. More...
 
int maildir_rewrite_message (struct Mailbox *m, int msgno)
 Sync a message in an MH folder. More...
 
int maildir_sync_message (struct Mailbox *m, int msgno)
 Sync an email to a Maildir folder. More...
 
void maildir_update_mtime (struct Mailbox *m)
 Update our record of the Maildir modification time. More...
 
static int maildir_cmp_inode (const void *a, const void *b)
 Compare two Maildirs by inode number - Implements sort_t. More...
 
int maildir_parse_dir (struct Mailbox *m, struct MdEmailArray *mda, const char *subdir, struct Progress *progress)
 Read a Maildir mailbox. More...
 
size_t maildir_hcache_keylen (const char *fn)
 Calculate the length of the Maildir path. More...
 
void maildir_delayed_parsing (struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
 This function does the second parsing pass. More...
 
int maildir_read_dir (struct Mailbox *m, const char *subdir)
 Read a Maildir style mailbox. More...
 
void maildir_canon_filename (struct Buffer *dest, const char *src)
 Generate the canonical filename for a Maildir folder. More...
 
static FILE * maildir_open_find_message_dir (const char *folder, const char *unique, const char *subfolder, char **newname)
 Find a message in a maildir folder. More...
 
void maildir_parse_flags (struct Email *e, const char *path)
 Parse Maildir file flags. More...
 
struct Emailmaildir_parse_stream (enum MailboxType type, FILE *fp, const char *fname, bool is_old, struct Email *e)
 Parse a Maildir message. More...
 
struct Emailmaildir_parse_message (enum MailboxType type, const char *fname, bool is_old, struct Email *e)
 Actually parse a maildir message. More...
 
bool maildir_sync_mailbox_message (struct Mailbox *m, int msgno, struct HeaderCache *hc)
 Save changes to the mailbox. More...
 
FILE * maildir_open_find_message (const char *folder, const char *msg, char **newname)
 Find a new. More...
 
int maildir_check_empty (const char *path)
 Is the mailbox empty. More...
 
bool maildir_ac_owns_path (struct Account *a, const char *path)
 Check whether an Account own a Mailbox path - Implements MxOps::ac_owns_path() -. More...
 
bool maildir_ac_add (struct Account *a, struct Mailbox *m)
 Add a Mailbox to an Account - Implements MxOps::ac_add() -. More...
 
static enum MxOpenReturns maildir_mbox_open (struct Mailbox *m)
 Open a Mailbox - Implements MxOps::mbox_open() -. More...
 
static bool maildir_mbox_open_append (struct Mailbox *m, OpenMailboxFlags flags)
 Open a Mailbox for appending - Implements MxOps::mbox_open_append() -. More...
 
enum MxStatus maildir_mbox_check (struct Mailbox *m)
 Check for new mail - Implements MxOps::mbox_check() -This function handles arrival of new mail and reopening of maildir folders. More...
 
static enum MxStatus maildir_mbox_check_stats (struct Mailbox *m, uint8_t flags)
 Check the Mailbox statistics - Implements MxOps::mbox_check_stats() -. More...
 
enum MxStatus maildir_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -. More...
 
enum MxStatus maildir_mbox_close (struct Mailbox *m)
 Close a Mailbox - Implements MxOps::mbox_close() -. More...
 
static bool maildir_msg_open (struct Mailbox *m, struct Message *msg, int msgno)
 Open an email message in a Mailbox - Implements MxOps::msg_open() -. More...
 
bool maildir_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 a maildir folder. More...
 
static int maildir_msg_commit (struct Mailbox *m, struct Message *msg)
 Save changes to an email - Implements MxOps::msg_commit() -. More...
 
int maildir_msg_close (struct Mailbox *m, struct Message *msg)
 Close an email - Implements MxOps::msg_close() -. More...
 
static int maildir_msg_save_hcache (struct Mailbox *m, struct Email *e)
 Save message to the header cache - Implements MxOps::msg_save_hcache() -. More...
 
int maildir_path_canon (char *buf, size_t buflen)
 Canonicalise a Mailbox path - Implements MxOps::path_canon() -. More...
 
int maildir_path_parent (char *buf, size_t buflen)
 Find the parent of a Mailbox path - Implements MxOps::path_parent() -. More...
 
int maildir_path_pretty (char *buf, size_t buflen, const char *folder)
 Abbreviate a Mailbox path - Implements MxOps::path_pretty() -. More...
 
static enum MailboxType maildir_path_probe (const char *path, const struct stat *st)
 Is this a Maildir Mailbox? - Implements MxOps::path_probe() -. More...
 

Variables

struct MxOps MxMaildirOps
 Maildir Mailbox - Implements MxOps -. More...
 

Detailed Description

Maildir 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 maildir.c.

Macro Definition Documentation

◆ MMC_NO_DIRS

#define MMC_NO_DIRS   0

No directories changed.

Definition at line 72 of file maildir.c.

◆ MMC_NEW_DIR

#define MMC_NEW_DIR   (1 << 0)

'new' directory changed

Definition at line 73 of file maildir.c.

◆ MMC_CUR_DIR

#define MMC_CUR_DIR   (1 << 1)

'cur' directory changed

Definition at line 74 of file maildir.c.

Function Documentation

◆ maildir_check_dir()

static void maildir_check_dir ( struct Mailbox m,
const char *  dir_name,
bool  check_new,
bool  check_stats 
)
static

Check for new mail / mail counts.

Parameters
mMailbox to check
dir_namePath to Mailbox
check_newif true, check for new mail
check_statsif true, count total, new, and flagged messages

Checks the specified maildir subdir (cur or new) for new mail or mail counts.

Definition at line 85 of file maildir.c.

87 {
88  DIR *dirp = NULL;
89  struct dirent *de = NULL;
90  char *p = NULL;
91  struct stat sb;
92 
93  struct Buffer *path = mutt_buffer_pool_get();
94  struct Buffer *msgpath = mutt_buffer_pool_get();
95  mutt_buffer_printf(path, "%s/%s", mailbox_path(m), dir_name);
96 
97  /* when $mail_check_recent is set, if the new/ directory hasn't been modified since
98  * the user last exited the m, then we know there is no recent mail. */
99  const bool c_mail_check_recent =
100  cs_subset_bool(NeoMutt->sub, "mail_check_recent");
101  if (check_new && c_mail_check_recent)
102  {
103  if ((stat(mutt_buffer_string(path), &sb) == 0) &&
105  {
106  check_new = false;
107  }
108  }
109 
110  if (!(check_new || check_stats))
111  goto cleanup;
112 
113  dirp = opendir(mutt_buffer_string(path));
114  if (!dirp)
115  {
116  m->type = MUTT_UNKNOWN;
117  goto cleanup;
118  }
119 
120  while ((de = readdir(dirp)))
121  {
122  if (*de->d_name == '.')
123  continue;
124 
125  p = strstr(de->d_name, ":2,");
126  if (p && strchr(p + 3, 'T'))
127  continue;
128 
129  if (check_stats)
130  {
131  m->msg_count++;
132  if (p && strchr(p + 3, 'F'))
133  m->msg_flagged++;
134  }
135  if (!p || !strchr(p + 3, 'S'))
136  {
137  if (check_stats)
138  m->msg_unread++;
139  if (check_new)
140  {
141  if (c_mail_check_recent)
142  {
143  mutt_buffer_printf(msgpath, "%s/%s", mutt_buffer_string(path), de->d_name);
144  /* ensure this message was received since leaving this m */
145  if ((stat(mutt_buffer_string(msgpath), &sb) == 0) &&
147  {
148  continue;
149  }
150  }
151  m->has_new = true;
152  check_new = false;
153  m->msg_new++;
154  if (!check_stats)
155  break;
156  }
157  }
158  }
159 
160  closedir(dirp);
161 
162 cleanup:
164  mutt_buffer_pool_release(&msgpath);
165 }
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
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
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
File/dir&#39;s ctime - creation time.
Definition: file.h:64
int msg_unread
Number of unread messages.
Definition: mailbox.h:92
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:93
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
Mailbox wasn&#39;t recognised.
Definition: mailbox.h:47
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
Container for Accounts, Notifications.
Definition: neomutt.h:36
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
bool has_new
Mailbox has new mail.
Definition: mailbox.h:88
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
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
int msg_new
Number of new messages.
Definition: mailbox.h:95
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:

◆ ch_compare()

static int ch_compare ( const void *  a,
const void *  b 
)
static

qsort callback to sort characters

Parameters
aFirst character to compare
bSecond character to compare
Return values
-1a precedes b
0a and b are identical
1b precedes a

Definition at line 175 of file maildir.c.

176 {
177  return (int) (*((const char *) a) - *((const char *) b));
178 }
+ Here is the caller graph for this function:

◆ maildir_gen_flags()

void maildir_gen_flags ( char *  dest,
size_t  destlen,
struct Email e 
)

Generate the Maildir flags for an email.

Parameters
destBuffer for the result
destlenLength of buffer
eEmail

Definition at line 186 of file maildir.c.

187 {
188  *dest = '\0';
189 
190  const char *flags = NULL;
191 
193  if (edata)
194  flags = edata->maildir_flags;
195 
196  /* The maildir specification requires that all files in the cur
197  * subdirectory have the :unique string appended, regardless of whether
198  * or not there are any flags. If .old is set, we know that this message
199  * will end up in the cur directory, so we include it in the following
200  * test even though there is no associated flag. */
201 
202  if (e->flagged || e->replied || e->read || e->deleted || e->old || flags)
203  {
204  char tmp[1024];
205  snprintf(tmp, sizeof(tmp), "%s%s%s%s%s", e->flagged ? "F" : "", e->replied ? "R" : "",
206  e->read ? "S" : "", e->deleted ? "T" : "", NONULL(flags));
207  if (flags)
208  qsort(tmp, strlen(tmp), 1, ch_compare);
209  snprintf(dest, destlen, ":2,%s", tmp);
210  }
211 }
#define NONULL(x)
Definition: string2.h:37
Maildir-specific Email data -.
Definition: edata.h:33
bool read
Email is read.
Definition: email.h:51
bool old
Email is seen, but unread.
Definition: email.h:50
static int ch_compare(const void *a, const void *b)
qsort callback to sort characters
Definition: maildir.c:175
bool flagged
Marked important?
Definition: email.h:43
bool deleted
Email is deleted.
Definition: email.h:45
void * edata
Driver-specific data.
Definition: email.h:111
bool replied
Email has been replied to.
Definition: email.h:54
struct MaildirEmailData * maildir_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:64
char * maildir_flags
Unknown Maildir flags.
Definition: edata.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_commit_message()

int maildir_commit_message ( struct Mailbox m,
struct Message msg,
struct Email e 
)

Commit a message to a maildir folder.

Parameters
mMailbox
msgMessage to commit
eEmail
Return values
0Success
-1Failure

msg->path contains the file name of a file in tmp/. We take the flags from this file's name.

m is the mail folder we commit to.

e is a header structure to which we write the message's new file name. This is used in the mh and maildir folder sync routines. When this routine is invoked from mx_msg_commit(), e is NULL.

msg->path looks like this:

tmp/{cur,new}.neomutt-HOSTNAME-PID-COUNTER:flags

See also maildir_msg_open_new().

Definition at line 237 of file maildir.c.

238 {
239  char subdir[4];
240  char suffix[16];
241  int rc = 0;
242 
243  if (mutt_file_fsync_close(&msg->fp))
244  {
245  mutt_perror(_("Could not flush message to disk"));
246  return -1;
247  }
248 
249  /* extract the subdir */
250  char *s = strrchr(msg->path, '/') + 1;
251  mutt_str_copy(subdir, s, 4);
252 
253  /* extract the flags */
254  s = strchr(s, ':');
255  if (s)
256  mutt_str_copy(suffix, s, sizeof(suffix));
257  else
258  suffix[0] = '\0';
259 
260  /* construct a new file name. */
261  struct Buffer *path = mutt_buffer_pool_get();
262  struct Buffer *full = mutt_buffer_pool_get();
263  while (true)
264  {
265  mutt_buffer_printf(path, "%s/%lld.R%" PRIu64 ".%s%s", subdir,
266  (long long) mutt_date_epoch(), mutt_rand64(),
267  NONULL(ShortHostname), suffix);
268  mutt_buffer_printf(full, "%s/%s", mailbox_path(m), mutt_buffer_string(path));
269 
270  mutt_debug(LL_DEBUG2, "renaming %s to %s\n", msg->path, mutt_buffer_string(full));
271 
272  if (mutt_file_safe_rename(msg->path, mutt_buffer_string(full)) == 0)
273  {
274  /* Adjust the mtime on the file to match the time at which this
275  * message was received. Currently this is only set when copying
276  * messages between mailboxes, so we test to ensure that it is
277  * actually set. */
278  if (msg->received)
279  {
280  struct utimbuf ut;
281  int rc_utime;
282 
283  ut.actime = msg->received;
284  ut.modtime = msg->received;
285  do
286  {
287  rc_utime = utime(mutt_buffer_string(full), &ut);
288  } while ((rc_utime == -1) && (errno == EINTR));
289  if (rc_utime == -1)
290  {
291  mutt_perror(
292  _("maildir_commit_message(): unable to set time on file"));
293  rc = -1;
294  goto cleanup;
295  }
296  }
297 
298 #ifdef USE_NOTMUCH
299  if (m->type == MUTT_NOTMUCH)
300  nm_update_filename(m, e->path, mutt_buffer_string(full), e);
301 #endif
302  if (e)
305  FREE(&msg->path);
306 
307  goto cleanup;
308  }
309  else if (errno != EEXIST)
310  {
312  rc = -1;
313  goto cleanup;
314  }
315  }
316 
317 cleanup:
320 
321  return rc;
322 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
#define NONULL(x)
Definition: string2.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:169
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
#define _(a)
Definition: message.h:28
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
#define mutt_perror(...)
Definition: logging.h:89
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
int nm_update_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Change the filename.
Definition: notmuch.c:1747
Log at debug level 2.
Definition: logging.h:41
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: random.c:130
WHERE char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:46
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:54
char * committed_path
the final path generated by mx_msg_commit()
Definition: mxapi.h:45
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
#define FREE(x)
Definition: memory.h:40
time_t received
the time at which this message was received
Definition: mxapi.h:54
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:

◆ maildir_rewrite_message()

int maildir_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 331 of file maildir.c.

332 {
333  if (!m || !m->emails || (msgno >= m->msg_count))
334  return -1;
335 
336  struct Email *e = m->emails[msgno];
337  if (!e)
338  return -1;
339 
340  bool restore = true;
341 
342  long old_body_offset = e->body->offset;
343  long old_body_length = e->body->length;
344  long old_hdr_lines = e->lines;
345 
346  struct Message *dest = mx_msg_open_new(m, e, MUTT_MSG_NO_FLAGS);
347  if (!dest)
348  return -1;
349 
350  int rc = mutt_copy_message(dest->fp, m, e, dest, MUTT_CM_UPDATE,
351  CH_UPDATE | CH_UPDATE_LEN, 0);
352  if (rc == 0)
353  {
354  char oldpath[PATH_MAX];
355  char partpath[PATH_MAX];
356  snprintf(oldpath, sizeof(oldpath), "%s/%s", mailbox_path(m), e->path);
357  mutt_str_copy(partpath, e->path, sizeof(partpath));
358 
359  rc = maildir_commit_message(m, dest, e);
360 
361  if (rc == 0)
362  {
363  unlink(oldpath);
364  restore = false;
365  }
366  }
367  mx_msg_close(m, &dest);
368 
369  if ((rc == -1) && restore)
370  {
371  e->body->offset = old_body_offset;
372  e->body->length = old_body_length;
373  e->lines = old_hdr_lines;
374  }
375 
376  mutt_body_free(&e->body->parts);
377  return rc;
378 }
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 maildir_commit_message(struct Mailbox *m, struct Message *msg, struct Email *e)
Commit a message to a maildir folder.
Definition: maildir.c:237
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
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 * 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
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_sync_message()

int maildir_sync_message ( struct Mailbox m,
int  msgno 
)

Sync an email to a Maildir folder.

Parameters
mMailbox
msgnoIndex number
Return values
0Success
-1Error

Definition at line 387 of file maildir.c.

388 {
389  if (!m || !m->emails || (msgno >= m->msg_count))
390  return -1;
391 
392  struct Email *e = m->emails[msgno];
393  if (!e)
394  return -1;
395 
396  struct Buffer *newpath = NULL;
397  struct Buffer *partpath = NULL;
398  struct Buffer *fullpath = NULL;
399  struct Buffer *oldpath = NULL;
400  char suffix[16];
401  int rc = 0;
402 
403  /* TODO: why the e->env check? */
404  if (e->attach_del || (e->env && e->env->changed))
405  {
406  /* when doing attachment deletion/rethreading, fall back to the MH case. */
407  if (maildir_rewrite_message(m, msgno) != 0)
408  return -1;
409  /* TODO: why the env check? */
410  if (e->env)
411  e->env->changed = 0;
412  }
413  else
414  {
415  /* we just have to rename the file. */
416 
417  char *p = strrchr(e->path, '/');
418  if (!p)
419  {
420  mutt_debug(LL_DEBUG1, "%s: unable to find subdir!\n", e->path);
421  return -1;
422  }
423  p++;
424  newpath = mutt_buffer_pool_get();
425  partpath = mutt_buffer_pool_get();
426  fullpath = mutt_buffer_pool_get();
427  oldpath = mutt_buffer_pool_get();
428 
429  mutt_buffer_strcpy(newpath, p);
430 
431  /* kill the previous flags */
432  p = strchr(newpath->data, ':');
433  if (p)
434  {
435  *p = '\0';
436  newpath->dptr = p; /* fix buffer up, just to be safe */
437  }
438 
439  maildir_gen_flags(suffix, sizeof(suffix), e);
440 
441  mutt_buffer_printf(partpath, "%s/%s%s", (e->read || e->old) ? "cur" : "new",
442  mutt_buffer_string(newpath), suffix);
443  mutt_buffer_printf(fullpath, "%s/%s", mailbox_path(m), mutt_buffer_string(partpath));
444  mutt_buffer_printf(oldpath, "%s/%s", mailbox_path(m), e->path);
445 
446  if (mutt_str_equal(mutt_buffer_string(fullpath), mutt_buffer_string(oldpath)))
447  {
448  /* message hasn't really changed */
449  goto cleanup;
450  }
451 
452  /* record that the message is possibly marked as trashed on disk */
453  e->trash = e->deleted;
454 
455  if (rename(mutt_buffer_string(oldpath), mutt_buffer_string(fullpath)) != 0)
456  {
457  mutt_perror("rename");
458  rc = -1;
459  goto cleanup;
460  }
461  mutt_str_replace(&e->path, mutt_buffer_string(partpath));
462  }
463 
464 cleanup:
465  mutt_buffer_pool_release(&newpath);
466  mutt_buffer_pool_release(&partpath);
467  mutt_buffer_pool_release(&fullpath);
468  mutt_buffer_pool_release(&oldpath);
469 
470  return rc;
471 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
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
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
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
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
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
#define mutt_perror(...)
Definition: logging.h:89
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:88
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
int maildir_rewrite_message(struct Mailbox *m, int msgno)
Sync a message in an MH folder.
Definition: maildir.c:331
bool read
Email is read.
Definition: email.h:51
bool old
Email is seen, but unread.
Definition: email.h:50
struct Envelope * env
Envelope information.
Definition: email.h:90
bool trash
Message is marked as trashed on disk (used by the maildir_trash option)
Definition: email.h:60
void maildir_gen_flags(char *dest, size_t destlen, struct Email *e)
Generate the Maildir flags for an email.
Definition: maildir.c:186
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
Log at debug level 1.
Definition: logging.h:40
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
bool deleted
Email is deleted.
Definition: email.h:45
char * path
Path of Email (for local Mailboxes)
Definition: email.h:92
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:

◆ maildir_update_mtime()

void maildir_update_mtime ( struct Mailbox m)

Update our record of the Maildir modification time.

Parameters
mMailbox

Definition at line 477 of file maildir.c.

478 {
479  char buf[PATH_MAX];
480  struct stat st;
482 
483  snprintf(buf, sizeof(buf), "%s/%s", mailbox_path(m), "cur");
484  if (stat(buf, &st) == 0)
486  snprintf(buf, sizeof(buf), "%s/%s", mailbox_path(m), "new");
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
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:

◆ maildir_cmp_inode()

static int maildir_cmp_inode ( const void *  a,
const void *  b 
)
static

Compare two Maildirs by inode number - Implements sort_t.

Definition at line 495 of file maildir.c.

496 {
497  const struct MdEmail *ma = *(struct MdEmail **) a;
498  const struct MdEmail *mb = *(struct MdEmail **) b;
499 
500  return ma->inode - mb->inode;
501 }
A Maildir Email helper.
Definition: mdemail.h:33
ino_t inode
Definition: mdemail.h:38
+ Here is the caller graph for this function:

◆ maildir_parse_dir()

int maildir_parse_dir ( struct Mailbox m,
struct MdEmailArray *  mda,
const char *  subdir,
struct Progress progress 
)

Read a Maildir mailbox.

Parameters
[in]mMailbox
[out]mdaArray for results
[in]subdirSubdirectory, e.g. 'new'
[in]progressProgress bar
Return values
0Success
-1Error
-2Aborted

Definition at line 513 of file maildir.c.

515 {
516  struct dirent *de = NULL;
517  int rc = 0;
518  bool is_old = false;
519  struct MdEmail *entry = NULL;
520  struct Email *e = NULL;
521 
522  struct Buffer *buf = mutt_buffer_pool_get();
523 
524  mutt_buffer_printf(buf, "%s/%s", mailbox_path(m), subdir);
525  const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
526  is_old = c_mark_old ? mutt_str_equal("cur", subdir) : false;
527 
528  DIR *dirp = opendir(mutt_buffer_string(buf));
529  if (!dirp)
530  {
531  rc = -1;
532  goto cleanup;
533  }
534 
535  while (((de = readdir(dirp))) && !SigInt)
536  {
537  if (*de->d_name == '.')
538  continue;
539 
540  /* FOO - really ignore the return value? */
541  mutt_debug(LL_DEBUG2, "queueing %s\n", de->d_name);
542 
543  e = email_new();
544  e->edata = maildir_edata_new();
546 
547  e->old = is_old;
548  maildir_parse_flags(e, de->d_name);
549 
550  if (m->verbose && progress)
551  progress_update(progress, ARRAY_SIZE(mda) + 1, -1);
552 
553  mutt_buffer_printf(buf, "%s/%s", subdir, de->d_name);
554  e->path = mutt_buffer_strdup(buf);
555 
556  entry = maildir_entry_new();
557  entry->email = e;
558  entry->inode = de->d_ino;
559  ARRAY_ADD(mda, entry);
560  }
561 
562  closedir(dirp);
563 
564  if (SigInt)
565  {
566  SigInt = false;
567  return -2; /* action aborted */
568  }
569 
571 
572 cleanup:
574 
575  return rc;
576 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
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
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
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
void maildir_parse_flags(struct Email *e, const char *path)
Parse Maildir file flags.
Definition: maildir.c:811
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
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
Container for Accounts, Notifications.
Definition: neomutt.h:36
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 old
Email is seen, but unread.
Definition: email.h:50
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
static int maildir_cmp_inode(const void *a, const void *b)
Compare two Maildirs by inode number - Implements sort_t.
Definition: maildir.c:495
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
ino_t inode
Definition: mdemail.h:38
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
#define ARRAY_SORT(head, fn)
Sort an array.
Definition: array.h:271
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
#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:

◆ maildir_hcache_keylen()

size_t maildir_hcache_keylen ( const char *  fn)

Calculate the length of the Maildir path.

Parameters
fnFile name
Return values
numLength in bytes
Note
This length excludes the flags, which will vary

Definition at line 585 of file maildir.c.

586 {
587  const char *p = strrchr(fn, ':');
588  return p ? (size_t) (p - fn) : mutt_str_len(fn);
589 }
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_delayed_parsing()

void maildir_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 597 of file maildir.c.

599 {
600  char fn[PATH_MAX];
601 
602 #ifdef USE_HCACHE
603  const char *const c_header_cache =
604  cs_subset_path(NeoMutt->sub, "header_cache");
605  struct HeaderCache *hc = mutt_hcache_open(c_header_cache, mailbox_path(m), NULL);
606 #endif
607 
608  struct MdEmail *md = NULL;
609  struct MdEmail **mdp = NULL;
610  ARRAY_FOREACH(mdp, mda)
611  {
612  md = *mdp;
613  if (!md || !md->email || md->header_parsed)
614  continue;
615 
616  if (m->verbose && progress)
617  progress_update(progress, ARRAY_FOREACH_IDX, -1);
618 
619  snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
620 
621 #ifdef USE_HCACHE
622  struct stat lastchanged = { 0 };
623  int rc = 0;
624  const bool c_maildir_header_cache_verify =
625  cs_subset_bool(NeoMutt->sub, "maildir_header_cache_verify");
626  if (c_maildir_header_cache_verify)
627  {
628  rc = stat(fn, &lastchanged);
629  }
630 
631  const char *key = md->email->path + 3;
632  size_t keylen = maildir_hcache_keylen(key);
633  struct HCacheEntry hce = mutt_hcache_fetch(hc, key, keylen, 0);
634 
635  if (hce.email && (rc == 0) && (lastchanged.st_mtime <= hce.uidvalidity))
636  {
637  hce.email->edata = maildir_edata_new();
639  hce.email->old = md->email->old;
640  hce.email->path = mutt_str_dup(md->email->path);
641  email_free(&md->email);
642  md->email = hce.email;
643  maildir_parse_flags(md->email, fn);
644  }
645  else
646 #endif
647  {
648  if (maildir_parse_message(m->type, fn, md->email->old, md->email))
649  {
650  md->header_parsed = true;
651 #ifdef USE_HCACHE
652  key = md->email->path + 3;
653  keylen = maildir_hcache_keylen(key);
654  mutt_hcache_store(hc, key, keylen, md->email, 0);
655 #endif
656  }
657  else
658  email_free(&md->email);
659  }
660  }
661 #ifdef USE_HCACHE
662  mutt_hcache_close(hc);
663 #endif
664 }
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
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
void maildir_parse_flags(struct Email *e, const char *path)
Parse Maildir file flags.
Definition: maildir.c:811
#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
Container for Accounts, Notifications.
Definition: neomutt.h:36
size_t maildir_hcache_keylen(const char *fn)
Calculate the length of the Maildir path.
Definition: maildir.c:585
A Maildir Email helper.
Definition: mdemail.h:33
bool old
Email is seen, but unread.
Definition: email.h:50
struct Email * maildir_parse_message(enum MailboxType type, const char *fname, bool is_old, struct Email *e)
Actually parse a maildir message.
Definition: maildir.c:926
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
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
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
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
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_read_dir()

int maildir_read_dir ( struct Mailbox m,
const char *  subdir 
)

Read a Maildir style mailbox.

Parameters
mMailbox
subdirSubdir of the maildir mailbox to read from
Return values
0Success
-1Failure

Definition at line 673 of file maildir.c.

674 {
675  if (!m)
676  return -1;
677 
678  struct Progress *progress = NULL;
679 
680  if (m->verbose)
681  {
682  char msg[PATH_MAX];
683  snprintf(msg, sizeof(msg), _("Scanning %s..."), mailbox_path(m));
684  progress = progress_new(msg, MUTT_PROGRESS_READ, 0);
685  }
686 
688  if (!mdata)
689  {
690  mdata = maildir_mdata_new();
691  m->mdata = mdata;
693  }
694 
695  struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
696  int rc = maildir_parse_dir(m, &mda, subdir, progress);
697  progress_free(&progress);
698  if (rc < 0)
699  return -1;
700 
701  if (m->verbose)
702  {
703  char msg[PATH_MAX];
704  snprintf(msg, sizeof(msg), _("Reading %s..."), mailbox_path(m));
705  progress = progress_new(msg, MUTT_PROGRESS_READ, ARRAY_SIZE(&mda));
706  }
707  maildir_delayed_parsing(m, &mda, progress);
708  progress_free(&progress);
709 
710  maildir_move_to_mailbox(m, &mda);
711 
712  if (!mdata->mh_umask)
713  mdata->mh_umask = mh_umask(m);
714 
715  return 0;
716 }
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
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
A Progress Bar.
Definition: progress.c:47
void(* mdata_free)(void **ptr)
Free the private data attached to the Mailbox.
Definition: mailbox.h:146
#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 maildir_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
This function does the second parsing pass.
Definition: maildir.c:597
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
struct MaildirMboxData * maildir_mdata_new(void)
Create a new MaildirMboxData object.
Definition: mdata.c:47
int maildir_parse_dir(struct Mailbox *m, struct MdEmailArray *mda, const char *subdir, struct Progress *progress)
Read a Maildir mailbox.
Definition: maildir.c:513
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:

◆ maildir_canon_filename()

void maildir_canon_filename ( struct Buffer dest,
const char *  src 
)

Generate the canonical filename for a Maildir folder.

Parameters
destBuffer for the result
srcBuffer containing source filename
Note
maildir filename is defined as: <base filename>:2,<flags> but <base filename> may contain additional comma separated fields.

Definition at line 727 of file maildir.c.

728 {
729  if (!dest || !src)
730  return;
731 
732  char *t = strrchr(src, '/');
733  if (t)
734  src = t + 1;
735 
736  mutt_buffer_strcpy(dest, src);
737  char *u = strpbrk(dest->data, ",:");
738  if (u)
739  {
740  *u = '\0';
741  dest->dptr = u;
742  }
743 }
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_open_find_message_dir()

static FILE* maildir_open_find_message_dir ( const char *  folder,
const char *  unique,
const char *  subfolder,
char **  newname 
)
static

Find a message in a maildir folder.

Parameters
[in]folderBase folder
[in]uniqueUnique part of filename
[in]subfolderSubfolder to search, e.g. 'cur'
[out]newnameFile's new name
Return values
ptrFile handle

These functions try to find a message in a maildir folder when it has moved under our feet. Note that this code is rather expensive, but then again, it's called rarely.

Definition at line 757 of file maildir.c.

759 {
760  struct Buffer *dir = mutt_buffer_pool_get();
761  struct Buffer *tunique = mutt_buffer_pool_get();
762  struct Buffer *fname = mutt_buffer_pool_get();
763 
764  struct dirent *de = NULL;
765 
766  FILE *fp = NULL;
767  int oe = ENOENT;
768 
769  mutt_buffer_printf(dir, "%s/%s", folder, subfolder);
770 
771  DIR *dp = opendir(mutt_buffer_string(dir));
772  if (!dp)
773  {
774  errno = ENOENT;
775  goto cleanup;
776  }
777 
778  while ((de = readdir(dp)))
779  {
780  maildir_canon_filename(tunique, de->d_name);
781 
782  if (mutt_str_equal(mutt_buffer_string(tunique), unique))
783  {
784  mutt_buffer_printf(fname, "%s/%s/%s", folder, subfolder, de->d_name);
785  fp = fopen(mutt_buffer_string(fname), "r");
786  oe = errno;
787  break;
788  }
789  }
790 
791  closedir(dp);
792 
793  if (newname && fp)
794  *newname = mutt_buffer_strdup(fname);
795 
796  errno = oe;
797 
798 cleanup:
800  mutt_buffer_pool_release(&tunique);
801  mutt_buffer_pool_release(&fname);
802 
803  return fp;
804 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
void maildir_canon_filename(struct Buffer *dest, const char *src)
Generate the canonical filename for a Maildir folder.
Definition: maildir.c:727
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
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
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_parse_flags()

void maildir_parse_flags ( struct Email e,
const char *  path 
)

Parse Maildir file flags.

Parameters
eEmail
pathPath to email file

Definition at line 811 of file maildir.c.

812 {
813  char *q = NULL;
814 
815  e->flagged = false;
816  e->read = false;
817  e->replied = false;
818 
820 
821  char *p = strrchr(path, ':');
822  if (p && mutt_str_startswith(p + 1, "2,"))
823  {
824  p += 3;
825 
826  mutt_str_replace(&edata->maildir_flags, p);
827  q = edata->maildir_flags;
828 
829  while (*p)
830  {
831  switch (*p)
832  {
833  case 'F':
834  e->flagged = true;
835  break;
836 
837  case 'R': /* replied */
838  e->replied = true;
839  break;
840 
841  case 'S': /* seen */
842  e->read = true;
843  break;
844 
845  case 'T': /* trashed */
846  {
847  const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
848  if (!e->flagged || !c_flag_safe)
849  {
850  e->trash = true;
851  e->deleted = true;
852  }
853  break;
854  }
855 
856  default:
857  *q++ = *p;
858  break;
859  }
860  p++;
861  }
862  }
863 
864  if (q == edata->maildir_flags)
865  FREE(&edata->maildir_flags);
866  else if (q)
867  *q = '\0';
868 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
Container for Accounts, Notifications.
Definition: neomutt.h:36
Maildir-specific Email data -.
Definition: edata.h:33
bool read
Email is read.
Definition: email.h:51
bool trash
Message is marked as trashed on disk (used by the maildir_trash option)
Definition: email.h:60
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
bool flagged
Marked important?
Definition: email.h:43
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
bool deleted
Email is deleted.
Definition: email.h:45
void * edata
Driver-specific data.
Definition: email.h:111
bool replied
Email has been replied to.
Definition: email.h:54
char * path
Path of Email (for local Mailboxes)
Definition: email.h:92
#define FREE(x)
Definition: memory.h:40
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
struct MaildirEmailData * maildir_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:64
char * maildir_flags
Unknown Maildir flags.
Definition: edata.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_parse_stream()

struct Email* maildir_parse_stream ( enum MailboxType  type,
FILE *  fp,
const char *  fname,
bool  is_old,
struct Email e 
)

Parse a Maildir message.

Parameters
typeMailbox type, e.g. MUTT_MAILDIR
fpMessage file handle
fnameMessage filename
is_oldtrue, if the email is old (read)
eEmail
Return values
ptrPopulated Email

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

Definition at line 882 of file maildir.c.

884 {
885  if (!e)
886  {
887  e = email_new();
888  e->edata = maildir_edata_new();
890  }
891  e->env = mutt_rfc822_read_header(fp, e, false, false);
892 
893  struct stat st;
894  fstat(fileno(fp), &st);
895 
896  if (!e->received)
897  e->received = e->date_sent;
898 
899  /* always update the length since we have fresh information available. */
900  e->body->length = st.st_size - e->body->offset;
901 
902  e->index = -1;
903 
904  if (type == MUTT_MAILDIR)
905  {
906  /* maildir stores its flags in the filename, so ignore the
907  * flags in the header of the message */
908 
909  e->old = is_old;
910  maildir_parse_flags(e, fname);
911  }
912  return e;
913 }
struct Body * body
List of MIME parts.
Definition: email.h:91
void maildir_parse_flags(struct Email *e, const char *path)
Parse Maildir file flags.
Definition: maildir.c:811
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
bool old
Email is seen, but unread.
Definition: email.h:50
struct Envelope * env
Envelope information.
Definition: email.h:90
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:51
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:

◆ maildir_parse_message()

struct Email* maildir_parse_message ( enum MailboxType  type,
const char *  fname,
bool  is_old,
struct Email e 
)

Actually parse a maildir message.

Parameters
typeMailbox type, e.g. MUTT_MAILDIR
fnameMessage filename
is_oldtrue, if the email is old (read)
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 926 of file maildir.c.

928 {
929  FILE *fp = fopen(fname, "r");
930  if (!fp)
931  return NULL;
932 
933  e = maildir_parse_stream(type, fp, fname, is_old, e);
934  mutt_file_fclose(&fp);
935  return e;
936 }
struct Email * maildir_parse_stream(enum MailboxType type, FILE *fp, const char *fname, bool is_old, struct Email *e)
Parse a Maildir message.
Definition: maildir.c:882
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_sync_mailbox_message()

bool maildir_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
trueSuccess
falseError

Definition at line 946 of file maildir.c.

947 {
948  struct Email *e = m->emails[msgno];
949  if (!e)
950  return false;
951 
952  const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
953  if (e->deleted && !c_maildir_trash)
954  {
955  char path[PATH_MAX];
956  snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
957 #ifdef USE_HCACHE
958  if (hc)
959  {
960  const char *key = e->path + 3;
961  size_t keylen = maildir_hcache_keylen(key);
962  mutt_hcache_delete_record(hc, key, keylen);
963  }
964 #endif
965  unlink(path);
966  }
967  else if (e->changed || e->attach_del ||
968  ((c_maildir_trash || e->trash) && (e->deleted != e->trash)))
969  {
970  if (maildir_sync_message(m, msgno) == -1)
971  return false;
972  }
973 
974 #ifdef USE_HCACHE
975  if (hc && e->changed)
976  {
977  const char *key = e->path + 3;
978  size_t keylen = maildir_hcache_keylen(key);
979  mutt_hcache_store(hc, key, keylen, e, 0);
980  }
981 #endif
982 
983  return true;
984 }
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
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
size_t maildir_hcache_keylen(const char *fn)
Calculate the length of the Maildir path.
Definition: maildir.c:585
bool trash
Message is marked as trashed on disk (used by the maildir_trash option)
Definition: email.h:60
int maildir_sync_message(struct Mailbox *m, int msgno)
Sync an email to a Maildir folder.
Definition: maildir.c:387
#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:

◆ maildir_open_find_message()

FILE* maildir_open_find_message ( const char *  folder,
const char *  msg,
char **  newname 
)

Find a new.

Parameters
[in]folderMaildir path
[in]msgEmail path
[out]newnameNew name, if it has moved
Return values
ptrFile handle

Definition at line 993 of file maildir.c.

994 {
995  static unsigned int new_hits = 0, cur_hits = 0; /* simple dynamic optimization */
996 
997  struct Buffer *unique = mutt_buffer_pool_get();
998  maildir_canon_filename(unique, msg);
999 
1000  FILE *fp = maildir_open_find_message_dir(folder, mutt_buffer_string(unique),
1001  (new_hits > cur_hits) ? "new" : "cur", newname);
1002  if (fp || (errno != ENOENT))
1003  {
1004  if ((new_hits < UINT_MAX) && (cur_hits < UINT_MAX))
1005  {
1006  new_hits += ((new_hits > cur_hits) ? 1 : 0);
1007  cur_hits += ((new_hits > cur_hits) ? 0 : 1);
1008  }
1009 
1010  goto cleanup;
1011  }
1013  (new_hits > cur_hits) ? "cur" : "new", newname);
1014  if (fp || (errno != ENOENT))
1015  {
1016  if ((new_hits < UINT_MAX) && (cur_hits < UINT_MAX))
1017  {
1018  new_hits += ((new_hits > cur_hits) ? 0 : 1);
1019  cur_hits += ((new_hits > cur_hits) ? 1 : 0);
1020  }
1021 
1022  goto cleanup;
1023  }
1024 
1025  fp = NULL;
1026 
1027 cleanup:
1028  mutt_buffer_pool_release(&unique);
1029 
1030  return fp;
1031 }
void maildir_canon_filename(struct Buffer *dest, const char *src)
Generate the canonical filename for a Maildir folder.
Definition: maildir.c:727
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
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
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
static FILE * maildir_open_find_message_dir(const char *folder, const char *unique, const char *subfolder, char **newname)
Find a message in a maildir folder.
Definition: maildir.c:757
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_check_empty()

int maildir_check_empty ( const char *  path)

Is the mailbox empty.

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

Definition at line 1040 of file maildir.c.

1041 {
1042  DIR *dp = NULL;
1043  struct dirent *de = NULL;
1044  int rc = 1; /* assume empty until we find a message */
1045  char realpath[PATH_MAX];
1046  int iter = 0;
1047 
1048  /* Strategy here is to look for any file not beginning with a period */
1049 
1050  do
1051  {
1052  /* we do "cur" on the first iteration since it's more likely that we'll
1053  * find old messages without having to scan both subdirs */
1054  snprintf(realpath, sizeof(realpath), "%s/%s", path, (iter == 0) ? "cur" : "new");
1055  dp = opendir(realpath);
1056  if (!dp)
1057  return -1;
1058  while ((de = readdir(dp)))
1059  {
1060  if (*de->d_name != '.')
1061  {
1062  rc = 0;
1063  break;
1064  }
1065  }
1066  closedir(dp);
1067  iter++;
1068  } while (rc && iter < 2);
1069 
1070  return rc;
1071 }
#define PATH_MAX
Definition: mutt.h:40