NeoMutt  2022-04-29-145-g9b6a0e
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 <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 "mutt_globals.h"
#include "mx.h"
#include "monitor.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() -. 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() -. 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 73 of file maildir.c.

◆ MMC_NEW_DIR

#define MMC_NEW_DIR   (1 << 0)

'new' directory changed

Definition at line 74 of file maildir.c.

◆ MMC_CUR_DIR

#define MMC_CUR_DIR   (1 << 1)

'cur' directory changed

Definition at line 75 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 86 of file maildir.c.

88 {
89  DIR *dirp = NULL;
90  struct dirent *de = NULL;
91  char *p = NULL;
92  struct stat st = { 0 };
93 
94  struct Buffer *path = mutt_buffer_pool_get();
95  struct Buffer *msgpath = mutt_buffer_pool_get();
96  mutt_buffer_printf(path, "%s/%s", mailbox_path(m), dir_name);
97 
98  /* when $mail_check_recent is set, if the new/ directory hasn't been modified since
99  * the user last exited the m, then we know there is no recent mail. */
100  const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
101  if (check_new && c_mail_check_recent)
102  {
103  if ((stat(mutt_buffer_string(path), &st) == 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), &st) == 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 }
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:158
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
int mutt_file_stat_timespec_compare(struct stat *st, enum MuttStatType type, struct timespec *b)
Compare stat info with a time value.
Definition: file.c:1651
@ MUTT_STAT_CTIME
File/dir's ctime - creation time.
Definition: file.h:64
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:63
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:211
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:44
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
String manipulation buffer.
Definition: buffer.h:34
bool has_new
Mailbox has new mail.
Definition: mailbox.h:85
int msg_new
Number of new messages.
Definition: mailbox.h:92
int msg_count
Total number of messages.
Definition: mailbox.h:88
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:90
struct timespec last_visited
Time of last exit from this mailbox.
Definition: mailbox.h:105
int msg_unread
Number of unread messages.
Definition: mailbox.h:89
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:

◆ 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 }
struct MaildirEmailData * maildir_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:64
static int ch_compare(const void *a, const void *b)
qsort() callback to sort characters
Definition: maildir.c:175
#define NONULL(x)
Definition: string2.h:37
bool read
Email is read.
Definition: email.h:48
void * edata
Driver-specific data.
Definition: email.h:72
bool old
Email is seen, but unread.
Definition: email.h:47
bool flagged
Marked important?
Definition: email.h:45
bool replied
Email has been replied to.
Definition: email.h:49
bool deleted
Email is deleted.
Definition: email.h:76
Maildir-specific Email data -.
Definition: edata.h:34
+ 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 != 0)
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(_("maildir_commit_message(): unable to set time on file"));
292  rc = -1;
293  goto cleanup;
294  }
295  }
296 
297 #ifdef USE_NOTMUCH
298  if (m->type == MUTT_NOTMUCH)
299  nm_update_filename(m, e->path, mutt_buffer_string(full), e);
300 #endif
301  if (e)
304  FREE(&msg->path);
305 
306  goto cleanup;
307  }
308  else if (errno != EEXIST)
309  {
311  rc = -1;
312  goto cleanup;
313  }
314  }
315 
316 cleanup:
319 
320  return rc;
321 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:344
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:168
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
#define FREE(x)
Definition: memory.h:43
#define _(a)
Definition: message.h:28
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:629
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:50
int nm_update_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Change the filename.
Definition: notmuch.c:1736
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: random.c:129
char * path
Path of Email (for local Mailboxes)
Definition: email.h:68
FILE * fp
pointer to the message data
Definition: mxapi.h:44
char * path
path to temp file
Definition: mxapi.h:45
char * committed_path
the final path generated by mx_msg_commit()
Definition: mxapi.h:46
time_t received
Time at which this message was received.
Definition: mxapi.h:55
+ 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 330 of file maildir.c.

