NeoMutt  2025-01-09-41-g086358
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
mailbox.c File Reference

Maildir Mailbox. More...

#include "config.h"
#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "mailbox.h"
#include "progress/lib.h"
#include "edata.h"
#include "hcache.h"
#include "mdata.h"
#include "mdemail.h"
#include "mx.h"
#include "shared.h"
#include "monitor.h"
+ Include dependency graph for mailbox.c:

Go to the source code of this file.

Macros

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

Functions

struct Emailmaildir_email_new (void)
 Create a Maildir Email.
 
void maildir_parse_flags (struct Email *e, const char *path)
 Parse Maildir file flags.
 
bool maildir_parse_stream (FILE *fp, const char *fname, bool is_old, struct Email *e)
 Parse a Maildir message.
 
bool maildir_parse_message (const char *fname, bool is_old, struct Email *e)
 Actually parse a maildir message.
 
static int maildir_move_to_mailbox (struct Mailbox *m, const struct MdEmailArray *mda)
 Copy the Maildir list to the Mailbox.
 
static int maildir_sort_inode (const void *a, const void *b, void *sdata)
 Compare two Maildirs by inode number - Implements sort_t -.
 
static int maildir_parse_dir (struct Mailbox *m, struct MdEmailArray *mda, const char *subdir, struct Progress *progress)
 Read a Maildir mailbox.
 
static void maildir_delayed_parsing (struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
 This function does the second parsing pass.
 
static void maildir_check_dir (struct Mailbox *m, const char *dir_name, bool check_new, bool check_stats)
 Check for new mail / mail counts.
 
static int maildir_read_dir (struct Mailbox *m, const char *subdir)
 Read a Maildir style mailbox.
 
static enum MxStatus maildir_check (struct Mailbox *m)
 Check for new mail.
 
void maildir_update_mtime (struct Mailbox *m)
 Update our record of the Maildir modification time.
 
enum MxOpenReturns maildir_mbox_open (struct Mailbox *m)
 Open a Mailbox - Implements MxOps::mbox_open() -.
 
bool maildir_mbox_open_append (struct Mailbox *m, OpenMailboxFlags flags)
 Open a Mailbox for appending - Implements MxOps::mbox_open_append() -.
 
enum MxStatus maildir_mbox_check (struct Mailbox *m)
 Check for new mail - Implements MxOps::mbox_check() -.
 
enum MxStatus maildir_mbox_check_stats (struct Mailbox *m, uint8_t flags)
 Check the Mailbox statistics - Implements MxOps::mbox_check_stats() -.
 
enum MxStatus maildir_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
 
enum MxStatus maildir_mbox_close (struct Mailbox *m)
 Close a Mailbox - Implements MxOps::mbox_close() -.
 

Detailed Description

Maildir Mailbox.

Authors
  • 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 mailbox.c.

Macro Definition Documentation

◆ MMC_NO_DIRS

#define MMC_NO_DIRS   0

No directories changed.

Definition at line 55 of file mailbox.c.

◆ MMC_NEW_DIR

#define MMC_NEW_DIR   (1 << 0)

'new' directory changed

Definition at line 56 of file mailbox.c.

◆ MMC_CUR_DIR

#define MMC_CUR_DIR   (1 << 1)

'cur' directory changed

Definition at line 57 of file mailbox.c.

Function Documentation

◆ maildir_email_new()

struct Email * maildir_email_new ( void  )

Create a Maildir Email.

Return values
ptrNewly created Email

Create a new Email and attach MaildirEmailData.

Note
This should be freed using email_free()

Definition at line 67 of file mailbox.c.

68{
69 struct Email *e = email_new();
72
73 return e;
74}
struct Email * email_new(void)
Create a new Email.
Definition: email.c:77
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
The envelope/body of an email.
Definition: email.h:39
void * edata
Driver-specific data.
Definition: email.h:74
void(* edata_free)(void **ptr)
Definition: email.h:90
+ 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 81 of file mailbox.c.

82{
83 char *q = NULL;
84
85 e->flagged = false;
86 e->read = false;
87 e->replied = false;
88
90 if (!edata)
91 {
93 edata = e->edata;
94 }
95
96 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
97 char *p = strrchr(path, c_maildir_field_delimiter);
98 if (p && mutt_str_startswith(p + 1, "2,"))
99 {
100 p += 3;
101
102 mutt_str_replace(&edata->custom_flags, p);
103 q = edata->custom_flags;
104
105 while (*p)
106 {
107 switch (*p)
108 {
109 case 'F': // Flagged
110 e->flagged = true;
111 break;
112
113 case 'R': // Replied
114 e->replied = true;
115 break;
116
117 case 'S': // Seen
118 e->read = true;
119 break;
120
121 case 'T': // Trashed
122 {
123 const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
124 if (!e->flagged || !c_flag_safe)
125 {
126 e->trash = true;
127 e->deleted = true;
128 }
129 break;
130 }
131
132 default:
133 *q++ = *p;
134 break;
135 }
136 p++;
137 }
138 }
139
140 if (q == edata->custom_flags)
141 FREE(&edata->custom_flags);
142 else if (q)
143 *q = '\0';
144}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
const char * cc_maildir_field_delimiter(void)
Get the cached value of $maildir_field_delimiter.
Definition: config_cache.c:131
struct MaildirEmailData * maildir_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:63
#define FREE(x)
Definition: memory.h:55
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:230
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:280
bool read
Email is read.
Definition: email.h:50
bool flagged
Marked important?
Definition: email.h:47
bool replied
Email has been replied to.
Definition: email.h:51
char * path
Path of Email (for local Mailboxes)
Definition: email.h:70
bool deleted
Email is deleted.
Definition: email.h:78
bool trash
Message is marked as trashed on disk (used by the maildir_trash option)
Definition: email.h:53
Maildir-specific Email data -.
Definition: edata.h:32
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_parse_stream()

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

Parse a Maildir message.

Parameters
fpMessage file handle
fnameMessage filename
is_oldtrue, if the email is old (read)
eEmail
Return values
trueSuccess

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 157 of file mailbox.c.

158{
159 if (!fp || !fname || !e)
160 return false;
161
162 const long size = mutt_file_get_size_fp(fp);
163 if (size == 0)
164 return false;
165
166 e->env = mutt_rfc822_read_header(fp, e, false, false);
167
168 if (e->received == 0)
169 e->received = e->date_sent;
170
171 /* always update the length since we have fresh information available. */
172 e->body->length = size - e->body->offset;
173
174 e->index = -1;
175
176 /* maildir stores its flags in the filename, so ignore the
177 * flags in the header of the message */
178 e->old = is_old;
179 maildir_parse_flags(e, fname);
180
181 return e;
182}
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1205
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1430
void maildir_parse_flags(struct Email *e, const char *path)
Parse Maildir file flags.
Definition: mailbox.c:81
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
struct Envelope * env
Envelope information.
Definition: email.h:68
struct Body * body
List of MIME parts.
Definition: email.h:69
bool old
Email is seen, but unread.
Definition: email.h:49
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:60
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:61
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_parse_message()

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

Actually parse a maildir message.

Parameters
fnameMessage filename
is_oldtrue, if the email is old (read)
eEmail to populate
Return values
trueSuccess

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

Definition at line 194 of file mailbox.c.

195{
196 if (!fname || !e)
197 return false;
198
199 FILE *fp = mutt_file_fopen(fname, "r");
200 if (!fp)
201 return false;
202
203 bool rc = maildir_parse_stream(fp, fname, is_old, e);
204 mutt_file_fclose(&fp);
205 return rc;
206}
#define mutt_file_fclose(FP)
Definition: file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:138
bool maildir_parse_stream(FILE *fp, const char *fname, bool is_old, struct Email *e)
Parse a Maildir message.
Definition: mailbox.c:157
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_move_to_mailbox()

static int maildir_move_to_mailbox ( struct Mailbox m,
const struct MdEmailArray *  mda 
)
static

Copy the Maildir list to the Mailbox.

Parameters
[in]mMailbox
[out]mdaMaildir array to copy, then free
Return values
numNumber of new emails
0Error

Definition at line 215 of file mailbox.c.

216{
217 if (!m)
218 return 0;
219
220 int oldmsgcount = m->msg_count;
221
222 struct MdEmail *md = NULL;
223 struct MdEmail **mdp = NULL;
224 ARRAY_FOREACH(mdp, mda)
225 {
226 md = *mdp;
227 mutt_debug(LL_DEBUG2, "Considering %s\n", NONULL(md->canon_fname));
228 if (!md->email)
229 continue;
230
231 mutt_debug(LL_DEBUG2, "Adding header structure. Flags: %s%s%s%s%s\n",
232 md->email->flagged ? "f" : "", md->email->deleted ? "D" : "",
233 md->email->replied ? "r" : "", md->email->old ? "O" : "",
234 md->email->read ? "R" : "");
236
237 m->emails[m->msg_count] = md->email;
238 m->emails[m->msg_count]->index = m->msg_count;
239 mailbox_size_add(m, md->email);
240
241 md->email = NULL;
242 m->msg_count++;
243 }
244
245 int num = 0;
246 if (m->msg_count > oldmsgcount)
247 num = m->msg_count - oldmsgcount;
248
249 return num;
250}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:212
void mailbox_size_add(struct Mailbox *m, const struct Email *e)
Add an email's size to the total size of a Mailbox.
Definition: mailbox.c:249
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
void mx_alloc_memory(struct Mailbox *m, int req_size)
Create storage for the emails.
Definition: mx.c:1210
#define NONULL(x)
Definition: string2.h:37
int msg_count
Total number of messages.
Definition: mailbox.h:88
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
A Maildir Email helper.
Definition: mdemail.h:34
char * canon_fname
Canonical filename for hashing.
Definition: mdemail.h:36
struct Email * email
Temporary Email.
Definition: mdemail.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 273 of file mailbox.c.

275{
276 struct dirent *de = NULL;
277 int rc = 0;
278 bool is_old = false;
279 struct MdEmail *entry = NULL;
280 struct Email *e = NULL;
281
282 struct Buffer *buf = buf_pool_get();
283
284 buf_printf(buf, "%s/%s", mailbox_path(m), subdir);
285 is_old = mutt_str_equal("cur", subdir);
286
288 if (!dir)
289 {
290 rc = -1;
291 goto cleanup;
292 }
293
294 while (((de = readdir(dir))) && !SigInt)
295 {
296 if (*de->d_name == '.')
297 continue;
298
299 mutt_debug(LL_DEBUG2, "queueing %s\n", de->d_name);
300
301 e = maildir_email_new();
302 e->old = is_old;
303 maildir_parse_flags(e, de->d_name);
304
305 progress_update(progress, ARRAY_SIZE(mda) + 1, -1);
306
307 buf_printf(buf, "%s/%s", subdir, de->d_name);
308 e->path = buf_strdup(buf);
309
310 entry = maildir_entry_new();
311 entry->email = e;
312 entry->inode = de->d_ino;
313 ARRAY_ADD(mda, entry);
314 }
315
316 closedir(dir);
317
318 if (SigInt)
319 {
320 SigInt = false;
321 return -2; /* action aborted */
322 }
323
324 ARRAY_SORT(mda, maildir_sort_inode, NULL);
325
326cleanup:
327 buf_pool_release(&buf);
328
329 return rc;
330}
#define ARRAY_SORT(head, fn, sdata)
Sort an array.
Definition: array.h:279
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:156
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:87
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:571
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:223
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:542
@ MUTT_OPENDIR_CREATE
Create the directory if it doesn't exist.
Definition: file.h:64
static int maildir_sort_inode(const void *a, const void *b, void *sdata)
Compare two Maildirs by inode number - Implements sort_t -.
Definition: mailbox.c:255
struct Email * maildir_email_new(void)
Create a Maildir Email.
Definition: mailbox.c:67
struct MdEmail * maildir_entry_new(void)
Create a new Maildir entry.
Definition: mdemail.c:39
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:80
volatile sig_atomic_t SigInt
true after SIGINT is received
Definition: signal.c:66
String manipulation buffer.
Definition: buffer.h:36
ino_t inode
Inode number of the file.
Definition: mdemail.h:38
+ 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 338 of file mailbox.c.

340{
341 char fn[PATH_MAX] = { 0 };
342
343 struct HeaderCache *hc = maildir_hcache_open(m);
344
345 struct MdEmail *md = NULL;
346 struct MdEmail **mdp = NULL;
347 ARRAY_FOREACH(mdp, mda)
348 {
349 md = *mdp;
350 if (!md || !md->email || md->header_parsed)
351 continue;
352
353 progress_update(progress, ARRAY_FOREACH_IDX_mdp, -1);
354
355 snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
356
357 struct Email *e = maildir_hcache_read(hc, md->email, fn);
358 if (e)
359 {
360 email_free(&md->email);
361 md->email = e;
362 }
363 else
364 {
365 if (maildir_parse_message(fn, md->email->old, md->email))
366 {
367 md->header_parsed = true;
369 }
370 else
371 {
372 email_free(&md->email);
373 }
374 }
375 }
376
378}
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:46
int maildir_hcache_store(struct HeaderCache *hc, struct Email *e)
Save an Email to the Header Cache.
Definition: hcache.c:155
struct Email * maildir_hcache_read(struct HeaderCache *hc, struct Email *e, const char *fn)
Read an Email from the Header Cache.
Definition: hcache.c:113
struct HeaderCache * maildir_hcache_open(struct Mailbox *m)
Open the Header Cache.
Definition: hcache.c:96
void maildir_hcache_close(struct HeaderCache **ptr)
Close the Header Cache.
Definition: hcache.c:69
bool maildir_parse_message(const char *fname, bool is_old, struct Email *e)
Actually parse a maildir message.
Definition: mailbox.c:194
#define PATH_MAX
Definition: mutt.h:42
Header Cache.
Definition: lib.h:86
bool header_parsed
Has the Email header been parsed?
Definition: mdemail.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ 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 389 of file mailbox.c.

391{
392 DIR *dir = NULL;
393 struct dirent *de = NULL;
394 char *p = NULL;
395 struct stat st = { 0 };
396
397 struct Buffer *path = buf_pool_get();
398 struct Buffer *msgpath = buf_pool_get();
399 buf_printf(path, "%s/%s", mailbox_path(m), dir_name);
400
401 /* when $mail_check_recent is set, if the new/ directory hasn't been modified since
402 * the user last exited the mailbox, then we know there is no recent mail. */
403 const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
404 if (check_new && c_mail_check_recent)
405 {
406 if ((stat(buf_string(path), &st) == 0) &&
408 {
409 check_new = false;
410 }
411 }
412
413 if (!(check_new || check_stats))
414 goto cleanup;
415
417 if (!dir)
418 {
419 m->type = MUTT_UNKNOWN;
420 goto cleanup;
421 }
422
423 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
424
425 char delimiter_version[8] = { 0 };
426 snprintf(delimiter_version, sizeof(delimiter_version), "%c2,", c_maildir_field_delimiter);
427 while ((de = readdir(dir)))
428 {
429 if (*de->d_name == '.')
430 continue;
431
432 p = strstr(de->d_name, delimiter_version);
433 if (p && strchr(p + 3, 'T'))
434 continue;
435
436 if (check_stats)
437 {
438 m->msg_count++;
439 if (p && strchr(p + 3, 'F'))
440 m->msg_flagged++;
441 }
442 if (!p || !strchr(p + 3, 'S'))
443 {
444 if (check_stats)
445 m->msg_unread++;
446 if (check_new)
447 {
448 if (c_mail_check_recent)
449 {
450 buf_printf(msgpath, "%s/%s", buf_string(path), de->d_name);
451 /* ensure this message was received since leaving this m */
452 if ((stat(buf_string(msgpath), &st) == 0) &&
454 {
455 continue;
456 }
457 }
458 m->has_new = true;
459 if (check_stats)
460 {
461 m->msg_new++;
462 }
463 else
464 {
465 break;
466 }
467 }
468 }
469 }
470
471 closedir(dir);
472
473cleanup:
474 buf_pool_release(&path);
475 buf_pool_release(&msgpath);
476}
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:44
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:1512
@ MUTT_STAT_CTIME
File/dir's ctime - creation time.
Definition: file.h:55
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:54
bool has_new
Mailbox has new mail.
Definition: mailbox.h:85
int msg_new
Number of new messages.
Definition: mailbox.h:92
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:104
int msg_unread
Number of unread messages.
Definition: mailbox.h:89
+ 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 485 of file mailbox.c.

486{
487 if (!m)
488 return -1;
489
490 mutt_path_tidy(&m->pathbuf, true);
491
492 struct Progress *progress = NULL;
493
494 if (m->verbose)
495 {
496 progress = progress_new(MUTT_PROGRESS_READ, 0);
497 progress_set_message(progress, _("Scanning %s..."), mailbox_path(m));
498 }
499
501 if (!mdata)
502 {
504 m->mdata = mdata;
506 }
507
508 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
509 int rc = maildir_parse_dir(m, &mda, subdir, progress);
510 progress_free(&progress);
511 if (rc < 0)
512 return -1;
513
514 if (m->verbose)
515 {
516 progress = progress_new(MUTT_PROGRESS_READ, ARRAY_SIZE(&mda));
517 progress_set_message(progress, _("Reading %s..."), mailbox_path(m));
518 }
519 maildir_delayed_parsing(m, &mda, progress);
520 progress_free(&progress);
521
523 maildirarray_clear(&mda);
524
525 if (!mdata->umask)
526 mdata->umask = maildir_umask(m);
527
528 return 0;
529}
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:58
void maildir_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free() -.
Definition: mdata.c:37
static void maildir_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
This function does the second parsing pass.
Definition: mailbox.c:338
static int maildir_move_to_mailbox(struct Mailbox *m, const struct MdEmailArray *mda)
Copy the Maildir list to the Mailbox.
Definition: mailbox.c:215
static int maildir_parse_dir(struct Mailbox *m, struct MdEmailArray *mda, const char *subdir, struct Progress *progress)
Read a Maildir mailbox.
Definition: mailbox.c:273
struct MaildirMboxData * maildir_mdata_get(struct Mailbox *m)
Get the private data for this Mailbox.
Definition: mdata.c:59
struct MaildirMboxData * maildir_mdata_new(void)
Create a new MaildirMboxData object.
Definition: mdata.c:49
mode_t maildir_umask(struct Mailbox *m)
Create a umask from the mailbox directory.
Definition: shared.c:47
void maildirarray_clear(struct MdEmailArray *mda)
Free a Maildir array.
Definition: mdemail.c:64
#define _(a)
Definition: message.h:28
bool mutt_path_tidy(struct Buffer *path, bool is_dir)
Remove unnecessary parts of a path.
Definition: path.c:169
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: lib.h:83
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:139
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:110
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
void(* mdata_free)(void **ptr)
Definition: mailbox.h:143
void * mdata
Driver specific data.
Definition: mailbox.h:132
struct Buffer pathbuf
Path of the Mailbox.
Definition: mailbox.h:80
bool verbose
Display status messages?
Definition: mailbox.h:117
Maildir-specific Mailbox data -.
Definition: mdata.h:35
mode_t umask
umask to use when creating files
Definition: mdata.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_check()

static enum MxStatus maildir_check ( struct Mailbox m)
static

Check for new mail.

Parameters
mMailbox
Return values
enumMxStatus

This function handles arrival of new mail and reopening of maildir folders. The basic idea here is we check to see if either the new or cur subdirectories have changed, and if so, we scan them for the list of files. We check for newly added messages, and then merge the flags messages we already knew about. We don't treat either subdirectory differently, as mail could be copied directly into the cur directory from another agent.

Definition at line 543 of file mailbox.c.

544{
545 struct stat st_new = { 0 }; /* status of the "new" subdirectory */
546 struct stat st_cur = { 0 }; /* status of the "cur" subdirectory */
547 int changed = MMC_NO_DIRS; /* which subdirectories have changed */
548 bool occult = false; /* messages were removed from the mailbox */
549 int num_new = 0; /* number of new messages added to the mailbox */
550 bool flags_changed = false; /* message flags were changed in the mailbox */
551 struct HashTable *hash_names = NULL; // Hash Table: "base-filename" -> MdEmail
553
554 const bool c_check_new = cs_subset_bool(NeoMutt->sub, "check_new");
555 if (!c_check_new)
556 return MX_STATUS_OK;
557
558 struct Buffer *buf = buf_pool_get();
559 buf_printf(buf, "%s/new", mailbox_path(m));
560 if (stat(buf_string(buf), &st_new) == -1)
561 {
562 buf_pool_release(&buf);
563 return MX_STATUS_ERROR;
564 }
565
566 buf_printf(buf, "%s/cur", mailbox_path(m));
567 if (stat(buf_string(buf), &st_cur) == -1)
568 {
569 buf_pool_release(&buf);
570 return MX_STATUS_ERROR;
571 }
572
573 /* determine which subdirectories need to be scanned */
574 if (mutt_file_stat_timespec_compare(&st_new, MUTT_STAT_MTIME, &mdata->mtime) > 0)
575 changed = MMC_NEW_DIR;
577 changed |= MMC_CUR_DIR;
578
579 if (changed == MMC_NO_DIRS)
580 {
581 buf_pool_release(&buf);
582 return MX_STATUS_OK; /* nothing to do */
583 }
584
585 /* Update the modification times on the mailbox.
586 *
587 * The monitor code notices changes in the open mailbox too quickly.
588 * In practice, this sometimes leads to all the new messages not being
589 * noticed during the SAME group of mtime stat updates. To work around
590 * the problem, don't update the stat times for a monitor caused check. */
591#ifdef USE_INOTIFY
593 {
594 MonitorCurMboxChanged = false;
595 }
596 else
597#endif
598 {
601 }
602
603 /* do a fast scan of just the filenames in
604 * the subdirectories that have changed. */
605 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
606 if (changed & MMC_NEW_DIR)
607 maildir_parse_dir(m, &mda, "new", NULL);
608 if (changed & MMC_CUR_DIR)
609 maildir_parse_dir(m, &mda, "cur", NULL);
610
611 /* we create a hash table keyed off the canonical (sans flags) filename
612 * of each message we scanned. This is used in the loop over the
613 * existing messages below to do some correlation. */
614 hash_names = mutt_hash_new(ARRAY_SIZE(&mda), MUTT_HASH_NO_FLAGS);
615
616 struct MdEmail *md = NULL;
617 struct MdEmail **mdp = NULL;
618 ARRAY_FOREACH(mdp, &mda)
619 {
620 md = *mdp;
622 md->canon_fname = buf_strdup(buf);
623 mutt_hash_insert(hash_names, md->canon_fname, md);
624 }
625
626 /* check for modifications and adjust flags */
627 for (int i = 0; i < m->msg_count; i++)
628 {
629 struct Email *e = m->emails[i];
630 if (!e)
631 break;
632
634 md = mutt_hash_find(hash_names, buf_string(buf));
635 if (md && md->email)
636 {
637 /* message already exists, merge flags */
638
639 /* check to see if the message has moved to a different
640 * subdirectory. If so, update the associated filename. */
641 if (!mutt_str_equal(e->path, md->email->path))
642 mutt_str_replace(&e->path, md->email->path);
643
644 /* if the user hasn't modified the flags on this message, update
645 * the flags we just detected. */
646 if (!e->changed)
647 if (maildir_update_flags(m, e, md->email))
648 flags_changed = true;
649
650 if (e->deleted == e->trash)
651 {
652 if (e->deleted != md->email->deleted)
653 {
654 e->deleted = md->email->deleted;
655 flags_changed = true;
656 }
657 }
658 e->trash = md->email->trash;
659
660 /* this is a duplicate of an existing email, so remove it */
661 email_free(&md->email);
662 }
663 /* This message was not in the list of messages we just scanned.
664 * Check to see if we have enough information to know if the
665 * message has disappeared out from underneath us. */
666 else if (((changed & MMC_NEW_DIR) && mutt_strn_equal(e->path, "new/", 4)) ||
667 ((changed & MMC_CUR_DIR) && mutt_strn_equal(e->path, "cur/", 4)))
668 {
669 /* This message disappeared, so we need to simulate a "reopen"
670 * event. We know it disappeared because we just scanned the
671 * subdirectory it used to reside in. */
672 occult = true;
673 e->deleted = true;
674 e->purge = true;
675 }
676 else
677 {
678 /* This message resides in a subdirectory which was not
679 * modified, so we assume that it is still present and
680 * unchanged. */
681 }
682 }
683
684 /* destroy the file name hash */
685 mutt_hash_free(&hash_names);
686
687 /* If we didn't just get new mail, update the tables. */
688 if (occult)
690
691 /* do any delayed parsing we need to do. */
692 maildir_delayed_parsing(m, &mda, NULL);
693
694 /* Incorporate new messages */
695 num_new = maildir_move_to_mailbox(m, &mda);
696 maildirarray_clear(&mda);
697
698 if (num_new > 0)
699 {
701 m->changed = true;
702 }
703
704 buf_pool_release(&buf);
705
706 ARRAY_FREE(&mda);
707 if (occult)
708 return MX_STATUS_REOPENED;
709 if (num_new > 0)
710 return MX_STATUS_NEW_MAIL;
711 if (flags_changed)
712 return MX_STATUS_FLAGS;
713 return MX_STATUS_OK;
714}
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:204
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:233
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:190
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:189
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:1472
struct HashElem * mutt_hash_insert(struct HashTable *table, const char *strkey, void *data)
Add a new element to the Hash Table (with string keys)
Definition: hash.c:335
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition: hash.c:362
struct HashTable * mutt_hash_new(size_t num_elems, HashFlags flags)
Create a new Hash Table (with string keys)
Definition: hash.c:259
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:457
#define MUTT_HASH_NO_FLAGS
No flags are set.
Definition: hash.h:109
#define MMC_CUR_DIR
'cur' directory changed
Definition: mailbox.c:57
#define MMC_NO_DIRS
No directories changed.
Definition: mailbox.c:55
#define MMC_NEW_DIR
'new' directory changed
Definition: mailbox.c:56
bool maildir_update_flags(struct Mailbox *m, struct Email *e_old, struct Email *e_new)
Update the mailbox flags.
Definition: shared.c:105
void maildir_canon_filename(struct Buffer *dest, const char *src)
Generate the canonical filename for a Maildir folder.
Definition: shared.c:73
bool MonitorCurMboxChanged
Set to true when the current mailbox has changed.
Definition: monitor.c:55
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:425
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:61
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:62
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition: mxapi.h:66
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:65
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:63
bool purge
Skip trash folder when deleting.
Definition: email.h:79
bool changed
Email has been edited.
Definition: email.h:77
A Hash Table.
Definition: hash.h:97
bool changed
Mailbox has been modified.
Definition: mailbox.h:110
struct timespec mtime_cur
Timestamp of the 'cur' dir.
Definition: mdata.h:37
struct timespec mtime
Time Mailbox was last changed.
Definition: mdata.h:36
+ 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 720 of file mailbox.c.

721{
722 char buf[PATH_MAX] = { 0 };
723 struct stat st = { 0 };
725
726 snprintf(buf, sizeof(buf), "%s/%s", mailbox_path(m), "cur");
727 if (stat(buf, &st) == 0)
729
730 snprintf(buf, sizeof(buf), "%s/%s", mailbox_path(m), "new");
731 if (stat(buf, &st) == 0)
733}
+ Here is the call graph for this function:
+ Here is the caller graph for this function: