NeoMutt  2025-12-11-980-ge38c27
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
mbox.c File Reference

Mbox local mailbox type. More...

#include "config.h"
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <utime.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "mutt.h"
#include "lib.h"
#include "progress/lib.h"
#include "globals.h"
#include "muttlib.h"
#include "mx.h"
+ Include dependency graph for mbox.c:

Go to the source code of this file.

Data Structures

struct  MUpdate
 Store of new offsets, used by mutt_sync_mailbox() More...
 

Functions

static void mbox_adata_free (void **ptr)
 Free the private Account data - Implements Account::adata_free() -.
 
static struct MboxAccountDatambox_adata_new (void)
 Create a new MboxAccountData struct.
 
static int init_mailbox (struct Mailbox *m)
 Add Mbox data to the Mailbox.
 
static struct MboxAccountDatambox_adata_get (struct Mailbox *m)
 Get the private data associated with a Mailbox.
 
static int mbox_lock_mailbox (struct Mailbox *m, bool excl, bool retry)
 Lock a mailbox.
 
static void mbox_unlock_mailbox (struct Mailbox *m)
 Unlock a mailbox.
 
static enum MxOpenReturns mmdf_parse_mailbox (struct Mailbox *m)
 Read a mailbox in MMDF format.
 
static enum MxOpenReturns mbox_parse_mailbox (struct Mailbox *m)
 Read a mailbox from disk.
 
static int reopen_mailbox (struct Mailbox *m)
 Close and reopen a mailbox.
 
static bool mbox_has_new (struct Mailbox *m)
 Does the mailbox have new mail.
 
void mbox_reset_atime (struct Mailbox *m, struct stat *st)
 Reset the access time on the mailbox file.
 
static bool mbox_ac_owns_path (struct Account *a, const char *path)
 Check whether an Account owns a Mailbox path - Implements MxOps::ac_owns_path() -.
 
static bool mbox_ac_add (struct Account *a, struct Mailbox *m)
 Add a Mailbox to an Account - Implements MxOps::ac_add() -.
 
static FILE * mbox_open_readwrite (struct Mailbox *m)
 Open an mbox read-write.
 
static FILE * mbox_open_readonly (struct Mailbox *m)
 Open an mbox read-only.
 
static enum MxOpenReturns mbox_mbox_open (struct Mailbox *m)
 Open a Mailbox - Implements MxOps::mbox_open() -.
 
static bool mbox_mbox_open_append (struct Mailbox *m, OpenMailboxFlags flags)
 Open a Mailbox for appending - Implements MxOps::mbox_open_append() -.
 
static enum MxStatus mbox_mbox_check (struct Mailbox *m)
 Check for new mail - Implements MxOps::mbox_check() -.
 
static enum MxStatus mbox_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
 
static enum MxStatus mbox_mbox_close (struct Mailbox *m)
 Close a Mailbox - Implements MxOps::mbox_close() -.
 
static bool mbox_msg_open (struct Mailbox *m, struct Message *msg, struct Email *e)
 Open an email message in a Mailbox - Implements MxOps::msg_open() -.
 
static bool mbox_msg_open_new (struct Mailbox *m, struct Message *msg, const struct Email *e)
 Open a new message in a Mailbox - Implements MxOps::msg_open_new() -.
 
static int mbox_msg_commit (struct Mailbox *m, struct Message *msg)
 Save changes to an email - Implements MxOps::msg_commit() -.
 
static int mbox_msg_close (struct Mailbox *m, struct Message *msg)
 Close an email - Implements MxOps::msg_close() -.
 
static int mbox_msg_padding_size (struct Mailbox *m)
 Bytes of padding between messages - Implements MxOps::msg_padding_size() -.
 
enum MailboxType mbox_path_probe (const char *path, const struct stat *st)
 Is this an mbox Mailbox?
 
static int mbox_path_canon (struct Buffer *path)
 Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
 
static int mbox_path_is_empty (struct Buffer *path)
 Is the mailbox empty - Implements MxOps::path_is_empty() -.
 
static int mmdf_msg_commit (struct Mailbox *m, struct Message *msg)
 Save changes to an email - Implements MxOps::msg_commit() -.
 
static int mmdf_msg_padding_size (struct Mailbox *m)
 Bytes of padding between messages - Implements MxOps::msg_padding_size() -.
 
static enum MxStatus mbox_mbox_check_stats (struct Mailbox *m, uint8_t flags)
 Check the Mailbox statistics - Implements MxOps::mbox_check_stats() -.
 

Variables

const struct MxOps MxMboxOps
 Mbox Mailbox - Implements MxOps -.
 
const struct MxOps MxMmdfOps
 MMDF Mailbox - Implements MxOps -.
 

Detailed Description

Mbox local mailbox type.

Authors
  • Richard Russon
  • Austin Ray
  • Ian Zimmerman
  • 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 mbox.c.

Function Documentation

◆ mbox_adata_new()

static struct MboxAccountData * mbox_adata_new ( void )
static

Create a new MboxAccountData struct.

Return values
ptrNew MboxAccountData

Definition at line 91 of file mbox.c.

92{
93 return MUTT_MEM_CALLOC(1, struct MboxAccountData);
94}
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
Mbox-specific Account data -.
Definition lib.h:50
+ Here is the caller graph for this function:

◆ init_mailbox()

static int init_mailbox ( struct Mailbox * m)
static

Add Mbox data to the Mailbox.

Parameters
mMailbox
Return values
0Success
-1Error Bad format

Definition at line 102 of file mbox.c.

103{
104 if (!m || !m->account)
105 return -1;
106 if ((m->type != MUTT_MBOX) && (m->type != MUTT_MMDF))
107 return -1;
108 if (m->account->adata)
109 return 0;
110
113 return 0;
114}
@ MUTT_MMDF
'mmdf' Mailbox type
Definition mailbox.h:45
@ MUTT_MBOX
'mbox' Mailbox type
Definition mailbox.h:44
static void mbox_adata_free(void **ptr)
Free the private Account data - Implements Account::adata_free() -.
Definition mbox.c:76
static struct MboxAccountData * mbox_adata_new(void)
Create a new MboxAccountData struct.
Definition mbox.c:91
void(* adata_free)(void **ptr)
Definition account.h:53
void * adata
Private data (for Mailbox backends)
Definition account.h:42
enum MailboxType type
Mailbox type.
Definition mailbox.h:104
struct Account * account
Account that owns this Mailbox.
Definition mailbox.h:129
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mbox_adata_get()

static struct MboxAccountData * mbox_adata_get ( struct Mailbox * m)
static

Get the private data associated with a Mailbox.

Parameters
mMailbox
Return values
ptrPrivate data

Definition at line 121 of file mbox.c.

122{
123 if (init_mailbox(m) == -1)
124 return NULL;
125 return m->account->adata;
126}
static int init_mailbox(struct Mailbox *m)
Add Mbox data to the Mailbox.
Definition mbox.c:102
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mbox_lock_mailbox()

static int mbox_lock_mailbox ( struct Mailbox * m,
bool excl,
bool retry )
static

Lock a mailbox.

Parameters
mMailbox to lock
exclExclusive lock?
retryShould retry if unable to lock?
Return values
0Success
-1Failure

Definition at line 136 of file mbox.c.

137{
139 if (!adata)
140 return -1;
141
142 int rc = mutt_file_lock(fileno(adata->fp), excl, retry);
143 if (rc == 0)
144 {
145 adata->locked = true;
146 }
147 else if (retry && !excl)
148 {
149 m->readonly = true;
150 return 0;
151 }
152
153 return rc;
154}
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
Definition file.c:1088
static struct MboxAccountData * mbox_adata_get(struct Mailbox *m)
Get the private data associated with a Mailbox.
Definition mbox.c:121
bool readonly
Don't allow changes to the mailbox.
Definition mailbox.h:118
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mbox_unlock_mailbox()

static void mbox_unlock_mailbox ( struct Mailbox * m)
static

Unlock a mailbox.

Parameters
mMailbox to unlock

Definition at line 160 of file mbox.c.

161{
163 if (!adata)
164 return;
165
166 if (adata->locked)
167 {
168 fflush(adata->fp);
169
170 mutt_file_unlock(fileno(adata->fp));
171 adata->locked = false;
172 }
173}
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition file.c:1136
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mmdf_parse_mailbox()

static enum MxOpenReturns mmdf_parse_mailbox ( struct Mailbox * m)
static

Read a mailbox in MMDF format.