331 {
332  if (!m || !m->emails || (msgno >= m->msg_count))
333  return -1;
334 
335  struct Email *e = m->emails[msgno];
336  if (!e)
337  return -1;
338 
339  bool restore = true;
340 
341  long old_body_offset = e->body->offset;
342  long old_body_length = e->body->length;
343  long old_hdr_lines = e->lines;
344 
345  struct Message *src = mx_msg_open(m, msgno);
346  struct Message *dest = mx_msg_open_new(m, e, MUTT_MSG_NO_FLAGS);
347  if (!src || !dest)
348  return -1;
349 
350  int rc = mutt_copy_message(dest->fp, e, src, MUTT_CM_UPDATE, CH_UPDATE | CH_UPDATE_LEN, 0);
351  if (rc == 0)
352  {
353  char oldpath[PATH_MAX];
354  char partpath[PATH_MAX];
355  snprintf(oldpath, sizeof(oldpath), "%s/%s", mailbox_path(m), e->path);
356  mutt_str_copy(partpath, e->path, sizeof(partpath));
357 
358  rc = maildir_commit_message(m, dest, e);
359 
360  if (rc == 0)
361  {
362  unlink(oldpath);
363  restore = false;
364  }
365  }
366  mx_msg_close(m, &src);
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 }
int mutt_copy_message(FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:864
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:40
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:52
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
static struct Email * restore(const unsigned char *d)
Restore an Email from data retrieved from the cache.
Definition: hcache.c:143
int maildir_commit_message(struct Mailbox *m, struct Message *msg, struct Email *e)
Commit a message to a maildir folder.
Definition: maildir.c:237
#define PATH_MAX
Definition: mutt.h:40
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1193
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1147
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1057
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:42
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
The envelope/body of an email.
Definition: email.h:37
int lines
How many lines in the body of this message?
Definition: email.h:60
struct Body * body
List of MIME parts.
Definition: email.h:67
int msgno
Number displayed to the user.
Definition: email.h:111
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
A local copy of an email.
Definition: mxapi.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ 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 }
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:310
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
int maildir_rewrite_message(struct Mailbox *m, int msgno)
Sync a message in an MH folder.
Definition: maildir.c:330
void maildir_gen_flags(char *dest, size_t destlen, struct Email *e)
Generate the Maildir flags for an email.
Definition: maildir.c:186
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:784
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
struct Envelope * env
Envelope information.
Definition: email.h:66
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:99
bool trash
Message is marked as trashed on disk (used by the maildir_trash option)
Definition: email.h:51
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:92
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ 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 = { 0 };
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 }
void mutt_file_get_stat_timespec(struct timespec *dest, struct stat *st, enum MuttStatType type)
Read the stat() time into a time value.
Definition: file.c:1611
struct MaildirMboxData * maildir_mdata_get(struct Mailbox *m)
Get the private data for this Mailbox.
Definition: mdata.c:58
struct timespec mtime
Time Mailbox was last changed.
Definition: mailbox.h:104
void * mdata
Driver specific data.
Definition: mailbox.h:133
Maildir-specific Mailbox data -.
Definition: mdata.h:35
+ Here is the call graph for this function:

