NeoMutt  2023-03-22-27-g3cb248
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 "globals.h"
#include "mdata.h"
#include "mdemail.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...
 
static int maildir_commit_message (struct Mailbox *m, struct Message *msg, struct Email *e)
 Commit a message to a maildir folder. More...
 
static int maildir_rewrite_message (struct Mailbox *m, int msgno)
 Sync a message in an MH folder. More...
 
static int maildir_sync_message (struct Mailbox *m, int msgno)
 Sync an email to a Maildir folder. More...
 
static 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...
 
static int maildir_parse_dir (struct Mailbox *m, struct MdEmailArray *mda, const char *subdir, struct Progress *progress)
 Read a Maildir mailbox. More...
 
static size_t maildir_hcache_keylen (const char *fn)
 Calculate the length of the Maildir path. More...
 
static void maildir_delayed_parsing (struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
 This function does the second parsing pass. More...
 
static int maildir_read_dir (struct Mailbox *m, const char *subdir)
 Read a Maildir style mailbox. More...
 
static 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 message by name. More...
 
int maildir_check_empty (const char *path)
 Is the mailbox empty. More...
 
static 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...
 
static 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...
 
static 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...
 
static enum MxStatus maildir_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -. More...
 
static 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...
 
static 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...
 
static int maildir_path_canon (char *buf, size_t buflen)
 Canonicalise a Mailbox path - Implements MxOps::path_canon() -. More...
 
static int maildir_path_parent (char *buf, size_t buflen)
 Find the parent of a Mailbox path - Implements MxOps::path_parent() -. More...
 
static 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 *dir = 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
114 if (!dir)
115 {
116 m->type = MUTT_UNKNOWN;
117 goto cleanup;
118 }
119
120 while ((de = readdir(dir)))
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(dir);
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:78
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:614
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:1638
@ MUTT_OPENDIR_CREATE
Create the directory if it doesn't exist.
Definition: file.h:74
@ MUTT_STAT_CTIME
File/dir's ctime - creation time.
Definition: file.h:65
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:64
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:209
@ 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()

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

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_now(), 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_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:432
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:343
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:165
char * ShortHostname
Short version of the hostname.
Definition: globals.c:39
#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
int nm_update_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Change the filename.
Definition: notmuch.c:1743
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()

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

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:875
#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
static 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:41
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1200
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1154
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1062
#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:110
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()

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

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:365
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
static 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:98
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()

static void maildir_update_mtime ( struct Mailbox m)
static

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
487 snprintf(buf, sizeof(buf), "%s/%s", mailbox_path(m), "new");
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:1598
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()

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

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
528 if (!dir)
529 {
530 rc = -1;
531 goto cleanup;
532 }
533
534 while (((de = readdir(dir))) && !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(dir);
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:485
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: globals.c:58
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:812
struct MdEmail * maildir_entry_new(void)
Create a new Maildir entry.
Definition: mdemail.c:39
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:86
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()

static size_t maildir_hcache_keylen ( const char *  fn)
static

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:567
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_delayed_parsing()

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

This function does the second parsing pass.

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

Definition at line 598 of file maildir.c.

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

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

Read a Maildir style mailbox.

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

Definition at line 674 of file maildir.c.

675{
676 if (!m)
677 return -1;
678
679 struct Progress *progress = NULL;
680
681 if (m->verbose)
682 {
683 char msg[PATH_MAX] = { 0 };
684 snprintf(msg, sizeof(msg), _("Scanning %s..."), mailbox_path(m));
685 progress = progress_new(msg, MUTT_PROGRESS_READ, 0);
686 }
687
689 if (!mdata)
690 {
692 m->mdata = mdata;
694 }
695
696 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
697 int rc = maildir_parse_dir(m, &mda, subdir, progress);
698 progress_free(&progress);
699 if (rc < 0)
700 return -1;
701
702 if (m->verbose)
703 {
704 char msg[PATH_MAX] = { 0 };
705 snprintf(msg, sizeof(msg), _("Reading %s..."), mailbox_path(m));
706 progress = progress_new(msg, MUTT_PROGRESS_READ, ARRAY_SIZE(&mda));
707 }
708 maildir_delayed_parsing(m, &mda, progress);
709 progress_free(&progress);
710
712
713 if (!mdata->mh_umask)
714 mdata->mh_umask = mh_umask(m);
715
716 return 0;
717}
#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
static void maildir_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
This function does the second parsing pass.
Definition: maildir.c:598
static int maildir_parse_dir(struct Mailbox *m, struct MdEmailArray *mda, const char *subdir, struct Progress *progress)
Read a Maildir mailbox.
Definition: maildir.c:513
@ 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:141
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()

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

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

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

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

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

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

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

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

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

Definition at line 998 of file maildir.c.

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

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