Parameters
mMailbox
Return values
enumMxOpenReturns

Definition at line 180 of file mbox.c.

181{
182 if (!m)
183 return MX_OPEN_ERROR;
184
186 if (!adata)
187 return MX_OPEN_ERROR;
188
189 char buf[8192] = { 0 };
190 char return_path[1024] = { 0 };
191 int count = 0;
192 int lines;
193 time_t t = 0;
194 LOFF_T loc;
195 LOFF_T tmploc;
196 struct Email *e = NULL;
197 struct stat st = { 0 };
198 struct Progress *progress = NULL;
200
201 /* Record mailbox timestamps and size for change detection */
202 if (stat(mailbox_path(m), &st) == -1)
203 {
204 mutt_perror("%s", mailbox_path(m));
205 goto fail;
206 }
209 m->size = st.st_size;
210
211 if (m->verbose)
212 {
213 progress = progress_new(MUTT_PROGRESS_READ, 0);
214 progress_set_message(progress, _("Reading %s..."), mailbox_path(m));
215 }
216
217 /* Read the file line-by-line looking for MMDF separator lines ("\001\001\001\001\n") */
218 while (true)
219 {
220 if (!fgets(buf, sizeof(buf) - 1, adata->fp))
221 break;
222
223 if (SigInt)
224 break;
225
226 if (mutt_str_equal(buf, MMDF_SEP))
227 {
228 loc = ftello(adata->fp);
229 if (loc < 0)
230 goto fail;
231
232 count++;
233 progress_update(progress, count, (int) (loc / (m->size / 100 + 1)));
234
235 /* Allocate a new Email for this message */
237 e = email_new();
238 m->emails[m->msg_count] = e;
239 e->offset = loc;
240 e->index = m->msg_count;
241
242 if (!fgets(buf, sizeof(buf) - 1, adata->fp))
243 {
244 mutt_debug(LL_DEBUG1, "unexpected EOF\n");
245 email_free(&m->emails[m->msg_count]);
246 break;
247 }
248
249 /* Try to parse "From " line for return path and date */
250 return_path[0] = '\0';
251
252 if (!is_from(buf, return_path, sizeof(return_path), &t))
253 {
254 if (!mutt_file_seek(adata->fp, loc, SEEK_SET))
255 {
256 mutt_error(_("Mailbox is corrupt"));
257 goto fail;
258 }
259 }
260 else
261 {
262 e->received = t - mutt_date_local_tz(t);
263 }
264
265 /* Parse RFC 822 headers to populate the envelope */
266 e->env = mutt_rfc822_read_header(adata->fp, e, false, false);
267
268 loc = ftello(adata->fp);
269 if (loc < 0)
270 goto fail;
271
272 /* Try to validate the Content-Length by seeking to the expected end
273 * and verifying an MMDF separator is there */
274 if ((e->body->length > 0) && (e->lines > 0))
275 {
276 tmploc = loc + e->body->length;
277
278 if ((tmploc > 0) && (tmploc < m->size))
279 {
280 if (!mutt_file_seek(adata->fp, tmploc, SEEK_SET) ||
281 !fgets(buf, sizeof(buf) - 1, adata->fp) || !mutt_str_equal(MMDF_SEP, buf))
282 {
283 (void) mutt_file_seek(adata->fp, loc, SEEK_SET);
284 e->body->length = -1;
285 }
286 }
287 else
288 {
289 e->body->length = -1;
290 }
291 }
292 else
293 {
294 e->body->length = -1;
295 }
296
297 /* If Content-Length was missing or invalid, scan for the next separator */
298 if (e->body->length < 0)
299 {
300 lines = -1;
301 do
302 {
303 loc = ftello(adata->fp);
304 if (loc < 0)
305 goto fail;
306 if (!fgets(buf, sizeof(buf) - 1, adata->fp))
307 break;
308 lines++;
309 } while (!mutt_str_equal(buf, MMDF_SEP));
310
311 e->lines = lines;
312 e->body->length = loc - e->body->offset;
313 }
314
315 /* Populate return path and from address if missing from headers */
316 if (TAILQ_EMPTY(&e->env->return_path) && return_path[0])
317 mutt_addrlist_parse(&e->env->return_path, return_path);
318
319 if (TAILQ_EMPTY(&e->env->from))
320 mutt_addrlist_copy(&e->env->from, &e->env->return_path, false);
321
322 m->msg_count++;
323 }
324 else
325 {
326 mutt_debug(LL_DEBUG1, "corrupt mailbox\n");
327 mutt_error(_("Mailbox is corrupt"));
328 goto fail;
329 }
330 }
331
332 if (SigInt)
333 {
334 SigInt = false;
335 rc = MX_OPEN_ABORT; /* action aborted */
336 goto fail;
337 }
338
339 rc = MX_OPEN_OK;
340fail:
341 progress_free(&progress);
342 return rc;
343}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:776
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:481
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:216
struct Email * email_new(void)
Create a new Email.
Definition email.c:77
void email_free(struct Email **ptr)
Free an Email.
Definition email.c:46
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition parse.c:1325
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:1475
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
@ MUTT_STAT_ATIME
File/dir's atime - last accessed time.
Definition file.h:58
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition file.h:59
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a 'From' header line?
Definition from.c:49
#define mutt_error(...)
Definition logging2.h:94
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define MMDF_SEP
Definition lib.h:63
int mutt_date_local_tz(time_t t)
Calculate the local timezone in seconds east of UTC.
Definition date.c:220
#define _(a)
Definition message.h:28
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
void mx_alloc_memory(struct Mailbox *m, int req_size)
Create storage for the emails.
Definition mx.c:1211
MxOpenReturns
Return values for mbox_open()
Definition mxapi.h:83
@ MX_OPEN_ERROR
Open failed with an error.
Definition mxapi.h:85
@ MX_OPEN_ABORT
Open was aborted.
Definition mxapi.h:86
@ MX_OPEN_OK
Open succeeded.
Definition mxapi.h:84
@ 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__
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition progress.c:80
#define TAILQ_EMPTY(head)
Definition queue.h:778
volatile sig_atomic_t SigInt
true after SIGINT is received
Definition signal.c:68
LOFF_T offset
offset where the actual data begins
Definition body.h:52
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
The envelope/body of an email.
Definition email.h:39
struct Envelope * env
Envelope information.
Definition email.h:68
int lines
How many lines in the body of this message?
Definition email.h:62
struct Body * body
List of MIME parts.
Definition email.h:69
LOFF_T offset
Where in the stream does this message begin?
Definition email.h:71
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
struct AddressList return_path
Return path for the Email.
Definition envelope.h:58
struct AddressList from
Email's 'From' list.
Definition envelope.h:59
int msg_count
Total number of messages.
Definition mailbox.h:90
struct Email ** emails
Array of Emails.
Definition mailbox.h:98
off_t size
Size of the Mailbox.
Definition mailbox.h:86
bool verbose
Display status messages?
Definition mailbox.h:119
FILE * fp
Mailbox file.
Definition lib.h:51
struct timespec atime
File's last-access time.
Definition lib.h:53
struct timespec mtime
Time Mailbox was last changed.
Definition lib.h:52
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mbox_parse_mailbox()

static enum MxOpenReturns mbox_parse_mailbox ( struct Mailbox * m)
static

Read a mailbox from disk.

Parameters
mMailbox
Return values
enumMxOpenReturns

Note that this function is also called when new mail is appended to the currently open folder, and NOT just when the mailbox is initially read.

Note
It is assumed that the mailbox being read has been locked before this routine gets called. Strange things could happen if it's not!

Definition at line 356 of file mbox.c.

357{
358 if (!m)
359 return MX_OPEN_ERROR;
360
362 if (!adata)
363 return MX_OPEN_ERROR;
364
365 struct stat st = { 0 };
366 char buf[8192] = { 0 };
367 char return_path[1024] = { 0 };
368 struct Email *e_cur = NULL;
369 time_t t = 0;
370 int count = 0;
371 int lines = 0;
372 bool has_mbox_sep = false;
373 bool expect_from_line = true;
374 LOFF_T loc;
375 struct Progress *progress = NULL;
377
378 /* Save information about the folder at the time we opened it. */
379 if (stat(mailbox_path(m), &st) == -1)
380 {
381 mutt_perror("%s", mailbox_path(m));
382 goto fail;
383 }
384
385 m->size = st.st_size;
388
389 if (!m->readonly)
390 m->readonly = access(mailbox_path(m), W_OK) ? true : false;
391
392 if (m->verbose)
393 {
394 progress = progress_new(MUTT_PROGRESS_READ, 0);
395 progress_set_message(progress, _("Reading %s..."), mailbox_path(m));
396 }
397
398 loc = ftello(adata->fp);
399 if (loc < 0)
400 {
401 mutt_debug(LL_DEBUG1, "ftello: %s (errno %d)\n", strerror(errno), errno);
402 loc = 0;
403 }
404
405 while ((fgets(buf, sizeof(buf), adata->fp)) && !SigInt)
406 {
407 if (is_from(buf, return_path, sizeof(return_path), &t))
408 {
409 /* Save the Content-Length of the previous message */
410 if (count > 0)
411 {
412 struct Email *e = m->emails[m->msg_count - 1];
413 if (!has_mbox_sep)
414 {
415 mutt_debug(LL_DEBUG1, "mbox_parse_mailbox: missing separator at location: " OFF_T_FMT "\n",
416 loc);
417 }
418 if (e->body->length < 0)
419 {
420 e->body->length = loc - e->body->offset - (has_mbox_sep ? 1 : 0);
421 if (e->body->length < 0)
422 e->body->length = 0;
423 }
424 if (e->lines == 0)
425 e->lines = lines ? lines - 1 : 0;
426 }
427
428 count++;
429 expect_from_line = false;
430
431 progress_update(progress, count, (int) (ftello(adata->fp) / (m->size / 100 + 1)));
432
434
435 m->emails[m->msg_count] = email_new();
436 e_cur = m->emails[m->msg_count];
437 e_cur->received = t - mutt_date_local_tz(t);
438 e_cur->offset = loc;
439 e_cur->index = m->msg_count;
440
441 e_cur->env = mutt_rfc822_read_header(adata->fp, e_cur, false, false);
442
443 /* if we know how long this message is, either just skip over the body,
444 * or if we don't know how many lines there are, count them now (this will
445 * save time by not having to search for the next message marker). */
446 if (e_cur->body->length > 0)
447 {
448 LOFF_T tmploc;
449
450 loc = ftello(adata->fp);
451 if (loc < 0)
452 {
453 mutt_debug(LL_DEBUG1, "ftello: %s (errno %d)\n", strerror(errno), errno);
454 loc = 0;
455 }
456
457 /* The test below avoids a potential integer overflow if the
458 * content-length is huge (thus necessarily invalid). */
459 tmploc = (e_cur->body->length < m->size) ? (loc + e_cur->body->length + 1) : -1;
460
461 if ((tmploc > 0) && (tmploc < m->size))
462 {
463 /* check to see if the content-length looks valid. we expect to
464 * to see a valid message separator at this point in the stream */
465 if (!mutt_file_seek(adata->fp, tmploc, SEEK_SET) ||
466 !fgets(buf, sizeof(buf), adata->fp) || !mutt_str_startswith(buf, "From "))
467 {
468 mutt_debug(LL_DEBUG1, "bad content-length in message %d (cl=" OFF_T_FMT ")\n",
469 e_cur->index, e_cur->body->length);
470 mutt_debug(LL_DEBUG1, " LINE: %s", buf);
471 /* nope, return the previous position */
472 (void) mutt_file_seek(adata->fp, loc, SEEK_SET);
473 e_cur->body->length = -1;
474 }
475 }
476 else if (tmploc != m->size)
477 {
478 /* content-length would put us past the end of the file, so it
479 * must be wrong */
480 e_cur->body->length = -1;
481 }
482
483 if (e_cur->body->length != -1)
484 {
485 /* good content-length. check to see if we know how many lines
486 * are in this message. */
487 if (e_cur->lines == 0)
488 {
489 LOFF_T cl = e_cur->body->length;
490
491 /* count the number of lines in this message */
492 (void) mutt_file_seek(adata->fp, loc, SEEK_SET);
493 while (cl-- > 0)
494 {
495 if (fgetc(adata->fp) == '\n')
496 e_cur->lines++;
497 }
498 }
499
500 /* return to the offset of the next *mbox* separator */
501 (void) mutt_file_seek(adata->fp, tmploc - 1, SEEK_SET);
502 expect_from_line = true;
503 }
504 }
505
506 m->msg_count++;
507
508 if (TAILQ_EMPTY(&e_cur->env->return_path) && return_path[0])
509 {
510 mutt_addrlist_parse(&e_cur->env->return_path, return_path);
511 }
512
513 if (TAILQ_EMPTY(&e_cur->env->from))
514 mutt_addrlist_copy(&e_cur->env->from, &e_cur->env->return_path, false);
515
516 lines = 0;
517 has_mbox_sep = false;
518 }
519 else
520 {
521 lines++;
522 has_mbox_sep = mutt_str_equal(MBOX_SEP, buf);
523 if (expect_from_line && !has_mbox_sep)
524 {
525 mutt_debug(LL_DEBUG1, "mbox_parse_mailbox: missing From_ line at location: " OFF_T_FMT "\n",
526 loc);
527 mutt_error(_("Mailbox is corrupt"));
528 goto fail;
529 }
530 }
531
532 loc = ftello(adata->fp);
533 }
534
535 /* Only set the content-length of the previous message if we have read more
536 * than one message during _this_ invocation. If this routine is called
537 * when new mail is received, we need to make sure not to clobber what
538 * previously was the last message since the headers may be sorted. */
539 if (count > 0)
540 {
541 struct Email *e = m->emails[m->msg_count - 1];
542 if (!has_mbox_sep)
543 {
545 "mbox_parse_mailbox: missing separator at location: " OFF_T_FMT "\n", loc);
546 }
547 if (e->body->length < 0)
548 {
549 e->body->length = ftello(adata->fp) - e->body->offset - (has_mbox_sep ? 1 : 0);
550 if (e->body->length < 0)
551 e->body->length = 0;
552 }
553
554 if (e->lines == 0)
555 e->lines = lines ? lines - 1 : 0;
556 }
557
558 if (SigInt)
559 {
560 SigInt = false;
561 rc = MX_OPEN_ABORT;
562 goto fail; /* action aborted */
563 }
564
565 rc = MX_OPEN_OK;
566fail:
567 progress_free(&progress);
568 return rc;
569}
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
#define MBOX_SEP
Definition mx.h:69
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ reopen_mailbox()

static int reopen_mailbox ( struct Mailbox * m)
static

Close and reopen a mailbox.

Parameters
mMailbox
Return values
>0Success, e.g. MX_STATUS_REOPENED, MX_STATUS_NEW_MAIL
-1Error

Definition at line 577 of file mbox.c.

578{
579 if (!m)
580 return -1;
581
583 if (!adata)
584 return -1;
585
586 bool (*cmp_headers)(const struct Email *, const struct Email *) = NULL;
587 struct Email **e_old = NULL;
588 int old_msg_count;
589 bool msg_mod = false;
590 int rc = -1;
591
592 /* silent operations */
593 m->verbose = false;
594
595 /* our heuristics require the old mailbox to be unsorted */
596 const enum EmailSortType c_sort = cs_subset_sort(NeoMutt->sub, "sort");
597 if (c_sort != EMAIL_SORT_UNSORTED)
598 {
601 cs_subset_str_native_set(NeoMutt->sub, "sort", c_sort, NULL);
602 }
603
604 e_old = NULL;
605 old_msg_count = 0;
606
607 /* simulate a close */
611 FREE(&m->v2r);
612 if (m->readonly)
613 {
614 for (int i = 0; i < m->msg_count; i++)
615 email_free(&(m->emails[i])); /* nothing to do! */
616 FREE(&m->emails);
617 }
618 else
619 {
620 /* save the old headers */
621 old_msg_count = m->msg_count;
622 e_old = m->emails;
623 m->emails = NULL;
624 }
625
626 m->email_max = 0; /* force allocation of new headers */
627 m->msg_count = 0;
628 m->vcount = 0;
629 m->msg_tagged = 0;
630 m->msg_deleted = 0;
631 m->msg_new = 0;
632 m->msg_unread = 0;
633 m->msg_flagged = 0;
634 m->changed = false;
635 m->id_hash = NULL;
636 m->subj_hash = NULL;
638
639 switch (m->type)
640 {
641 case MUTT_MBOX:
642 case MUTT_MMDF:
643 cmp_headers = email_cmp_strict;
644 mutt_file_fclose(&adata->fp);
645 adata->fp = mutt_file_fopen(mailbox_path(m), "r");
646 if (!adata->fp)
647 rc = -1;
648 else if (m->type == MUTT_MBOX)
649 rc = mbox_parse_mailbox(m);
650 else
651 rc = mmdf_parse_mailbox(m);
652 break;
653
654 default:
655 rc = -1;
656 break;
657 }
658
659 if (rc == -1)
660 {
661 /* free the old headers */
662 for (int i = 0; i < old_msg_count; i++)
663 email_free(&(e_old[i]));
664 FREE(&e_old);
665
666 m->verbose = true;
667 return -1;
668 }
669
670 mutt_file_touch_atime(fileno(adata->fp));
671
672 /* now try to recover the old flags */
673
674 if (!m->readonly)
675 {
676 for (int i = 0; i < m->msg_count; i++)
677 {
678 bool found = false;
679
680 /* some messages have been deleted, and new messages have been
681 * appended at the end; the heuristic is that old messages have then
682 * "advanced" towards the beginning of the folder, so we begin the
683 * search at index "i" */
684 int j = 0;
685 for (j = i; j < old_msg_count; j++)
686 {
687 if (!e_old[j])
688 continue;
689 if (cmp_headers(m->emails[i], e_old[j]))
690 {
691 found = true;
692 break;
693 }
694 }
695 if (!found)
696 {
697 for (j = 0; (j < i) && (j < old_msg_count); j++)
698 {
699 if (!e_old[j])
700 continue;
701 if (cmp_headers(m->emails[i], e_old[j]))
702 {
703 found = true;
704 break;
705 }
706 }
707 }
708
709 if (found)
710 {
711 m->changed = true;
712 if (e_old[j]->changed)
713 {
714 /* Only update the flags if the old header was changed;
715 * otherwise, the header may have been modified externally,
716 * and we don't want to lose _those_ changes */
717 mutt_set_flag(m, m->emails[i], MUTT_FLAG, e_old[j]->flagged, true);
718 mutt_set_flag(m, m->emails[i], MUTT_REPLIED, e_old[j]->replied, true);
719 mutt_set_flag(m, m->emails[i], MUTT_OLD, e_old[j]->old, true);
720 mutt_set_flag(m, m->emails[i], MUTT_READ, e_old[j]->read, true);
721 }
722 mutt_set_flag(m, m->emails[i], MUTT_DELETE, e_old[j]->deleted, true);
723 mutt_set_flag(m, m->emails[i], MUTT_PURGE, e_old[j]->purge, true);
724 mutt_set_flag(m, m->emails[i], MUTT_TAG, e_old[j]->tagged, true);
725
726 /* we don't need this header any more */
727 email_free(&(e_old[j]));
728 }
729 }
730
731 /* free the remaining old emails */
732 for (int j = 0; j < old_msg_count; j++)
733 {
734 if (e_old[j])
735 {
736 email_free(&(e_old[j]));
737 msg_mod = true;
738 }
739 }
740 FREE(&e_old);
741 }
742
744 m->verbose = true;
745
746 return (m->changed || msg_mod) ? MX_STATUS_REOPENED : MX_STATUS_NEW_MAIL;
747}
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition helpers.c:266
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:183
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition mailbox.h:184
bool email_cmp_strict(const struct Email *e1, const struct Email *e2)
Strictly compare message emails.
Definition email.c:96
void mutt_make_label_hash(struct Mailbox *m)
Create a Hash Table to store the labels.
Definition header.c:406
EmailSortType
Methods for sorting Emails.
Definition sort.h:53
@ EMAIL_SORT_UNSORTED
Sort by the order the messages appear in the mailbox.
Definition sort.h:64
void mutt_file_touch_atime(int fd)
Set the access time to current time.
Definition file.c:961
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition flags.c:54
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition hash.c:460
static enum MxOpenReturns mbox_parse_mailbox(struct Mailbox *m)
Read a mailbox from disk.
Definition mbox.c:356
static enum MxOpenReturns mmdf_parse_mailbox(struct Mailbox *m)
Read a mailbox in MMDF format.
Definition mbox.c:180
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
@ MUTT_READ
Messages that have been read.
Definition mutt.h:92
@ MUTT_OLD
Old messages.
Definition mutt.h:90
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition mutt.h:96
@ MUTT_TAG
Tagged messages.
Definition mutt.h:99
@ MUTT_FLAG
Flagged messages.
Definition mutt.h:98
@ MUTT_DELETE
Messages to be deleted.
Definition mutt.h:94
@ MUTT_REPLIED
Messages that have been replied to.
Definition mutt.h:91
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition mxapi.h:75
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition mxapi.h:73
bool changed
Email has been edited.
Definition email.h:77
int vcount
The number of virtual messages.
Definition mailbox.h:101
bool changed
Mailbox has been modified.
Definition mailbox.h:112
int * v2r
Mapping from virtual to real msgno.
Definition mailbox.h:100
int msg_new
Number of new messages.
Definition mailbox.h:94
int email_max
Size of emails array.
Definition mailbox.h:99
struct HashTable * subj_hash
Hash Table: "Subject" -> Email.
Definition mailbox.h:126
struct HashTable * id_hash
Hash Table: "Message-ID" -> Email.
Definition mailbox.h:125
int msg_deleted
Number of deleted messages.
Definition mailbox.h:95
struct HashTable * label_hash
Hash Table: "X-Label" -> Email.
Definition mailbox.h:127
int msg_flagged
Number of flagged messages.
Definition mailbox.h:92
int msg_tagged
How many messages are tagged?
Definition mailbox.h:96
int msg_unread
Number of unread messages.
Definition mailbox.h:91
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition subset.c:303
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mbox_has_new()