◆ 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 }
#define ARRAY_SORT(head, fn)
Sort an array.
Definition: array.h:277
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:155
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:86
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:430
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
static int maildir_cmp_inode(const void *a, const void *b)
Compare two Maildirs by inode number - Implements sort_t -.
Definition: maildir.c:495
struct MaildirEmailData * maildir_edata_new(void)
Create a new MaildirEmailData object.
Definition: edata.c:53
void maildir_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:38
void maildir_parse_flags(struct Email *e, const char *path)
Parse Maildir file flags.
Definition: maildir.c:809
struct MdEmail * maildir_entry_new(void)
Create a new Maildir entry.
Definition: mdemail.c:39
SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:69
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:73
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:87
bool verbose
Display status messages?
Definition: mailbox.h:115
A Maildir Email helper.
Definition: mdemail.h:34
struct Email * email
Definition: mdemail.h:35
ino_t inode
Definition: mdemail.h:38
+ 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:544
+ 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 = cs_subset_path(NeoMutt->sub, "header_cache");
604  struct HeaderCache *hc = mutt_hcache_open(c_header_cache, mailbox_path(m), NULL);
605 #endif
606 
607  struct MdEmail *md = NULL;
608  struct MdEmail **mdp = NULL;
609  ARRAY_FOREACH(mdp, mda)
610  {
611  md = *mdp;
612  if (!md || !md->email || md->header_parsed)
613  continue;
614 
615  if (m->verbose && progress)
616  progress_update(progress, ARRAY_FOREACH_IDX, -1);
617 
618  snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
619 
620 #ifdef USE_HCACHE
621  struct stat st_lastchanged = { 0 };
622  int rc = 0;
623  const bool c_maildir_header_cache_verify = cs_subset_bool(NeoMutt->sub, "maildir_header_cache_verify");
624  if (c_maildir_header_cache_verify)
625  {
626  rc = stat(fn, &st_lastchanged);
627  }
628 
629  const char *key = md->email->path + 3;
630  size_t keylen = maildir_hcache_keylen(key);
631  struct HCacheEntry hce = mutt_hcache_fetch(hc, key, keylen, 0);
632 
633  if (hce.email && (rc == 0) && (st_lastchanged.st_mtime <= hce.uidvalidity))
634  {
635  hce.email->edata = maildir_edata_new();
637  hce.email->old = md->email->old;
638  hce.email->path = mutt_str_dup(md->email->path);
639  email_free(&md->email);
640  md->email = hce.email;
641  maildir_parse_flags(md->email, fn);
642  }
643  else
644 #endif
645  {
646  if (maildir_parse_message(m->type, fn, md->email->old, md->email))
647  {
648  md->header_parsed = true;
649 #ifdef USE_HCACHE
650  key = md->email->path + 3;
651  keylen = maildir_hcache_keylen(key);
652  mutt_hcache_store(hc, key, keylen, md->email, 0);
653 #endif
654  }
655  else
656  email_free(&md->email);
657  }
658  }
659 #ifdef USE_HCACHE
660  mutt_hcache_close(hc);
661 #endif
662 }
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:211
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
int mutt_hcache_store(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition: hcache.c:548
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:332
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:432
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:456
size_t maildir_hcache_keylen(const char *fn)
Calculate the length of the Maildir path.
Definition: maildir.c:585
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:928
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
Wrapper for Email retrieved from the header cache.
Definition: lib.h:98
uint32_t uidvalidity
IMAP-specific UIDVALIDITY.
Definition: lib.h:99
struct Email * email
Retrieved email.
Definition: lib.h:101
Header cache structure.
Definition: lib.h:87
bool header_parsed
Definition: mdemail.h:37
+ 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 671 of file maildir.c.

672 {
673  if (!m)
674  return -1;
675 
676  struct Progress *progress = NULL;
677 
678  if (m->verbose)
679  {
680  char msg[PATH_MAX];
681  snprintf(msg, sizeof(msg), _("Scanning %s..."), mailbox_path(m));
682  progress = progress_new(msg, MUTT_PROGRESS_READ, 0);
683  }
684 
686  if (!mdata)
687  {
689  m->mdata = mdata;
691  }
692 
693  struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
694  int rc = maildir_parse_dir(m, &mda, subdir, progress);
695  progress_free(&progress);
696  if (rc < 0)
697  return -1;
698 
699  if (m->verbose)
700  {
701  char msg[PATH_MAX];
702  snprintf(msg, sizeof(msg), _("Reading %s..."), mailbox_path(m));
703  progress = progress_new(msg, MUTT_PROGRESS_READ, ARRAY_SIZE(&mda));
704  }
705  maildir_delayed_parsing(m, &mda, progress);
706  progress_free(&progress);
707 
708  maildir_move_to_mailbox(m, &mda);
709 
710  if (!mdata->mh_umask)
711  mdata->mh_umask = mh_umask(m);
712 
713  return 0;
714 }
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:57
void maildir_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free()
Definition: mdata.c:37
struct MaildirMboxData * maildir_mdata_new(void)
Create a new MaildirMboxData object.
Definition: mdata.c:47
mode_t mh_umask(struct Mailbox *m)
Create a umask from the mailbox directory.
Definition: shared.c:52
int maildir_move_to_mailbox(struct Mailbox *m, struct MdEmailArray *mda)
Copy the Maildir list to the Mailbox.
Definition: shared.c:75
int maildir_parse_dir(struct Mailbox *m, struct MdEmailArray *mda, const char *subdir, struct Progress *progress)
Read a Maildir mailbox.
Definition: maildir.c:513
void maildir_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
This function does the second parsing pass.
Definition: maildir.c:597
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: lib.h:49
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:86
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:118
void(* mdata_free)(void **ptr)
Free the private data attached to the Mailbox.
Definition: mailbox.h:143
mode_t mh_umask
umask to use when creating files
Definition: mdata.h:37
+ Here is the call 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 725 of file maildir.c.

726 {
727  if (!dest || !src)
728  return;
729 
730  char *t = strrchr(src, '/');
731  if (t)
732  src = t + 1;
733 
734  mutt_buffer_strcpy(dest, src);
735  char *u = strpbrk(dest->data, ",:");
736  if (u)
737  {
738  *u = '\0';
739  dest->dptr = u;
740  }
741 }
+ 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 755 of file maildir.c.

757 {
758  struct Buffer *dir = mutt_buffer_pool_get();
759  struct Buffer *tunique = mutt_buffer_pool_get();
760  struct Buffer *fname = mutt_buffer_pool_get();
761 
762  struct dirent *de = NULL;
763 
764  FILE *fp = NULL;
765  int oe = ENOENT;
766 
767  mutt_buffer_printf(dir, "%s/%s", folder, subfolder);
768 
769  DIR *dp = opendir(mutt_buffer_string(dir));
770  if (!dp)
771  {
772  errno = ENOENT;
773  goto cleanup;
774  }
775 
776  while ((de = readdir(dp)))
777  {
778  maildir_canon_filename(tunique, de->d_name);
779 
780  if (mutt_str_equal(mutt_buffer_string(tunique), unique))
781  {
782  mutt_buffer_printf(fname, "%s/%s/%s", folder, subfolder, de->d_name);
783  fp = fopen(mutt_buffer_string(fname), "r");
784  oe = errno;
785  break;
786  }
787  }
788 
789  closedir(dp);
790 
791  if (newname && fp)
792  *newname = mutt_buffer_strdup(fname);
793 
794  errno = oe;
795 
796 cleanup:
798  mutt_buffer_pool_release(&tunique);
799  mutt_buffer_pool_release(&fname);
800 
801  return fp;
802 }
void maildir_canon_filename(struct Buffer *dest, const char *src)
Generate the canonical filename for a Maildir folder.
Definition: maildir.c:725
+ 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 809 of file maildir.c.

810 {
811  char *q = NULL;
812 
813  e->flagged = false;
814  e->read = false;
815  e->replied = false;
816 
818 
819  char *p = strrchr(path, ':');
820  if (p && mutt_str_startswith(p + 1, "2,"))
821  {
822  p += 3;
823 
824  mutt_str_replace(&edata->maildir_flags, p);
825  q = edata->maildir_flags;
826 
827  while (*p)
828  {
829  switch (*p)
830  {
831  case 'F':
832  e->flagged = true;
833  break;
834 
835  case 'R': /* replied */
836  e->replied = true;
837  break;
838 
839  case 'S': /* seen */
840  e->read = true;
841  break;
842 
843  case 'T': /* trashed */
844  {
845  const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
846  if (!e->flagged || !c_flag_safe)
847  {
848  e->trash = true;
849  e->deleted = true;
850  }
851  break;
852  }
853 
854  default:
855  *q++ = *p;
856  break;
857  }
858  p++;
859  }
860  }
861 
862  if (q == edata->maildir_flags)
863  FREE(&edata->maildir_flags);
864  else if (q)
865  *q = '\0';
866 }
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:227
+ 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
NULLon error

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 881 of file maildir.c.

883 {
884  const long size = mutt_file_get_size_fp(fp);
885  if (size == 0)
886  {
887  return NULL;
888  }
889 
890  if (!e)
891  {
892  e = email_new();
893  e->edata = maildir_edata_new();
895  }
896  e->env = mutt_rfc822_read_header(fp, e, false, false);
897 
898  if (e->received == 0)
899  e->received = e->date_sent;
900 
901  /* always update the length since we have fresh information available. */
902  e->body->length = size - e->body->offset;
903 
904  e->index = -1;
905 
906  if (type == MUTT_MAILDIR)
907  {
908  /* maildir stores its flags in the filename, so ignore the
909  * flags in the header of the message */
910 
911  e->old = is_old;
912  maildir_parse_flags(e, fname);
913  }
914  return e;
915 }
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1569
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:48
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1158
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:58
int index
The absolute (unsorted) message number.
Definition: email.h:110
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ 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 928 of file maildir.c.

930 {
931  FILE *fp = fopen(fname, "r");
932  if (!fp)
933  return NULL;
934 
935  struct Email *e_res = maildir_parse_stream(type, fp, fname, is_old, e);
936  mutt_file_fclose(&fp);
937  return e_res;
938 }
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
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:881
+ 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 948 of file maildir.c.

949 {
950  struct Email *e = m->emails[msgno];
951  if (!e)
952  return false;
953 
954  const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
955  if (e->deleted && !c_maildir_trash)
956  {
957  char path[PATH_MAX];
958  snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
959 #ifdef USE_HCACHE
960  if (hc)
961  {
962  const char *key = e->path + 3;
963  size_t keylen = maildir_hcache_keylen(key);
964  mutt_hcache_delete_record(hc, key, keylen);
965  }
966 #endif
967  unlink(path);
968  }
969  else if (e->changed || e->attach_del ||
970  ((c_maildir_trash || e->trash) && (e->deleted != e->trash)))
971  {
972  if (maildir_sync_message(m, msgno) == -1)
973  return false;
974  }
975 
976 #ifdef USE_HCACHE
977  if (hc && e->changed)
978  {
979  const char *key = e->path + 3;
980  size_t keylen = maildir_hcache_keylen(key);
981  mutt_hcache_store(hc, key, keylen, e, 0);
982  }
983 #endif
984 
985  return true;
986 }
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:627
int maildir_sync_message(struct Mailbox *m, int msgno)
Sync an email to a Maildir folder.
Definition: maildir.c:387
bool changed
Email has been edited.
Definition: email.h:75
+ Here is the call 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 995 of file maildir.c.

996 {
997  static unsigned int new_hits = 0, cur_hits = 0; /* simple dynamic optimization */
998 
999  struct Buffer *unique = mutt_buffer_pool_get();
1000  maildir_canon_filename(unique, msg);
1001 
1002  FILE *fp = maildir_open_find_message_dir(folder, mutt_buffer_string(unique),
1003  (new_hits > cur_hits) ? "new" : "cur", newname);
1004  if (fp || (errno != ENOENT))
1005  {
1006  if ((new_hits < UINT_MAX) && (cur_hits < UINT_MAX))
1007  {
1008  new_hits += ((new_hits > cur_hits) ? 1 : 0);
1009  cur_hits += ((new_hits > cur_hits) ? 0 : 1);
1010  }
1011 
1012  goto cleanup;
1013  }
1015  (new_hits > cur_hits) ? "cur" : "new", newname);
1016  if (fp || (errno != ENOENT))
1017  {
1018  if ((new_hits < UINT_MAX) && (cur_hits < UINT_MAX))
1019  {
1020  new_hits += ((new_hits > cur_hits) ? 0 : 1);
1021  cur_hits += ((new_hits > cur_hits) ? 1 : 0);
1022  }
1023 
1024  goto cleanup;
1025  }
1026 
1027  fp = NULL;
1028 
1029 cleanup:
1030  mutt_buffer_pool_release(&unique);
1031 
1032  return fp;
1033 }
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:755
+ 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 1042 of file maildir.c.

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