NeoMutt  2025-12-11-694-ga89709
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:101
struct Account * account
Account that owns this Mailbox.
Definition mailbox.h:126
+ 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:115
+ 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:1135
+ 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, tmploc;
195 struct Email *e = NULL;
196 struct stat st = { 0 };
197 struct Progress *progress = NULL;
199
200 /* Record mailbox timestamps and size for change detection */
201 if (stat(mailbox_path(m), &st) == -1)
202 {
203 mutt_perror("%s", mailbox_path(m));
204 goto fail;
205 }
208 m->size = st.st_size;
209
210 if (m->verbose)
211 {
212 progress = progress_new(MUTT_PROGRESS_READ, 0);
213 progress_set_message(progress, _("Reading %s..."), mailbox_path(m));
214 }
215
216 /* Read the file line-by-line looking for MMDF separator lines ("\001\001\001\001\n") */
217 while (true)
218 {
219 if (!fgets(buf, sizeof(buf) - 1, adata->fp))
220 break;
221
222 if (SigInt)
223 break;
224
225 if (mutt_str_equal(buf, MMDF_SEP))
226 {
227 loc = ftello(adata->fp);
228 if (loc < 0)
229 goto fail;
230
231 count++;
232 progress_update(progress, count, (int) (loc / (m->size / 100 + 1)));
233
234 /* Allocate a new Email for this message */
236 e = email_new();
237 m->emails[m->msg_count] = e;
238 e->offset = loc;
239 e->index = m->msg_count;
240
241 if (!fgets(buf, sizeof(buf) - 1, adata->fp))
242 {
243 mutt_debug(LL_DEBUG1, "unexpected EOF\n");
244 email_free(&m->emails[m->msg_count]);
245 break;
246 }
247
248 /* Try to parse "From " line for return path and date */
249 return_path[0] = '\0';
250
251 if (!is_from(buf, return_path, sizeof(return_path), &t))
252 {
253 if (!mutt_file_seek(adata->fp, loc, SEEK_SET))
254 {
255 mutt_error(_("Mailbox is corrupt"));
256 goto fail;
257 }
258 }
259 else
260 {
261 e->received = t - mutt_date_local_tz(t);
262 }
263
264 /* Parse RFC 822 headers to populate the envelope */
265 e->env = mutt_rfc822_read_header(adata->fp, e, false, false);
266
267 loc = ftello(adata->fp);
268 if (loc < 0)
269 goto fail;
270
271 /* Try to validate the Content-Length by seeking to the expected end
272 * and verifying an MMDF separator is there */
273 if ((e->body->length > 0) && (e->lines > 0))
274 {
275 tmploc = loc + e->body->length;
276
277 if ((tmploc > 0) && (tmploc < m->size))
278 {
279 if (!mutt_file_seek(adata->fp, tmploc, SEEK_SET) ||
280 !fgets(buf, sizeof(buf) - 1, adata->fp) || !mutt_str_equal(MMDF_SEP, buf))
281 {
282 (void) mutt_file_seek(adata->fp, loc, SEEK_SET);
283 e->body->length = -1;
284 }
285 }
286 else
287 {
288 e->body->length = -1;
289 }
290 }
291 else
292 {
293 e->body->length = -1;
294 }
295
296 /* If Content-Length was missing or invalid, scan for the next separator */
297 if (e->body->length < 0)
298 {
299 lines = -1;
300 do
301 {
302 loc = ftello(adata->fp);
303 if (loc < 0)
304 goto fail;
305 if (!fgets(buf, sizeof(buf) - 1, adata->fp))
306 break;
307 lines++;
308 } while (!mutt_str_equal(buf, MMDF_SEP));
309
310 e->lines = lines;
311 e->body->length = loc - e->body->offset;
312 }
313
314 /* Populate return path and from address if missing from headers */
315 if (TAILQ_EMPTY(&e->env->return_path) && return_path[0])
316 mutt_addrlist_parse(&e->env->return_path, return_path);
317
318 if (TAILQ_EMPTY(&e->env->from))
319 mutt_addrlist_copy(&e->env->from, &e->env->return_path, false);
320
321 m->msg_count++;
322 }
323 else
324 {
325 mutt_debug(LL_DEBUG1, "corrupt mailbox\n");
326 mutt_error(_("Mailbox is corrupt"));
327 goto fail;
328 }
329 }
330
331 if (SigInt)
332 {
333 SigInt = false;
334 rc = MX_OPEN_ABORT; /* action aborted */
335 goto fail;
336 }
337
338 rc = MX_OPEN_OK;
339fail:
340 progress_free(&progress);
341 return rc;
342}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:774
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:480
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:213
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:1210
void mutt_file_get_stat_timespec(struct timespec *dest, struct stat *st, enum MuttStatType type)
Read the stat() time into a time value.
Definition file.c:1474
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:53
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition file.h:54
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:665
void mx_alloc_memory(struct Mailbox *m, int req_size)
Create storage for the emails.
Definition mx.c:1208
MxOpenReturns
Return values for mbox_open()
Definition mxapi.h:72
@ MX_OPEN_ERROR
Open failed with an error.
Definition mxapi.h:74
@ MX_OPEN_ABORT
Open was aborted.
Definition mxapi.h:75
@ MX_OPEN_OK
Open succeeded.
Definition mxapi.h:73
@ 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:87
struct Email ** emails
Array of Emails.
Definition mailbox.h:95
off_t size
Size of the Mailbox.
Definition mailbox.h:83
bool verbose
Display status messages?
Definition mailbox.h:116
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 355 of file mbox.c.

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