static bool mbox_has_new ( struct Mailbox * m)
static

Does the mailbox have new mail.

Parameters
mMailbox
Return values
trueThe mailbox has at least 1 new messages (not old)
falseotherwise

Definition at line 755 of file mbox.c.

756{
757 for (int i = 0; i < m->msg_count; i++)
758 {
759 struct Email *e = m->emails[i];
760 if (!e)
761 break;
762 if (!e->deleted && !e->read && !e->old)
763 return true;
764 }
765 return false;
766}
bool read
Email is read.
Definition email.h:50
bool old
Email is seen, but unread.
Definition email.h:49
bool deleted
Email is deleted.
Definition email.h:78
+ Here is the caller graph for this function:

◆ mbox_reset_atime()

void mbox_reset_atime ( struct Mailbox * m,
struct stat * st )

Reset the access time on the mailbox file.

Parameters
mMailbox
stTimestamp

if mailbox has at least 1 new message, sets mtime > atime of mailbox so mailbox check reports new mail

Definition at line 776 of file mbox.c.

777{
778 struct stat st2 = { 0 };
779 if (!st)
780 {
781 if (stat(mailbox_path(m), &st2) < 0)
782 return;
783 st = &st2;
784 }
785
786 struct utimbuf utimebuf = { 0 };
787 utimebuf.actime = st->st_atime;
788 utimebuf.modtime = st->st_mtime;
789
790 /* When $mbox_check_recent is set, existing new mail is ignored, so do not
791 * reset the atime to mtime-1 to signal new mail. */
792 const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
793 if (!c_mail_check_recent && (utimebuf.actime >= utimebuf.modtime) && mbox_has_new(m))
794 {
795 utimebuf.actime = utimebuf.modtime - 1;
796 }
797
798 utime(mailbox_path(m), &utimebuf);
799}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
static bool mbox_has_new(struct Mailbox *m)
Does the mailbox have new mail.
Definition mbox.c:755
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mbox_open_readwrite()

static FILE * mbox_open_readwrite ( struct Mailbox * m)
static

Open an mbox read-write.

Parameters
mMailbox
Return values
ptrFILE handle

This function ensures that the FILE and readonly flag are changed atomically.

Definition at line 831 of file mbox.c.

832{
833 FILE *fp = mutt_file_fopen(mailbox_path(m), "r+");
834 if (fp)
835 m->readonly = false;
836 return fp;
837}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mbox_open_readonly()

static FILE * mbox_open_readonly ( struct Mailbox * m)
static

Open an mbox read-only.

Parameters
mMailbox
Return values
ptrFILE handle

This function ensures that the FILE and readonly flag are changed atomically.

Definition at line 846 of file mbox.c.

847{
848 FILE *fp = mutt_file_fopen(mailbox_path(m), "r");
849 if (fp)
850 m->readonly = true;
851 return fp;
852}
+ Here is the call graph for this function:
+ Here is the caller graph for this function: