NeoMutt  2023-11-03-107-g582dc1
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 <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 "mutt_thread.h"
#include "muttlib.h"
#include "mx.h"
#include "protos.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
  • Michael R. Elkins
  • Richard Russon
  • 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 92 of file mbox.c.

93{
94 return mutt_mem_calloc(1, sizeof(struct MboxAccountData));
95}
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
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 103 of file mbox.c.

104{
105 if (!m || !m->account)
106 return -1;
107 if ((m->type != MUTT_MBOX) && (m->type != MUTT_MMDF))
108 return -1;
109 if (m->account->adata)
110 return 0;
111
114 return 0;
115}
static void mbox_adata_free(void **ptr)
Free the private Account data - Implements Account::adata_free() -.
Definition: mbox.c:77
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:46
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:45
static struct MboxAccountData * mbox_adata_new(void)
Create a new MboxAccountData struct.
Definition: mbox.c:92
void(* adata_free)(void **ptr)
Definition: account.h:54
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
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 122 of file mbox.c.

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

138{
140 if (!adata)
141 return -1;
142
143 int rc = mutt_file_lock(fileno(adata->fp), excl, retry);
144 if (rc == 0)
145 {
146 adata->locked = true;
147 }
148 else if (retry && !excl)
149 {
150 m->readonly = true;
151 return 0;
152 }
153
154 return rc;
155}
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
Definition: file.c:1243
static struct MboxAccountData * mbox_adata_get(struct Mailbox *m)
Get the private data associated with a Mailbox.
Definition: mbox.c:122
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 161 of file mbox.c.

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

182{
183 if (!m)
184 return MX_OPEN_ERROR;
185
187 if (!adata)
188 return MX_OPEN_ERROR;
189
190 char buf[8192] = { 0 };
191 char return_path[1024] = { 0 };
192 int count = 0;
193 int lines;
194 time_t t = 0;
195 LOFF_T loc, tmploc;
196 struct Email *e = NULL;
197 struct stat st = { 0 };
198 struct Progress *progress = NULL;
200
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 buf[sizeof(buf) - 1] = '\0';
211
212 if (m->verbose)
213 {
214 progress = progress_new(MUTT_PROGRESS_READ, 0);
215 progress_set_message(progress, _("Reading %s..."), mailbox_path(m));
216 }
217
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
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 /* TODO: memory leak??? */
244 mutt_debug(LL_DEBUG1, "unexpected EOF\n");
245 break;
246 }
247
248 return_path[0] = '\0';
249
250 if (!is_from(buf, return_path, sizeof(return_path), &t))
251 {
252 if (!mutt_file_seek(adata->fp, loc, SEEK_SET))
253 {
254 mutt_error(_("Mailbox is corrupt"));
255 goto fail;
256 }
257 }
258 else
259 {
260 e->received = t - mutt_date_local_tz(t);
261 }
262
263 e->env = mutt_rfc822_read_header(adata->fp, e, false, false);
264
265 loc = ftello(adata->fp);
266 if (loc < 0)
267 goto fail;
268
269 if ((e->body->length > 0) && (e->lines > 0))
270 {
271 tmploc = loc + e->body->length;
272
273 if ((tmploc > 0) && (tmploc < m->size))
274 {
275 if (!mutt_file_seek(adata->fp, tmploc, SEEK_SET) ||
276 !fgets(buf, sizeof(buf) - 1, adata->fp) || !mutt_str_equal(MMDF_SEP, buf))
277 {
278 (void) mutt_file_seek(adata->fp, loc, SEEK_SET);
279 e->body->length = -1;
280 }
281 }
282 else
283 {
284 e->body->length = -1;
285 }
286 }
287 else
288 {
289 e->body->length = -1;
290 }
291
292 if (e->body->length < 0)
293 {
294 lines = -1;
295 do
296 {
297 loc = ftello(adata->fp);
298 if (loc < 0)
299 goto fail;
300 if (!fgets(buf, sizeof(buf) - 1, adata->fp))
301 break;
302 lines++;
303 } while (!mutt_str_equal(buf, MMDF_SEP));
304
305 e->lines = lines;
306 e->body->length = loc - e->body->offset;
307 }
308
309 if (TAILQ_EMPTY(&e->env->return_path) && return_path[0])
310 mutt_addrlist_parse(&e->env->return_path, return_path);
311
312 if (TAILQ_EMPTY(&e->env->from))
313 mutt_addrlist_copy(&e->env->from, &e->env->return_path, false);
314
315 m->msg_count++;
316 }
317 else
318 {
319 mutt_debug(LL_DEBUG1, "corrupt mailbox\n");
320 mutt_error(_("Mailbox is corrupt"));
321 goto fail;
322 }
323 }
324
325 if (SigInt)
326 {
327 SigInt = false;
328 rc = MX_OPEN_ABORT; /* action aborted */
329 goto fail;
330 }
331
332 rc = MX_OPEN_OK;
333fail:
334 progress_free(&progress);
335 return rc;
336}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:762
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:478
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1156
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:1620
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:733
@ MUTT_STAT_ATIME
File/dir's atime - last accessed time.
Definition: file.h:63
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:64
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a 'From' header line?
Definition: from.c:48
SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: globals.c:59
#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
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
#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:209
#define _(a)
Definition: message.h:28
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:763
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: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:140
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:111
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:81
#define TAILQ_EMPTY(head)
Definition: queue.h:721
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:37
struct Envelope * env
Envelope information.
Definition: email.h:66
int lines
How many lines in the body of this message?
Definition: email.h:60
struct Body * body
List of MIME parts.
Definition: email.h:67
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:69
int index
The absolute (unsorted) message number.
Definition: email.h:111
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:59
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:116
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 349 of file mbox.c.

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

546{
547 if (!m)
548 return -1;
549
551 if (!adata)
552 return -1;
553
554 bool (*cmp_headers)(const struct Email *, const struct Email *) = NULL;
555 struct Email **e_old = NULL;
556 int old_msg_count;
557 bool msg_mod = false;
558 int rc = -1;
559
560 /* silent operations */
561 m->verbose = false;
562
563 /* our heuristics require the old mailbox to be unsorted */
564 const enum SortType c_sort = cs_subset_sort(NeoMutt->sub, "sort");
565 if (c_sort != SORT_ORDER)
566 {
569 cs_subset_str_native_set(NeoMutt->sub, "sort", c_sort, NULL);
570 }
571
572 e_old = NULL;
573 old_msg_count = 0;
574
575 /* simulate a close */
579 FREE(&m->v2r);
580 if (m->readonly)
581 {
582 for (int i = 0; i < m->msg_count; i++)
583 email_free(&(m->emails[i])); /* nothing to do! */
584 FREE(&m->emails);
585 }
586 else
587 {
588 /* save the old headers */
589 old_msg_count = m->msg_count;
590 e_old = m->emails;
591 m->emails = NULL;
592 }
593
594 m->email_max = 0; /* force allocation of new headers */
595 m->msg_count = 0;
596 m->vcount = 0;
597 m->msg_tagged = 0;
598 m->msg_deleted = 0;
599 m->msg_new = 0;
600 m->msg_unread = 0;
601 m->msg_flagged = 0;
602 m->changed = false;
603 m->id_hash = NULL;
604 m->subj_hash = NULL;
606
607 switch (m->type)
608 {
609 case MUTT_MBOX:
610 case MUTT_MMDF:
611 cmp_headers = email_cmp_strict;
612 mutt_file_fclose(&adata->fp);
613 adata->fp = mutt_file_fopen(mailbox_path(m), "r");
614 if (!adata->fp)
615 rc = -1;
616 else if (m->type == MUTT_MBOX)
617 rc = mbox_parse_mailbox(m);
618 else
619 rc = mmdf_parse_mailbox(m);
620 break;
621
622 default:
623 rc = -1;
624 break;
625 }
626
627 if (rc == -1)
628 {
629 /* free the old headers */
630 for (int i = 0; i < old_msg_count; i++)
631 email_free(&(e_old[i]));
632 FREE(&e_old);
633
634 m->verbose = true;
635 return -1;
636 }
637
638 mutt_file_touch_atime(fileno(adata->fp));
639
640 /* now try to recover the old flags */
641
642 if (!m->readonly)
643 {
644 for (int i = 0; i < m->msg_count; i++)
645 {
646 bool found = false;
647
648 /* some messages have been deleted, and new messages have been
649 * appended at the end; the heuristic is that old messages have then
650 * "advanced" towards the beginning of the folder, so we begin the
651 * search at index "i" */
652 int j;
653 for (j = i; j < old_msg_count; j++)
654 {
655 if (!e_old[j])
656 continue;
657 if (cmp_headers(m->emails[i], e_old[j]))
658 {
659 found = true;
660 break;
661 }
662 }
663 if (!found)
664 {
665 for (j = 0; (j < i) && (j < old_msg_count); j++)
666 {
667 if (!e_old[j])
668 continue;
669 if (cmp_headers(m->emails[i], e_old[j]))
670 {
671 found = true;
672 break;
673 }
674 }
675 }
676
677 if (found)
678 {
679 m->changed = true;
680 if (e_old[j]->changed)
681 {
682 /* Only update the flags if the old header was changed;
683 * otherwise, the header may have been modified externally,
684 * and we don't want to lose _those_ changes */
685 mutt_set_flag(m, m->emails[i], MUTT_FLAG, e_old[j]->flagged, true);
686 mutt_set_flag(m, m->emails[i], MUTT_REPLIED, e_old[j]->replied, true);
687 mutt_set_flag(m, m->emails[i], MUTT_OLD, e_old[j]->old, true);
688 mutt_set_flag(m, m->emails[i], MUTT_READ, e_old[j]->read, true);
689 }
690 mutt_set_flag(m, m->emails[i], MUTT_DELETE, e_old[j]->deleted, true);
691 mutt_set_flag(m, m->emails[i], MUTT_PURGE, e_old[j]->purge, true);
692 mutt_set_flag(m, m->emails[i], MUTT_TAG, e_old[j]->tagged, true);
693
694 /* we don't need this header any more */
695 email_free(&(e_old[j]));
696 }
697 }
698
699 /* free the remaining old emails */
700 for (int j = 0; j < old_msg_count; j++)
701 {
702 if (e_old[j])
703 {
704 email_free(&(e_old[j]));
705 msg_mod = true;
706 }
707 }
708 FREE(&e_old);
709 }
710
712 m->verbose = true;
713
714 return (m->changed || msg_mod) ? MX_STATUS_REOPENED : MX_STATUS_NEW_MAIL;
715}
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:267
bool email_cmp_strict(const struct Email *e1, const struct Email *e2)
Strictly compare message emails.
Definition: email.c:100
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:636
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
void mutt_file_touch_atime(int fd)
Set the access time to current time.
Definition: file.c:1094
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:53
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:457
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:226
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:177
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition: mailbox.h:178
static enum MxOpenReturns mbox_parse_mailbox(struct Mailbox *m)
Read a mailbox from disk.
Definition: mbox.c:349
static enum MxOpenReturns mmdf_parse_mailbox(struct Mailbox *m)
Read a mailbox in MMDF format.
Definition: mbox.c:181
#define FREE(x)
Definition: memory.h:45
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:72
@ MUTT_OLD
Old messages.
Definition: mutt.h:70
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:76
@ MUTT_TAG
Tagged messages.
Definition: mutt.h:79
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:78
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:74
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:71
void mutt_make_label_hash(struct Mailbox *m)
Create a Hash Table to store the labels.
Definition: mutt_header.c:417
@ 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:38
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:44
bool changed
Email has been edited.
Definition: email.h:75
int vcount
The number of virtual messages.
Definition: mailbox.h:99
bool changed
Mailbox has been modified.
Definition: mailbox.h:109
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:123
struct HashTable * id_hash
Hash Table: "message-id" -> Email.
Definition: mailbox.h:122
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:93
struct HashTable * label_hash
Hash Table: "x-labels" -> Email.
Definition: mailbox.h:124
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:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
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:304
+ 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 723 of file mbox.c.

724{
725 for (int i = 0; i < m->msg_count; i++)
726 {
727 struct Email *e = m->emails[i];
728 if (!e)
729 break;
730 if (!e->deleted && !e->read && !e->old)
731 return true;
732 }
733 return false;
734}
bool read
Email is read.
Definition: email.h:48
bool old
Email is seen, but unread.
Definition: email.h:47
bool deleted
Email is deleted.
Definition: email.h:76
+ 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 744 of file mbox.c.

745{
746 struct stat st2 = { 0 };
747 if (!st)
748 {
749 if (stat(mailbox_path(m), &st2) < 0)
750 return;
751 st = &st2;
752 }
753
754 struct utimbuf utimebuf = { 0 };
755 utimebuf.actime = st->st_atime;
756 utimebuf.modtime = st->st_mtime;
757
758 /* When $mbox_check_recent is set, existing new mail is ignored, so do not
759 * reset the atime to mtime-1 to signal new mail. */
760 const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
761 if (!c_mail_check_recent && (utimebuf.actime >= utimebuf.modtime) && mbox_has_new(m))
762 {
763 utimebuf.actime = utimebuf.modtime - 1;
764 }
765
766 utime(mailbox_path(m), &utimebuf);
767}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
static bool mbox_has_new(struct Mailbox *m)
Does the mailbox have new mail.
Definition: mbox.c:723
+ 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 799 of file mbox.c.

800{
801 FILE *fp = fopen(mailbox_path(m), "r+");
802 if (fp)
803 m->readonly = false;
804 return fp;
805}
+ 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 814 of file mbox.c.

815{
816 FILE *fp = fopen(mailbox_path(m), "r");
817 if (fp)
818 m->readonly = true;
819 return fp;
820}
+ Here is the call graph for this function:
+ Here is the caller graph for this function: