NeoMutt  2024-12-12-14-g7b49f7
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
91 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
92 char *p = strrchr(path, c_maildir_field_delimiter);
93 if (p && mutt_str_startswith(p + 1, "2,"))
94 {
95 p += 3;
96
97 mutt_str_replace(&edata->custom_flags, p);
98 q = edata->custom_flags;
99
100 while (*p)
101 {
102 switch (*p)
103 {
104 case 'F': // Flagged
105 e->flagged = true;
106 break;
107
108 case 'R': // Replied
109 e->replied = true;
110 break;
111
112 case 'S': // Seen
113 e->read = true;
114 break;
115
116 case 'T': // Trashed
117 {
118 const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
119 if (!e->flagged || !c_flag_safe)
120 {
121 e->trash = true;
122 e->deleted = true;
123 }
124 break;
125 }
126
127 default:
128 *q++ = *p;
129 break;
130 }
131 p++;
132 }
133 }
134
135 if (q == edata->custom_flags)
136 FREE(&edata->custom_flags);
137 else if (q)
138 *q = '\0';
139}
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 152 of file mailbox.c.

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

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

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

270{
271 struct dirent *de = NULL;
272 int rc = 0;
273 bool is_old = false;
274 struct MdEmail *entry = NULL;
275 struct Email *e = NULL;
276
277 struct Buffer *buf = buf_pool_get();
278
279 buf_printf(buf, "%s/%s", mailbox_path(m), subdir);
280 is_old = mutt_str_equal("cur", subdir);
281
283 if (!dir)
284 {
285 rc = -1;
286 goto cleanup;
287 }
288
289 while (((de = readdir(dir))) && !SigInt)
290 {
291 if (*de->d_name == '.')
292 continue;
293
294 mutt_debug(LL_DEBUG2, "queueing %s\n", de->d_name);
295
296 e = maildir_email_new();
297 e->old = is_old;
298 maildir_parse_flags(e, de->d_name);
299
300 progress_update(progress, ARRAY_SIZE(mda) + 1, -1);
301
302 buf_printf(buf, "%s/%s", subdir, de->d_name);
303 e->path = buf_strdup(buf);
304
305 entry = maildir_entry_new();
306 entry->email = e;
307 entry->inode = de->d_ino;
308 ARRAY_ADD(mda, entry);
309 }
310
311 closedir(dir);
312
313 if (SigInt)
314 {
315 SigInt = false;
316 return -2; /* action aborted */
317 }
318
319 ARRAY_SORT(mda, maildir_sort_inode, NULL);
320
321cleanup:
322 buf_pool_release(&buf);
323
324 return rc;
325}
#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:642
@ 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:250
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 333 of file mailbox.c.

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

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

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

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

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