NeoMutt  2024-10-02-37-gfa9146
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 "copy.h"
#include "globals.h"
#include "mutt_header.h"
#include "muttlib.h"
#include "mx.h"
#include "protos.h"
#include "sort.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? - Implements MxOps::path_probe() -.
 
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 95 of file mbox.c.

96{
97 return mutt_mem_calloc(1, sizeof(struct MboxAccountData));
98}
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:51
Mbox-specific Account data -.
Definition: lib.h:49
+ Here is the call graph for this function:
+ 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 106 of file mbox.c.

107{
108 if (!m || !m->account)
109 return -1;
110 if ((m->type != MUTT_MBOX) && (m->type != MUTT_MMDF))
111 return -1;
112 if (m->account->adata)
113 return 0;
114
117 return 0;
118}
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:46
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:45
static void mbox_adata_free(void **ptr)
Free the private Account data - Implements Account::adata_free() -.
Definition: mbox.c:80
static struct MboxAccountData * mbox_adata_new(void)
Create a new MboxAccountData struct.
Definition: mbox.c:95
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:102
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:127
+ 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 125 of file mbox.c.

126{
127 if (init_mailbox(m) == -1)
128 return NULL;
129 return m->account->adata;
130}
static int init_mailbox(struct Mailbox *m)
Add Mbox data to the Mailbox.
Definition: mbox.c:106
+ 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 140 of file mbox.c.

141{
143 if (!adata)
144 return -1;
145
146 int rc = mutt_file_lock(fileno(adata->fp), excl, retry);
147 if (rc == 0)
148 {
149 adata->locked = true;
150 }
151 else if (retry && !excl)
152 {
153 m->readonly = true;
154 return 0;
155 }
156
157 return rc;
158}
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
Definition: file.c:1202
static struct MboxAccountData * mbox_adata_get(struct Mailbox *m)
Get the private data associated with a Mailbox.
Definition: mbox.c:125
bool readonly
Don't allow changes to the mailbox.
Definition: mailbox.h:116
+ 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 164 of file mbox.c.

165{
167 if (!adata)
168 return;
169
170 if (adata->locked)
171 {
172 fflush(adata->fp);
173
174 mutt_file_unlock(fileno(adata->fp));
175 adata->locked = false;
176 }
177}
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition: file.c:1249
+ 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 184 of file mbox.c.

185{
186 if (!m)
187 return MX_OPEN_ERROR;
188
190 if (!adata)
191 return MX_OPEN_ERROR;
192
193 char buf[8192] = { 0 };
194 char return_path[1024] = { 0 };
195 int count = 0;
196 int lines;
197 time_t t = 0;
198 LOFF_T loc, tmploc;
199 struct Email *e = NULL;
200 struct stat st = { 0 };
201 struct Progress *progress = NULL;
203
204 if (stat(mailbox_path(m), &st) == -1)
205 {
206 mutt_perror("%s", mailbox_path(m));
207 goto fail;
208 }
211 m->size = st.st_size;
212
213 buf[sizeof(buf) - 1] = '\0';
214
215 if (m->verbose)
216 {
217 progress = progress_new(MUTT_PROGRESS_READ, 0);
218 progress_set_message(progress, _("Reading %s..."), mailbox_path(m));
219 }
220
221 while (true)
222 {
223 if (!fgets(buf, sizeof(buf) - 1, adata->fp))
224 break;
225
226 if (SigInt)
227 break;
228
229 if (mutt_str_equal(buf, MMDF_SEP))
230 {
231 loc = ftello(adata->fp);
232 if (loc < 0)
233 goto fail;
234
235 count++;
236 progress_update(progress, count, (int) (loc / (m->size / 100 + 1)));
237
239 e = email_new();
240 m->emails[m->msg_count] = e;
241 e->offset = loc;
242 e->index = m->msg_count;
243
244 if (!fgets(buf, sizeof(buf) - 1, adata->fp))
245 {
246 /* TODO: memory leak??? */
247 mutt_debug(LL_DEBUG1, "unexpected EOF\n");
248 break;
249 }
250
251 return_path[0] = '\0';
252
253 if (!is_from(buf, return_path, sizeof(return_path), &t))
254 {
255 if (!mutt_file_seek(adata->fp, loc, SEEK_SET))
256 {
257 mutt_error(_("Mailbox is corrupt"));
258 goto fail;
259 }
260 }
261 else
262 {
263 e->received = t - mutt_date_local_tz(t);
264 }
265
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 if ((e->body->length > 0) && (e->lines > 0))
273 {
274 tmploc = loc + e->body->length;
275
276 if ((tmploc > 0) && (tmploc < m->size))
277 {
278 if (!mutt_file_seek(adata->fp, tmploc, SEEK_SET) ||
279 !fgets(buf, sizeof(buf) - 1, adata->fp) || !mutt_str_equal(MMDF_SEP, buf))
280 {
281 (void) mutt_file_seek(adata->fp, loc, SEEK_SET);
282 e->body->length = -1;
283 }
284 }
285 else
286 {
287 e->body->length = -1;
288 }
289 }
290 else
291 {
292 e->body->length = -1;
293 }
294
295 if (e->body->length < 0)
296 {
297 lines = -1;
298 do
299 {
300 loc = ftello(adata->fp);
301 if (loc < 0)
302 goto fail;
303 if (!fgets(buf, sizeof(buf) - 1, adata->fp))
304 break;
305 lines++;
306 } while (!mutt_str_equal(buf, MMDF_SEP));
307
308 e->lines = lines;
309 e->body->length = loc - e->body->offset;
310 }
311
312 if (TAILQ_EMPTY(&e->env->return_path) && return_path[0])
313 mutt_addrlist_parse(&e->env->return_path, return_path);
314
315 if (TAILQ_EMPTY(&e->env->from))
316 mutt_addrlist_copy(&e->env->from, &e->env->return_path, false);
317
318 m->msg_count++;
319 }
320 else
321 {
322 mutt_debug(LL_DEBUG1, "corrupt mailbox\n");
323 mutt_error(_("Mailbox is corrupt"));
324 goto fail;
325 }
326 }
327
328 if (SigInt)
329 {
330 SigInt = false;
331 rc = MX_OPEN_ABORT; /* action aborted */
332 goto fail;
333 }
334
335 rc = MX_OPEN_OK;
336fail:
337 progress_free(&progress);
338 return rc;
339}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:765
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:223
struct Email * email_new(void)
Create a new Email.
Definition: email.c:77
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1205
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
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:778
@ 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:92
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#define MMDF_SEP
Definition: lib.h:62
int mutt_date_local_tz(time_t t)
Calculate the local timezone in seconds east of UTC.
Definition: date.c:219
#define _(a)
Definition: message.h:28
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
void mx_alloc_memory(struct Mailbox *m, int req_size)
Create storage for the emails.
Definition: mx.c:1206
MxOpenReturns
Return values for mbox_open()
Definition: mxapi.h:76
@ MX_OPEN_ERROR
Open failed with an error.
Definition: mxapi.h:78
@ MX_OPEN_ABORT
Open was aborted.
Definition: mxapi.h:79
@ MX_OPEN_OK
Open succeeded.
Definition: mxapi.h:77
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: lib.h:82
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:139
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:110
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
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:721
volatile sig_atomic_t SigInt
true after SIGINT is received
Definition: signal.c:66
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:88
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
off_t size
Size of the Mailbox.
Definition: mailbox.h:84
bool verbose
Display status messages?
Definition: mailbox.h:117
FILE * fp
Mailbox file.
Definition: lib.h:50
struct timespec atime
File's last-access time.
Definition: lib.h:52
struct timespec mtime
Time Mailbox was last changed.
Definition: lib.h:51
+ 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 352 of file mbox.c.

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

550{
551 if (!m)
552 return -1;
553
555 if (!adata)
556 return -1;
557
558 bool (*cmp_headers)(const struct Email *, const struct Email *) = NULL;
559 struct Email **e_old = NULL;
560 int old_msg_count;
561 bool msg_mod = false;
562 int rc = -1;
563
564 /* silent operations */
565 m->verbose = false;
566
567 /* our heuristics require the old mailbox to be unsorted */
568 const enum SortType c_sort = cs_subset_sort(NeoMutt->sub, "sort");
569 if (c_sort != SORT_ORDER)
570 {
573 cs_subset_str_native_set(NeoMutt->sub, "sort", c_sort, NULL);
574 }
575
576 e_old = NULL;
577 old_msg_count = 0;
578
579 /* simulate a close */
583 FREE(&m->v2r);
584 if (m->readonly)
585 {
586 for (int i = 0; i < m->msg_count; i++)
587 email_free(&(m->emails[i])); /* nothing to do! */
588 FREE(&m->emails);
589 }
590 else
591 {
592 /* save the old headers */
593 old_msg_count = m->msg_count;
594 e_old = m->emails;
595 m->emails = NULL;
596 }
597
598 m->email_max = 0; /* force allocation of new headers */
599 m->msg_count = 0;
600 m->vcount = 0;
601 m->msg_tagged = 0;
602 m->msg_deleted = 0;
603 m->msg_new = 0;
604 m->msg_unread = 0;
605 m->msg_flagged = 0;
606 m->changed = false;
607 m->id_hash = NULL;
608 m->subj_hash = NULL;
610
611 switch (m->type)
612 {
613 case MUTT_MBOX:
614 case MUTT_MMDF:
615 cmp_headers = email_cmp_strict;
616 mutt_file_fclose(&adata->fp);
617 adata->fp = mutt_file_fopen(mailbox_path(m), "r");
618 if (!adata->fp)
619 rc = -1;
620 else if (m->type == MUTT_MBOX)
621 rc = mbox_parse_mailbox(m);
622 else
623 rc = mmdf_parse_mailbox(m);
624 break;
625
626 default:
627 rc = -1;
628 break;
629 }
630
631 if (rc == -1)
632 {
633 /* free the old headers */
634 for (int i = 0; i < old_msg_count; i++)
635 email_free(&(e_old[i]));
636 FREE(&e_old);
637
638 m->verbose = true;
639 return -1;
640 }
641
642 mutt_file_touch_atime(fileno(adata->fp));
643
644 /* now try to recover the old flags */
645
646 if (!m->readonly)
647 {
648 for (int i = 0; i < m->msg_count; i++)
649 {
650 bool found = false;
651
652 /* some messages have been deleted, and new messages have been
653 * appended at the end; the heuristic is that old messages have then
654 * "advanced" towards the beginning of the folder, so we begin the
655 * search at index "i" */
656 int j;
657 for (j = i; j < old_msg_count; j++)
658 {
659 if (!e_old[j])
660 continue;
661 if (cmp_headers(m->emails[i], e_old[j]))
662 {
663 found = true;
664 break;
665 }
666 }
667 if (!found)
668 {
669 for (j = 0; (j < i) && (j < old_msg_count); j++)
670 {
671 if (!e_old[j])
672 continue;
673 if (cmp_headers(m->emails[i], e_old[j]))
674 {
675 found = true;
676 break;
677 }
678 }
679 }
680
681 if (found)
682 {
683 m->changed = true;
684 if (e_old[j]->changed)
685 {
686 /* Only update the flags if the old header was changed;
687 * otherwise, the header may have been modified externally,
688 * and we don't want to lose _those_ changes */
689 mutt_set_flag(m, m->emails[i], MUTT_FLAG, e_old[j]->flagged, true);
690 mutt_set_flag(m, m->emails[i], MUTT_REPLIED, e_old[j]->replied, true);
691 mutt_set_flag(m, m->emails[i], MUTT_OLD, e_old[j]->old, true);
692 mutt_set_flag(m, m->emails[i], MUTT_READ, e_old[j]->read, true);
693 }
694 mutt_set_flag(m, m->emails[i], MUTT_DELETE, e_old[j]->deleted, true);
695 mutt_set_flag(m, m->emails[i], MUTT_PURGE, e_old[j]->purge, true);
696 mutt_set_flag(m, m->emails[i], MUTT_TAG, e_old[j]->tagged, true);
697
698 /* we don't need this header any more */
699 email_free(&(e_old[j]));
700 }
701 }
702
703 /* free the remaining old emails */
704 for (int j = 0; j < old_msg_count; j++)
705 {
706 if (e_old[j])
707 {
708 email_free(&(e_old[j]));
709 msg_mod = true;
710 }
711 }
712 FREE(&e_old);
713 }
714
716 m->verbose = true;
717
718 return (m->changed || msg_mod) ? MX_STATUS_REOPENED : MX_STATUS_NEW_MAIL;
719}
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:233
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:190
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition: mailbox.h:191
bool email_cmp_strict(const struct Email *e1, const struct Email *e2)
Strictly compare message emails.
Definition: email.c:96
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:46
void mutt_file_touch_atime(int fd)
Set the access time to current time.
Definition: file.c:1091
#define mutt_file_fclose(FP)
Definition: file.h:138
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:137
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:57
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:457
static enum MxOpenReturns mbox_parse_mailbox(struct Mailbox *m)
Read a mailbox from disk.
Definition: mbox.c:352
static enum MxOpenReturns mmdf_parse_mailbox(struct Mailbox *m)
Read a mailbox in MMDF format.
Definition: mbox.c:184
#define FREE(x)
Definition: memory.h:45
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:73
@ MUTT_OLD
Old messages.
Definition: mutt.h:71
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:77
@ MUTT_TAG
Tagged messages.
Definition: mutt.h:80
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:79
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:75
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:72
void mutt_make_label_hash(struct Mailbox *m)
Create a Hash Table to store the labels.
Definition: mutt_header.c:403
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:68
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:66
SortType
Methods for sorting.
Definition: sort2.h:34
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:40
bool changed
Email has been edited.
Definition: email.h:77
int vcount
The number of virtual messages.
Definition: mailbox.h:99
bool changed
Mailbox has been modified.
Definition: mailbox.h:110
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:98
int msg_new
Number of new messages.
Definition: mailbox.h:92
int email_max
Size of emails array.
Definition: mailbox.h:97
struct HashTable * subj_hash
Hash Table: "subject" -> Email.
Definition: mailbox.h:124
struct HashTable * id_hash
Hash Table: "message-id" -> Email.
Definition: mailbox.h:123
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:93
struct HashTable * label_hash
Hash Table: "x-labels" -> Email.
Definition: mailbox.h:125
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:90
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:94
int msg_unread
Number of unread messages.
Definition: mailbox.h:89
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
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:297
+ 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 727 of file mbox.c.

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

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

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

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