NeoMutt  2022-04-29-247-gc6aae8
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
162cleanup:
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:168
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:210
@ 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:
+ 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] = { 0 };
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] = { 0 };
240 char suffix[16] = { 0 };
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)
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
316cleanup:
319
320 return rc;
321}
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:428
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:652
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:1737
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] = { 0 };
354 char partpath[PATH_MAX] = { 0 };
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
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] = { 0 };
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
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 }
462 }
463
464cleanup:
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:327
@ 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:807
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] = { 0 };
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:132
Maildir-specific Mailbox data -.
Definition: mdata.h:35
+ Here is the call graph for this function:
+ 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 is_old = mutt_str_equal("cur", subdir);
526
527 DIR *dirp = opendir(mutt_buffer_string(buf));
528 if (!dirp)
529 {
530 rc = -1;
531 goto cleanup;
532 }
533
534 while (((de = readdir(dirp))) && !SigInt)
535 {
536 if (*de->d_name == '.')
537 continue;
538
539 /* FOO - really ignore the return value? */
540 mutt_debug(LL_DEBUG2, "queueing %s\n", de->d_name);
541
542 e = email_new();
545
546 e->old = is_old;
547 maildir_parse_flags(e, de->d_name);
548
549 if (m->verbose && progress)
550 progress_update(progress, ARRAY_SIZE(mda) + 1, -1);
551
552 mutt_buffer_printf(buf, "%s/%s", subdir, de->d_name);
553 e->path = mutt_buffer_strdup(buf);
554
555 entry = maildir_entry_new();
556 entry->email = e;
557 entry->inode = de->d_ino;
558 ARRAY_ADD(mda, entry);
559 }
560
561 closedir(dirp);
562
563 if (SigInt)
564 {
565 SigInt = false;
566 return -2; /* action aborted */
567 }
568
570
571cleanup:
573
574 return rc;
575}
#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:447
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
void maildir_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:38
struct MaildirEmailData * maildir_edata_new(void)
Create a new MaildirEmailData object.
Definition: edata.c:53
void maildir_parse_flags(struct Email *e, const char *path)
Parse Maildir file flags.
Definition: maildir.c:808
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:114
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 584 of file maildir.c.

585{
586 const char *p = strrchr(fn, ':');
587 return p ? (size_t) (p - fn) : mutt_str_len(fn);
588}
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
+ 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 596 of file maildir.c.

598{
599 char fn[PATH_MAX] = { 0 };
600
601#ifdef USE_HCACHE
602 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
603 struct HeaderCache *hc = mutt_hcache_open(c_header_cache, mailbox_path(m), NULL);
604#endif
605
606 struct MdEmail *md = NULL;
607 struct MdEmail **mdp = NULL;
608 ARRAY_FOREACH(mdp, mda)
609 {
610 md = *mdp;
611 if (!md || !md->email || md->header_parsed)
612 continue;
613
614 if (m->verbose && progress)
615 progress_update(progress, ARRAY_FOREACH_IDX, -1);
616
617 snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
618
619#ifdef USE_HCACHE
620 struct stat st_lastchanged = { 0 };
621 int rc = 0;
622 const bool c_maildir_header_cache_verify = cs_subset_bool(NeoMutt->sub, "maildir_header_cache_verify");
623 if (c_maildir_header_cache_verify)
624 {
625 rc = stat(fn, &st_lastchanged);
626 }
627
628 const char *key = md->email->path + 3;
629 size_t keylen = maildir_hcache_keylen(key);
630 struct HCacheEntry hce = mutt_hcache_fetch(hc, key, keylen, 0);
631
632 if (hce.email && (rc == 0) && (st_lastchanged.st_mtime <= hce.uidvalidity))
633 {
636 hce.email->old = md->email->old;
637 hce.email->path = mutt_str_dup(md->email->path);
638 email_free(&md->email);
639 md->email = hce.email;
640 maildir_parse_flags(md->email, fn);
641 }
642 else
643#endif
644 {
645 if (maildir_parse_message(m->type, fn, md->email->old, md->email))
646 {
647 md->header_parsed = true;
648#ifdef USE_HCACHE
649 key = md->email->path + 3;
650 keylen = maildir_hcache_keylen(key);
651 mutt_hcache_store(hc, key, keylen, md->email, 0);
652#endif
653 }
654 else
655 email_free(&md->email);
656 }
657 }
658#ifdef USE_HCACHE
660#endif
661}
#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:552
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:432
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:332
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:584
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:927
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 670 of file maildir.c.

671{
672 if (!m)
673 return -1;
674
675 struct Progress *progress = NULL;
676
677 if (m->verbose)
678 {
679 char msg[PATH_MAX] = { 0 };
680 snprintf(msg, sizeof(msg), _("Scanning %s..."), mailbox_path(m));
681 progress = progress_new(msg, MUTT_PROGRESS_READ, 0);
682 }
683
685 if (!mdata)
686 {
688 m->mdata = mdata;
690 }
691
692 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
693 int rc = maildir_parse_dir(m, &mda, subdir, progress);
694 progress_free(&progress);
695 if (rc < 0)
696 return -1;
697
698 if (m->verbose)
699 {
700 char msg[PATH_MAX] = { 0 };
701 snprintf(msg, sizeof(msg), _("Reading %s..."), mailbox_path(m));
702 progress = progress_new(msg, MUTT_PROGRESS_READ, ARRAY_SIZE(&mda));
703 }
704 maildir_delayed_parsing(m, &mda, progress);
705 progress_free(&progress);
706
708
709 if (!mdata->mh_umask)
710 mdata->mh_umask = mh_umask(m);
711
712 return 0;
713}
#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:596
@ 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:142
mode_t mh_umask
umask to use when creating files
Definition: mdata.h:37
+ 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 724 of file maildir.c.

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

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

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

882{
883 const long size = mutt_file_get_size_fp(fp);
884 if (size == 0)
885 {
886 return NULL;
887 }
888
889 if (!e)
890 {
891 e = email_new();
894 }
895 e->env = mutt_rfc822_read_header(fp, e, false, false);
896
897 if (e->received == 0)
898 e->received = e->date_sent;
899
900 /* always update the length since we have fresh information available. */
901 e->body->length = size - e->body->offset;
902
903 e->index = -1;
904
905 if (type == MUTT_MAILDIR)
906 {
907 /* maildir stores its flags in the filename, so ignore the
908 * flags in the header of the message */
909
910 e->old = is_old;
911 maildir_parse_flags(e, fname);
912 }
913 return e;
914}
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:1157
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 927 of file maildir.c.

929{
930 FILE *fp = fopen(fname, "r");
931 if (!fp)
932 return NULL;
933
934 struct Email *e_res = maildir_parse_stream(type, fp, fname, is_old, e);
935 mutt_file_fclose(&fp);
936 return e_res;
937}
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:880
+ 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 947 of file maildir.c.

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

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

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