553{
554 if (!m)
555 return -1;
556
558 if (!adata)
559 return -1;
560
561 bool (*cmp_headers)(const struct Email *, const struct Email *) = NULL;
562 struct Email **e_old = NULL;
563 int old_msg_count;
564 bool msg_mod = false;
565 int rc = -1;
566
567 /* silent operations */
568 m->verbose = false;
569
570 /* our heuristics require the old mailbox to be unsorted */
571 const enum EmailSortType c_sort = cs_subset_sort(NeoMutt->sub, "sort");
572 if (c_sort != EMAIL_SORT_UNSORTED)
573 {
576 cs_subset_str_native_set(NeoMutt->sub, "sort", c_sort, NULL);
577 }
578
579 e_old = NULL;
580 old_msg_count = 0;
581
582 /* simulate a close */
586 FREE(&m->v2r);
587 if (m->readonly)
588 {
589 for (int i = 0; i < m->msg_count; i++)
590 email_free(&(m->emails[i])); /* nothing to do! */
591 FREE(&m->emails);
592 }
593 else
594 {
595 /* save the old headers */
596 old_msg_count = m->msg_count;
597 e_old = m->emails;
598 m->emails = NULL;
599 }
600
601 m->email_max = 0; /* force allocation of new headers */
602 m->msg_count = 0;
603 m->vcount = 0;
604 m->msg_tagged = 0;
605 m->msg_deleted = 0;
606 m->msg_new = 0;
607 m->msg_unread = 0;
608 m->msg_flagged = 0;
609 m->changed = false;
610 m->id_hash = NULL;
611 m->subj_hash = NULL;
613
614 switch (m->type)
615 {
616 case MUTT_MBOX:
617 case MUTT_MMDF:
618 cmp_headers = email_cmp_strict;
619 mutt_file_fclose(&adata->fp);
620 adata->fp = mutt_file_fopen(mailbox_path(m), "r");
621 if (!adata->fp)
622 rc = -1;
623 else if (m->type == MUTT_MBOX)
624 rc = mbox_parse_mailbox(m);
625 else
626 rc = mmdf_parse_mailbox(m);
627 break;
628
629 default:
630 rc = -1;
631 break;
632 }
633
634 if (rc == -1)
635 {
636 /* free the old headers */
637 for (int i = 0; i < old_msg_count; i++)
638 email_free(&(e_old[i]));
639 FREE(&e_old);
640
641 m->verbose = true;
642 return -1;
643 }
644
645 mutt_file_touch_atime(fileno(adata->fp));
646
647 /* now try to recover the old flags */
648
649 if (!m->readonly)
650 {
651 for (int i = 0; i < m->msg_count; i++)
652 {
653 bool found = false;
654
655 /* some messages have been deleted, and new messages have been
656 * appended at the end; the heuristic is that old messages have then
657 * "advanced" towards the beginning of the folder, so we begin the
658 * search at index "i" */
659 int j;
660 for (j = i; j < old_msg_count; j++)
661 {
662 if (!e_old[j])
663 continue;
664 if (cmp_headers(m->emails[i], e_old[j]))
665 {
666 found = true;
667 break;
668 }
669 }
670 if (!found)
671 {
672 for (j = 0; (j < i) && (j < old_msg_count); j++)
673 {
674 if (!e_old[j])
675 continue;
676 if (cmp_headers(m->emails[i], e_old[j]))
677 {
678 found = true;
679 break;
680 }
681 }
682 }
683
684 if (found)
685 {
686 m->changed = true;
687 if (e_old[j]->changed)
688 {
689 /* Only update the flags if the old header was changed;
690 * otherwise, the header may have been modified externally,
691 * and we don't want to lose _those_ changes */
692 mutt_set_flag(m, m->emails[i], MUTT_FLAG, e_old[j]->flagged, true);
693 mutt_set_flag(m, m->emails[i], MUTT_REPLIED, e_old[j]->replied, true);
694 mutt_set_flag(m, m->emails[i], MUTT_OLD, e_old[j]->old, true);
695 mutt_set_flag(m, m->emails[i], MUTT_READ, e_old[j]->read, true);
696 }
697 mutt_set_flag(m, m->emails[i], MUTT_DELETE, e_old[j]->deleted, true);
698 mutt_set_flag(m, m->emails[i], MUTT_PURGE, e_old[j]->purge, true);
699 mutt_set_flag(m, m->emails[i], MUTT_TAG, e_old[j]->tagged, true);
700
701 /* we don't need this header any more */
702 email_free(&(e_old[j]));
703 }
704 }
705
706 /* free the remaining old emails */
707 for (int j = 0; j < old_msg_count; j++)
708 {
709 if (e_old[j])
710 {
711 email_free(&(e_old[j]));
712 msg_mod = true;
713 }
714 }
715 FREE(&e_old);
716 }
717
719 m->verbose = true;
720
721 return (m->changed || msg_mod) ? MX_STATUS_REOPENED : MX_STATUS_NEW_MAIL;
722}
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:180
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition mailbox.h:181
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:405
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:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
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:459
static enum MxOpenReturns mbox_parse_mailbox(struct Mailbox *m)
Read a mailbox from disk.
Definition mbox.c:355
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:64
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition mxapi.h:62
bool changed
Email has been edited.
Definition email.h:77
int vcount
The number of virtual messages.
Definition mailbox.h:98
bool changed
Mailbox has been modified.
Definition mailbox.h:109
int * v2r
Mapping from virtual to real msgno.
Definition mailbox.h:97
int msg_new
Number of new messages.
Definition mailbox.h:91
int email_max
Size of emails array.
Definition mailbox.h:96
struct HashTable * subj_hash
Hash Table: "Subject" -> Email.
Definition mailbox.h:123
struct HashTable * id_hash
Hash Table: "Message-ID" -> Email.
Definition mailbox.h:122
int msg_deleted
Number of deleted messages.
Definition mailbox.h:92
struct HashTable * label_hash
Hash Table: "X-Label" -> Email.
Definition mailbox.h:124
int msg_flagged
Number of flagged messages.
Definition mailbox.h:89
int msg_tagged
How many messages are tagged?
Definition mailbox.h:93
int msg_unread
Number of unread messages.
Definition mailbox.h:88
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 730 of file mbox.c.

731{
732 for (int i = 0; i < m->msg_count; i++)
733 {
734 struct Email *e = m->emails[i];
735 if (!e)
736 break;
737 if (!e->deleted && !e->read && !e->old)
738 return true;
739 }
740 return false;
741}
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 751 of file mbox.c.

752{
753 struct stat st2 = { 0 };
754 if (!st)
755 {
756 if (stat(mailbox_path(m), &st2) < 0)
757 return;
758 st = &st2;
759 }
760
761 struct utimbuf utimebuf = { 0 };
762 utimebuf.actime = st->st_atime;
763 utimebuf.modtime = st->st_mtime;
764
765 /* When $mbox_check_recent is set, existing new mail is ignored, so do not
766 * reset the atime to mtime-1 to signal new mail. */
767 const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
768 if (!c_mail_check_recent && (utimebuf.actime >= utimebuf.modtime) && mbox_has_new(m))
769 {
770 utimebuf.actime = utimebuf.modtime - 1;
771 }
772
773 utime(mailbox_path(m), &utimebuf);
774}
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:730
+ 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 806 of file mbox.c.

807{
808 FILE *fp = mutt_file_fopen(mailbox_path(m), "r+");
809 if (fp)
810 m->readonly = false;
811 return fp;
812}
+ 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 821 of file mbox.c.

822{
823 FILE *fp = mutt_file_fopen(mailbox_path(m), "r");
824 if (fp)
825 m->readonly = true;
826 return fp;
827}
+ Here is the call graph for this function:
+ Here is the caller graph for this function: