NeoMutt  2025-12-11-694-ga89709
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
  • Pietro Cerutti

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

◆ MMC_NEW_DIR

#define MMC_NEW_DIR   (1 << 0)

'new' directory changed

Definition at line 57 of file mailbox.c.

◆ MMC_CUR_DIR

#define MMC_CUR_DIR   (1 << 1)

'cur' directory changed

Definition at line 58 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 68 of file mailbox.c.

69{
70 struct Email *e = email_new();
73
74 return e;
75}
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 82 of file mailbox.c.

83{
84 char *q = NULL;
85
86 e->flagged = false;
87 e->read = false;
88 e->replied = false;
89
91 if (!edata)
92 {
94 edata = e->edata;
95 }
96
97 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
98 char *p = strrchr(path, c_maildir_field_delimiter);
99 if (p && mutt_str_startswith(p + 1, "2,"))
100 {
101 p += 3;
102
103 mutt_str_replace(&edata->custom_flags, p);
104 q = edata->custom_flags;
105
106 while (*p)
107 {
108 switch (*p)
109 {
110 case 'F': // Flagged
111 e->flagged = true;
112 break;
113
114 case 'R': // Replied
115 e->replied = true;
116 break;
117
118 case 'S': // Seen
119 e->read = true;
120 break;
121
122 case 'T': // Trashed
123 {
124 const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
125 if (!e->flagged || !c_flag_safe)
126 {
127 e->trash = true;
128 e->deleted = true;
129 }
130 break;
131 }
132
133 default:
134 *q++ = *p;
135 break;
136 }
137 p++;
138 }
139 }
140
141 if (q == edata->custom_flags)
142 FREE(&edata->custom_flags);
143 else if (q)
144 *q = '\0';
145}
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.
struct MaildirEmailData * maildir_edata_get(struct Email *e)
Get the private data for this Email.
Definition edata.c:63
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
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:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
+ 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 158 of file mailbox.c.

159{
160 if (!fp || !fname || !e)
161 return false;
162
163 const long size = mutt_file_get_size_fp(fp);
164 if (size == 0)
165 return false;
166
167 e->env = mutt_rfc822_read_header(fp, e, false, false);
168
169 if (e->received == 0)
170 e->received = e->date_sent;
171
172 /* always update the length since we have fresh information available. */
173 e->body->length = size - e->body->offset;
174
175 e->index = -1;
176
177 /* maildir stores its flags in the filename, so ignore the
178 * flags in the header of the message */
179 e->old = is_old;
180 maildir_parse_flags(e, fname);
181
182 return true;
183}
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition parse.c:1210
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1432
void maildir_parse_flags(struct Email *e, const char *path)
Parse Maildir file flags.
Definition mailbox.c:82
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 195 of file mailbox.c.

196{
197 if (!fname || !e)
198 return false;
199
200 FILE *fp = mutt_file_fopen(fname, "r");
201 if (!fp)
202 return false;
203
204 bool rc = maildir_parse_stream(fp, fname, is_old, e);
205 mutt_file_fclose(&fp);
206 return rc;
207}
#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:158
+ 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 216 of file mailbox.c.

217{
218 if (!m)
219 return 0;
220
221 int oldmsgcount = m->msg_count;
222
223 struct MdEmail *md = NULL;
224 struct MdEmail **mdp = NULL;
225 ARRAY_FOREACH(mdp, mda)
226 {
227 md = *mdp;
228 mutt_debug(LL_DEBUG2, "Considering %s\n", NONULL(md->canon_fname));
229 if (!md->email)
230 continue;
231
232 mutt_debug(LL_DEBUG2, "Adding header structure. Flags: %s%s%s%s%s\n",
233 md->email->flagged ? "f" : "", md->email->deleted ? "D" : "",
234 md->email->replied ? "r" : "", md->email->old ? "O" : "",
235 md->email->read ? "R" : "");
237
238 m->emails[m->msg_count] = md->email;
239 m->emails[m->msg_count]->index = m->msg_count;
240 mailbox_size_add(m, md->email);
241
242 md->email = NULL;
243 m->msg_count++;
244 }
245
246 int num = 0;
247 if (m->msg_count > oldmsgcount)
248 num = m->msg_count - oldmsgcount;
249
250 return num;
251}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
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:248
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
void mx_alloc_memory(struct Mailbox *m, int req_size)
Create storage for the emails.
Definition mx.c:1208
#define NONULL(x)
Definition string2.h:44
int msg_count
Total number of messages.
Definition mailbox.h:87
struct Email ** emails
Array of Emails.
Definition mailbox.h:95
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 274 of file mailbox.c.

276{
277 struct dirent *de = NULL;
278 int rc = 0;
279 bool is_old = false;
280 struct MdEmail *entry = NULL;
281 struct Email *e = NULL;
282
283 struct Buffer *buf = buf_pool_get();
284
285 buf_printf(buf, "%s/%s", mailbox_path(m), subdir);
286 is_old = mutt_str_equal("cur", subdir);
287
289 if (!dir)
290 {
291 rc = -1;
292 goto cleanup;
293 }
294
295 while (((de = readdir(dir))) && !SigInt)
296 {
297 if (*de->d_name == '.')
298 continue;
299
300 mutt_debug(LL_DEBUG2, "queueing %s\n", de->d_name);
301
302 e = maildir_email_new();
303 e->old = is_old;
304 maildir_parse_flags(e, de->d_name);
305
306 progress_update(progress, ARRAY_SIZE(mda) + 1, -1);
307
308 buf_printf(buf, "%s/%s", subdir, de->d_name);
309 e->path = buf_strdup(buf);
310
311 entry = maildir_entry_new();
312 entry->email = e;
313 entry->inode = de->d_ino;
314 ARRAY_ADD(mda, entry);
315 }
316
317 closedir(dir);
318
319 if (SigInt)
320 {
321 SigInt = false;
322 rc = -2; /* action aborted */
323 goto cleanup;
324 }
325
326 ARRAY_SORT(mda, maildir_sort_inode, NULL);
327
328cleanup:
329 buf_pool_release(&buf);
330
331 return rc;
332}
#define ARRAY_SORT(head, fn, sdata)
Sort an array.
Definition array.h:373
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#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:213
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition file.c:535
@ 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:256
struct Email * maildir_email_new(void)
Create a Maildir Email.
Definition mailbox.c:68
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:665
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
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:68
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 340 of file mailbox.c.

342{
343 char fn[PATH_MAX] = { 0 };
344
345 struct HeaderCache *hc = maildir_hcache_open(m);
346
347 struct MdEmail *md = NULL;
348 struct MdEmail **mdp = NULL;
349 ARRAY_FOREACH(mdp, mda)
350 {
351 md = *mdp;
352 if (!md || !md->email || md->header_parsed)
353 continue;
354
355 progress_update(progress, ARRAY_FOREACH_IDX_mdp, -1);
356
357 snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
358
359 struct Email *e = maildir_hcache_read(hc, md->email, fn);
360 if (e)
361 {
362 email_free(&md->email);
363 md->email = e;
364 }
365 else
366 {
367 if (maildir_parse_message(fn, md->email->old, md->email))
368 {
369 md->header_parsed = true;
371 }
372 else
373 {
374 email_free(&md->email);
375 }
376 }
377 }
378
380}
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:163
struct Email * maildir_hcache_read(struct HeaderCache *hc, struct Email *e, const char *fn)
Read an Email from the Header Cache.
Definition hcache.c:121
struct HeaderCache * maildir_hcache_open(struct Mailbox *m)
Open the Header Cache.
Definition hcache.c:104
void maildir_hcache_close(struct HeaderCache **ptr)
Close the Header Cache.
Definition hcache.c:77
bool maildir_parse_message(const char *fname, bool is_old, struct Email *e)
Actually parse a maildir message.
Definition mailbox.c:195
#define PATH_MAX
Definition mutt.h:49
Header Cache.
Definition lib.h:87
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 391 of file mailbox.c.

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

488{
489 if (!m)
490 return -1;
491
492 mutt_path_tidy(&m->pathbuf, true);
493
494 struct Progress *progress = NULL;
495
496 if (m->verbose)
497 {
498 progress = progress_new(MUTT_PROGRESS_READ, 0);
499 progress_set_message(progress, _("Scanning %s..."), mailbox_path(m));
500 }
501
503 if (!mdata)
504 {
506 m->mdata = mdata;
508 }
509
510 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
511 int rc = maildir_parse_dir(m, &mda, subdir, progress);
512 progress_free(&progress);
513 if (rc < 0)
514 return -1;
515
516 if (m->verbose)
517 {
518 progress = progress_new(MUTT_PROGRESS_READ, ARRAY_SIZE(&mda));
519 progress_set_message(progress, _("Reading %s..."), mailbox_path(m));
520 }
521 maildir_delayed_parsing(m, &mda, progress);
522 progress_free(&progress);
523
525 maildirarray_clear(&mda);
526
527 if (!mdata->umask)
528 mdata->umask = maildir_umask(m);
529
530 return 0;
531}
#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:340
static int maildir_move_to_mailbox(struct Mailbox *m, const struct MdEmailArray *mda)
Copy the Maildir list to the Mailbox.
Definition mailbox.c:216
static int maildir_parse_dir(struct Mailbox *m, struct MdEmailArray *mda, const char *subdir, struct Progress *progress)
Read a Maildir mailbox.
Definition mailbox.c:274
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:46
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:84
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:142
void * mdata
Driver specific data.
Definition mailbox.h:131
struct Buffer pathbuf
Path of the Mailbox.
Definition mailbox.h:79
bool verbose
Display status messages?
Definition mailbox.h:116
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 545 of file mailbox.c.

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

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