NeoMutt  2024-04-16-36-g75b6fb
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 "sort.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 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:80
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
92 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
93 char *p = strrchr(path, c_maildir_field_delimiter);
94 if (p && mutt_str_startswith(p + 1, "2,"))
95 {
96 p += 3;
97
98 mutt_str_replace(&edata->custom_flags, p);
99 q = edata->custom_flags;
100
101 while (*p)
102 {
103 switch (*p)
104 {
105 case 'F': // Flagged
106 e->flagged = true;
107 break;
108
109 case 'R': // Replied
110 e->replied = true;
111 break;
112
113 case 'S': // Seen
114 e->read = true;
115 break;
116
117 case 'T': // Trashed
118 {
119 const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
120 if (!e->flagged || !c_flag_safe)
121 {
122 e->trash = true;
123 e->deleted = true;
124 }
125 break;
126 }
127
128 default:
129 *q++ = *p;
130 break;
131 }
132 p++;
133 }
134 }
135
136 if (q == edata->custom_flags)
137 FREE(&edata->custom_flags);
138 else if (q)
139 *q = '\0';
140}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
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:64
#define FREE(x)
Definition: memory.h:45
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:274
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:45
+ 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 153 of file mailbox.c.

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

191{
192 if (!fname || !e)
193 return false;
194
195 FILE *fp = mutt_file_fopen(fname, "r");
196 if (!fp)
197 return false;
198
199 bool rc = maildir_parse_stream(fp, fname, is_old, e);
200 mutt_file_fclose(&fp);
201 return rc;
202}
#define mutt_file_fclose(FP)
Definition: file.h:147
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:146
bool maildir_parse_stream(FILE *fp, const char *fname, bool is_old, struct Email *e)
Parse a Maildir message.
Definition: mailbox.c:153
+ 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 211 of file mailbox.c.

212{
213 if (!m)
214 return 0;
215
216 int oldmsgcount = m->msg_count;
217
218 struct MdEmail *md = NULL;
219 struct MdEmail **mdp = NULL;
220 ARRAY_FOREACH(mdp, mda)
221 {
222 md = *mdp;
223 mutt_debug(LL_DEBUG2, "Considering %s\n", NONULL(md->canon_fname));
224 if (!md->email)
225 continue;
226
227 mutt_debug(LL_DEBUG2, "Adding header structure. Flags: %s%s%s%s%s\n",
228 md->email->flagged ? "f" : "", md->email->deleted ? "D" : "",
229 md->email->replied ? "r" : "", md->email->old ? "O" : "",
230 md->email->read ? "R" : "");
232
233 m->emails[m->msg_count] = md->email;
234 m->emails[m->msg_count]->index = m->msg_count;
235 mailbox_size_add(m, md->email);
236
237 md->email = NULL;
238 m->msg_count++;
239 }
240
241 int num = 0;
242 if (m->msg_count > oldmsgcount)
243 num = m->msg_count - oldmsgcount;
244
245 return num;
246}
#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:250
#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:1204
#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 269 of file mailbox.c.

271{
272 struct dirent *de = NULL;
273 int rc = 0;
274 bool is_old = false;
275 struct MdEmail *entry = NULL;
276 struct Email *e = NULL;
277
278 struct Buffer *buf = buf_pool_get();
279
280 buf_printf(buf, "%s/%s", mailbox_path(m), subdir);
281 is_old = mutt_str_equal("cur", subdir);
282
284 if (!dir)
285 {
286 rc = -1;
287 goto cleanup;
288 }
289
290 while (((de = readdir(dir))) && !SigInt)
291 {
292 if (*de->d_name == '.')
293 continue;
294
295 mutt_debug(LL_DEBUG2, "queueing %s\n", de->d_name);
296
297 e = maildir_email_new();
298 e->old = is_old;
299 maildir_parse_flags(e, de->d_name);
300
301 progress_update(progress, ARRAY_SIZE(mda) + 1, -1);
302
303 buf_printf(buf, "%s/%s", subdir, de->d_name);
304 e->path = buf_strdup(buf);
305
306 entry = maildir_entry_new();
307 entry->email = e;
308 entry->inode = de->d_ino;
309 ARRAY_ADD(mda, entry);
310 }
311
312 closedir(dir);
313
314 if (SigInt)
315 {
316 SigInt = false;
317 return -2; /* action aborted */
318 }
319
320 ARRAY_SORT(mda, maildir_sort_inode, NULL);
321
322cleanup:
323 buf_pool_release(&buf);
324
325 return rc;
326}
#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:160
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:570
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:640
@ MUTT_OPENDIR_CREATE
Create the directory if it doesn't exist.
Definition: file.h:75
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:251
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:654
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
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:63
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 334 of file mailbox.c.

336{
337 char fn[PATH_MAX] = { 0 };
338
339 struct HeaderCache *hc = maildir_hcache_open(m);
340
341 struct MdEmail *md = NULL;
342 struct MdEmail **mdp = NULL;
343 ARRAY_FOREACH(mdp, mda)
344 {
345 md = *mdp;
346 if (!md || !md->email || md->header_parsed)
347 continue;
348
349 progress_update(progress, ARRAY_FOREACH_IDX, -1);
350
351 snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
352
353 struct Email *e = maildir_hcache_read(hc, md->email, fn);
354 if (e)
355 {
356 email_free(&md->email);
357 md->email = e;
358 }
359 else
360 {
361 if (maildir_parse_message(fn, md->email->old, md->email))
362 {
363 md->header_parsed = true;
365 }
366 else
367 {
368 email_free(&md->email);
369 }
370 }
371 }
372
374}
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:190
#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 385 of file mailbox.c.

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

482{
483 if (!m)
484 return -1;
485
486 mutt_path_tidy(&m->pathbuf, true);
487
488 struct Progress *progress = NULL;
489
490 if (m->verbose)
491 {
492 progress = progress_new(MUTT_PROGRESS_READ, 0);
493 progress_set_message(progress, _("Scanning %s..."), mailbox_path(m));
494 }
495
497 if (!mdata)
498 {
500 m->mdata = mdata;
502 }
503
504 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
505 int rc = maildir_parse_dir(m, &mda, subdir, progress);
506 progress_free(&progress);
507 if (rc < 0)
508 return -1;
509
510 if (m->verbose)
511 {
512 progress = progress_new(MUTT_PROGRESS_READ, ARRAY_SIZE(&mda));
513 progress_set_message(progress, _("Reading %s..."), mailbox_path(m));
514 }
515 maildir_delayed_parsing(m, &mda, progress);
516 progress_free(&progress);
517
519 maildirarray_clear(&mda);
520
521 if (!mdata->umask)
522 mdata->umask = maildir_umask(m);
523
524 return 0;
525}
#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:334
static int maildir_move_to_mailbox(struct Mailbox *m, const struct MdEmailArray *mda)
Copy the Maildir list to the Mailbox.
Definition: mailbox.c:211
static int maildir_parse_dir(struct Mailbox *m, struct MdEmailArray *mda, const char *subdir, struct Progress *progress)
Read a Maildir mailbox.
Definition: mailbox.c:269
struct MaildirMboxData * maildir_mdata_get(struct Mailbox *m)
Get the private data for this Mailbox.
Definition: mdata.c:60
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:82
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 539 of file mailbox.c.

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

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