NeoMutt  2022-04-29-247-gc6aae8
Teaching an old dog new tricks
DOXYGEN
mh.c File Reference

MH local mailbox type. More...

#include "config.h"
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "private.h"
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "lib.h"
#include "progress/lib.h"
#include "copy.h"
#include "edata.h"
#include "mdata.h"
#include "mdemail.h"
#include "mutt_globals.h"
#include "mx.h"
#include "sequence.h"
#include "monitor.h"
#include "hcache/lib.h"
+ Include dependency graph for mh.c:

Go to the source code of this file.

Functions

bool mh_mkstemp (struct Mailbox *m, FILE **fp, char **tgt)
 Create a temporary file. More...
 
static int mh_already_notified (struct Mailbox *m, int msgno)
 Has the message changed. More...
 
bool mh_valid_message (const char *s)
 Is this a valid MH message filename. More...
 
int mh_check_empty (const char *path)
 Is mailbox empty. More...
 
static enum MxStatus mh_mbox_check_stats (struct Mailbox *m, uint8_t flags)
 Check the Mailbox statistics - Implements MxOps::mbox_check_stats() -. More...
 
void mh_update_maildir (struct MdEmailArray *mda, struct MhSequences *mhs)
 Update our record of flags. More...
 
int mh_commit_msg (struct Mailbox *m, struct Message *msg, struct Email *e, bool updseq)
 Commit a message to an MH folder. More...
 
int mh_rewrite_message (struct Mailbox *m, int msgno)
 Sync a message in an MH folder. More...
 
int mh_sync_message (struct Mailbox *m, int msgno)
 Sync an email to an MH folder. More...
 
void mh_update_mtime (struct Mailbox *m)
 Update our record of the Maildir modification time. More...
 
int mh_parse_dir (struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
 Read a Maildir mailbox. More...
 
int mh_cmp_path (const void *a, const void *b)
 Compare two Maildirs by path - Implements sort_t -. More...
 
struct Emailmh_parse_message (const char *fname, struct Email *e)
 Actually parse an MH message. More...
 
void mh_delayed_parsing (struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
 This function does the second parsing pass. More...
 
static bool mh_read_dir (struct Mailbox *m)
 Read an MH mailbox. More...
 
int mh_sync_mailbox_message (struct Mailbox *m, int msgno, struct HeaderCache *hc)
 Save changes to the mailbox. More...
 
int mh_msg_save_hcache (struct Mailbox *m, struct Email *e)
 Save message to the header cache - Implements MxOps::msg_save_hcache() -. More...
 
bool mh_ac_owns_path (struct Account *a, const char *path)
 Check whether an Account own a Mailbox path - Implements MxOps::ac_owns_path() -. More...
 
bool mh_ac_add (struct Account *a, struct Mailbox *m)
 Add a Mailbox to an Account - Implements MxOps::ac_add() -. More...
 
static enum MxOpenReturns mh_mbox_open (struct Mailbox *m)
 Open a Mailbox - Implements MxOps::mbox_open() -. More...
 
static bool mh_mbox_open_append (struct Mailbox *m, OpenMailboxFlags flags)
 Open a Mailbox for appending - Implements MxOps::mbox_open_append() -. More...
 
enum MxStatus mh_mbox_check (struct Mailbox *m)
 Check for new mail - Implements MxOps::mbox_check() -. More...
 
enum MxStatus mh_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -. More...
 
enum MxStatus mh_mbox_close (struct Mailbox *m)
 Close a Mailbox - Implements MxOps::mbox_close() -. More...
 
static bool mh_msg_open (struct Mailbox *m, struct Message *msg, int msgno)
 Open an email message in a Mailbox - Implements MxOps::msg_open() -. More...
 
static bool mh_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() -. More...
 
static int mh_msg_commit (struct Mailbox *m, struct Message *msg)
 Save changes to an email - Implements MxOps::msg_commit() -. More...
 
int mh_msg_close (struct Mailbox *m, struct Message *msg)
 Close an email - Implements MxOps::msg_close() -. More...
 
int mh_path_canon (char *buf, size_t buflen)
 Canonicalise a Mailbox path - Implements MxOps::path_canon() -. More...
 
int mh_path_parent (char *buf, size_t buflen)
 Find the parent of a Mailbox path - Implements MxOps::path_parent() -. More...
 
int mh_path_pretty (char *buf, size_t buflen, const char *folder)
 Abbreviate a Mailbox path - Implements MxOps::path_pretty() -. More...
 
static enum MailboxType mh_path_probe (const char *path, const struct stat *st)
 Is this an mh Mailbox? - Implements MxOps::path_probe() -. More...
 

Variables

struct MxOps MxMhOps
 MH Mailbox - Implements MxOps -. More...
 

Detailed Description

MH local mailbox type.

Authors
  • Michael R. Elkins
  • Thomas Roessler
  • Michael R. Elkins
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file mh.c.

Function Documentation

◆ mh_mkstemp()

bool mh_mkstemp ( struct Mailbox m,
FILE **  fp,
char **  tgt 
)

Create a temporary file.

Parameters
[in]mMailbox to create the file in
[out]fpFile handle
[out]tgtFile name
Return values
trueSuccess
falseFailure

Definition at line 78 of file mh.c.

79{
80 int fd;
81 char path[PATH_MAX] = { 0 };
82
83 mode_t omask = umask(mh_umask(m));
84 while (true)
85 {
86 snprintf(path, sizeof(path), "%s/.neomutt-%s-%d-%" PRIu64, mailbox_path(m),
87 NONULL(ShortHostname), (int) getpid(), mutt_rand64());
88 fd = open(path, O_WRONLY | O_EXCL | O_CREAT, 0666);
89 if (fd == -1)
90 {
91 if (errno != EEXIST)
92 {
93 mutt_perror(path);
94 umask(omask);
95 return false;
96 }
97 }
98 else
99 {
100 *tgt = mutt_str_dup(path);
101 break;
102 }
103 }
104 umask(omask);
105
106 *fp = fdopen(fd, "w");
107 if (!*fp)
108 {
109 FREE(tgt);
110 close(fd);
111 unlink(path);
112 return false;
113 }
114
115 return true;
116}
#define mutt_perror(...)
Definition: logging.h:88
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
mode_t mh_umask(struct Mailbox *m)
Create a umask from the mailbox directory.
Definition: shared.c:52
#define FREE(x)
Definition: memory.h:43
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
#define PATH_MAX
Definition: mutt.h:40
char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:50
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: random.c:129
#define NONULL(x)
Definition: string2.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_already_notified()

static int mh_already_notified ( struct Mailbox m,
int  msgno 
)
static

Has the message changed.

Parameters
mMailbox
msgnoMessage number
Return values
1Modification time on the message file is older than the last visit to this mailbox
0Modification time on the message file is newer
-1Error

Definition at line 126 of file mh.c.

127{
128 char path[PATH_MAX] = { 0 };
129 struct stat st = { 0 };
130
131 if ((snprintf(path, sizeof(path), "%s/%d", mailbox_path(m), msgno) < sizeof(path)) &&
132 (stat(path, &st) == 0))
133 {
135 }
136 return -1;
137}
int mutt_file_stat_timespec_compare(struct stat *st, enum MuttStatType type, struct timespec *b)
Compare stat info with a time value.
Definition: file.c:1651
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:63
struct timespec last_visited
Time of last exit from this mailbox.
Definition: mailbox.h:105
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_valid_message()

bool mh_valid_message ( const char *  s)

Is this a valid MH message filename.

Parameters
sPathname to examine
Return values
truename is valid
falsename is invalid

Ignore the garbage files. A valid MH message consists of only digits. Deleted message get moved to a filename with a comma before it.

Definition at line 149 of file mh.c.

150{
151 for (; *s; s++)
152 {
153 if (!isdigit((unsigned char) *s))
154 return false;
155 }
156 return true;
157}
+ Here is the caller graph for this function:

◆ mh_check_empty()

int mh_check_empty ( const char *  path)

Is mailbox empty.

Parameters
pathMailbox to check
Return values
1Mailbox is empty
0Mailbox contains mail
-1Error

Definition at line 166 of file mh.c.

167{
168 struct dirent *de = NULL;
169 int rc = 1; /* assume empty until we find a message */
170
171 DIR *dp = opendir(path);
172 if (!dp)
173 return -1;
174 while ((de = readdir(dp)))
175 {
176 if (mh_valid_message(de->d_name))
177 {
178 rc = 0;
179 break;
180 }
181 }
182 closedir(dp);
183
184 return rc;
185}
bool mh_valid_message(const char *s)
Is this a valid MH message filename.
Definition: mh.c:149
+ Here is the call graph for this function:

◆ mh_update_maildir()

void mh_update_maildir ( struct MdEmailArray *  mda,
struct MhSequences mhs 
)

Update our record of flags.

Parameters
mdaMaildir array to update
mhsSequences

Definition at line 260 of file mh.c.

261{
262 struct MdEmail *md = NULL;
263 struct MdEmail **mdp = NULL;
264 ARRAY_FOREACH(mdp, mda)
265 {
266 md = *mdp;
267 char *p = strrchr(md->email->path, '/');
268 if (p)
269 p++;
270 else
271 p = md->email->path;
272
273 int i = 0;
274 if (!mutt_str_atoi_full(p, &i))
275 continue;
276 MhSeqFlags flags = mh_seq_check(mhs, i);
277
278 md->email->read = !(flags & MH_SEQ_UNSEEN);
279 md->email->flagged = (flags & MH_SEQ_FLAGGED);
280 md->email->replied = (flags & MH_SEQ_REPLIED);
281 }
282}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:211
MhSeqFlags mh_seq_check(struct MhSequences *mhs, int i)
Get the flags for a given sequence.
Definition: sequence.c:78
#define MH_SEQ_UNSEEN
Email hasn't been read.
Definition: sequence.h:33
#define MH_SEQ_REPLIED
Email has been replied to.
Definition: sequence.h:34
uint8_t MhSeqFlags
Flags, e.g. MH_SEQ_UNSEEN.
Definition: sequence.h:31
#define MH_SEQ_FLAGGED
Email is flagged.
Definition: sequence.h:35
bool read
Email is read.
Definition: email.h:48
bool flagged
Marked important?
Definition: email.h:45
bool replied
Email has been replied to.
Definition: email.h:49
char * path
Path of Email (for local Mailboxes)
Definition: email.h:68
A Maildir Email helper.
Definition: mdemail.h:34
struct Email * email
Definition: mdemail.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_commit_msg()

int mh_commit_msg ( struct Mailbox m,
struct Message msg,
struct Email e,
bool  updseq 
)

Commit a message to an MH folder.

Parameters
mMailbox
msgMessage to commit
eEmail
updseqIf true, update the sequence number
Return values
0Success
-1Failure

Definition at line 293 of file mh.c.

294{
295 struct dirent *de = NULL;
296 char *cp = NULL, *dep = NULL;
297 unsigned int n, hi = 0;
298 char path[PATH_MAX] = { 0 };
299 char tmp[16] = { 0 };
300
301 if (mutt_file_fsync_close(&msg->fp))
302 {
303 mutt_perror(_("Could not flush message to disk"));
304 return -1;
305 }
306
307 DIR *dirp = opendir(mailbox_path(m));
308 if (!dirp)
309 {
311 return -1;
312 }
313
314 /* figure out what the next message number is */
315 while ((de = readdir(dirp)))
316 {
317 dep = de->d_name;
318 if (*dep == ',')
319 dep++;
320 cp = dep;
321 while (*cp)
322 {
323 if (!isdigit((unsigned char) *cp))
324 break;
325 cp++;
326 }
327 if (*cp == '\0')
328 {
329 if (!mutt_str_atoui(dep, &n))
330 mutt_debug(LL_DEBUG2, "Invalid MH message number '%s'\n", dep);
331 if (n > hi)
332 hi = n;
333 }
334 }
335 closedir(dirp);
336
337 /* Now try to rename the file to the proper name.
338 * Note: We may have to try multiple times, until we find a free slot. */
339
340 while (true)
341 {
342 hi++;
343 snprintf(tmp, sizeof(tmp), "%u", hi);
344 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), tmp);
345 if (mutt_file_safe_rename(msg->path, path) == 0)
346 {
347 if (e)
348 mutt_str_replace(&e->path, tmp);
349 mutt_str_replace(&msg->committed_path, path);
350 FREE(&msg->path);
351 break;
352 }
353 else if (errno != EEXIST)
354 {
356 return -1;
357 }
358 }
359 if (updseq)
360 {
361 mh_seq_add_one(m, hi, !msg->flags.read, msg->flags.flagged, msg->flags.replied);
362 }
363 return 0;
364}
const char * mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: atoi.c:202
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:344
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:168
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
#define _(a)
Definition: message.h:28
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
void mh_seq_add_one(struct Mailbox *m, int n, bool unseen, bool flagged, bool replied)
Update the flags for one sequence.
Definition: sequence.c:107
FILE * fp
pointer to the message data
Definition: mxapi.h:44
char * path
path to temp file
Definition: mxapi.h:45
bool replied
Message has been replied to.
Definition: mxapi.h:52
char * committed_path
the final path generated by mx_msg_commit()
Definition: mxapi.h:46
bool flagged
Message is flagged.
Definition: mxapi.h:51
bool read
Message has been read.
Definition: mxapi.h:50
struct Message::@0 flags
Flags for the Message.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_rewrite_message()

int mh_rewrite_message ( struct Mailbox m,
int  msgno 
)

Sync a message in an MH folder.

Parameters
mMailbox
msgnoIndex number
Return values
0Success
-1Error

Definition at line 373 of file mh.c.

374{
375 if (!m || !m->emails || (msgno >= m->msg_count))
376 return -1;
377
378 struct Email *e = m->emails[msgno];
379 if (!e)
380 return -1;
381
382 bool restore = true;
383
384 long old_body_offset = e->body->offset;
385 long old_body_length = e->body->length;
386 long old_hdr_lines = e->lines;
387
388 struct Message *src = mx_msg_open(m, msgno);
389 struct Message *dest = mx_msg_open_new(m, e, MUTT_MSG_NO_FLAGS);
390 if (!src || !dest)
391 return -1;
392
393 int rc = mutt_copy_message(dest->fp, e, src, MUTT_CM_UPDATE, CH_UPDATE | CH_UPDATE_LEN, 0);
394 if (rc == 0)
395 {
396 char oldpath[PATH_MAX] = { 0 };
397 char partpath[PATH_MAX] = { 0 };
398 snprintf(oldpath, sizeof(oldpath), "%s/%s", mailbox_path(m), e->path);
399 mutt_str_copy(partpath, e->path, sizeof(partpath));
400
401 rc = mh_commit_msg(m, dest, e, false);
402
403 if (rc == 0)
404 {
405 unlink(oldpath);
406 restore = false;
407 }
408
409 /* Try to move the new message to the old place.
410 * (MH only.)
411 *
412 * This is important when we are just updating flags.
413 *
414 * Note that there is a race condition against programs which
415 * use the first free slot instead of the maximum message
416 * number. NeoMutt does _not_ behave like this.
417 *
418 * Anyway, if this fails, the message is in the folder, so
419 * all what happens is that a concurrently running neomutt will
420 * lose flag modifications. */
421 if (rc == 0)
422 {
423 char newpath[PATH_MAX] = { 0 };
424 snprintf(newpath, sizeof(newpath), "%s/%s", mailbox_path(m), e->path);
425 rc = mutt_file_safe_rename(newpath, oldpath);
426 if (rc == 0)
427 mutt_str_replace(&e->path, partpath);
428 }
429 }
430 mx_msg_close(m, &src);
431 mx_msg_close(m, &dest);
432
433 if ((rc == -1) && restore)
434 {
435 e->body->offset = old_body_offset;
436 e->body->length = old_body_length;
437 e->lines = old_hdr_lines;
438 }
439
441 return rc;
442}
int mutt_copy_message(FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:864
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:40
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:52
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
static struct Email * restore(const unsigned char *d)
Restore an Email from data retrieved from the cache.
Definition: hcache.c:143
int mh_commit_msg(struct Mailbox *m, struct Message *msg, struct Email *e, bool updseq)
Commit a message to an MH folder.
Definition: mh.c:293
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:652
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1193
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1147
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1057
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:42
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
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
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
int msgno
Number displayed to the user.
Definition: email.h:111
int msg_count
Total number of messages.
Definition: mailbox.h:88
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
A local copy of an email.
Definition: mxapi.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_sync_message()

int mh_sync_message ( struct Mailbox m,
int  msgno 
)

Sync an email to an MH folder.

Parameters
mMailbox
msgnoIndex number
Return values
0Success
-1Error

Definition at line 451 of file mh.c.

452{
453 if (!m || !m->emails)
454 return -1;
455
456 struct Email *e = m->emails[msgno];
457 if (!e)
458 return -1;
459
460 /* TODO: why the e->env check? */
461 if (e->attach_del || (e->env && e->env->changed))
462 {
463 if (mh_rewrite_message(m, msgno) != 0)
464 return -1;
465 /* TODO: why the env check? */
466 if (e->env)
467 e->env->changed = 0;
468 }
469
470 return 0;
471}
int mh_rewrite_message(struct Mailbox *m, int msgno)
Sync a message in an MH folder.
Definition: mh.c:373
struct Envelope * env
Envelope information.
Definition: email.h:66
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:99
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:92
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_update_mtime()

void mh_update_mtime ( struct Mailbox m)

Update our record of the Maildir modification time.

Parameters
mMailbox

Definition at line 477 of file mh.c.

478{
479 char buf[PATH_MAX] = { 0 };
480 struct stat st = { 0 };
482
483 snprintf(buf, sizeof(buf), "%s/.mh_sequences", mailbox_path(m));
484 if (stat(buf, &st) == 0)
486
487 mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
488
489 if (stat(buf, &st) == 0)
491}
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:1611
struct MaildirMboxData * maildir_mdata_get(struct Mailbox *m)
Get the private data for this Mailbox.
Definition: mdata.c:58
struct timespec mtime
Time Mailbox was last changed.
Definition: mailbox.h:104
void * mdata
Driver specific data.
Definition: mailbox.h:132
Maildir-specific Mailbox data -.
Definition: mdata.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_parse_dir()

int mh_parse_dir ( struct Mailbox m,
struct MdEmailArray *  mda,
struct Progress *  progress 
)

Read a Maildir mailbox.

Parameters
[in]mMailbox
[out]mdaArray for results
[in]progressProgress bar
Return values
0Success
-1Error
-2Aborted

Definition at line 502 of file mh.c.

503{
504 struct dirent *de = NULL;
505 int rc = 0;
506 struct MdEmail *entry = NULL;
507 struct Email *e = NULL;
508
509 struct Buffer *buf = mutt_buffer_pool_get();
511
512 DIR *dirp = opendir(mutt_buffer_string(buf));
513 if (!dirp)
514 {
515 rc = -1;
516 goto cleanup;
517 }
518
519 while (((de = readdir(dirp))) && !SigInt)
520 {
521 if (!mh_valid_message(de->d_name))
522 continue;
523
524 /* FOO - really ignore the return value? */
525 mutt_debug(LL_DEBUG2, "queueing %s\n", de->d_name);
526
527 e = email_new();
530
531 if (m->verbose && progress)
532 progress_update(progress, ARRAY_SIZE(mda) + 1, -1);
533
534 e->path = mutt_str_dup(de->d_name);
535
536 entry = maildir_entry_new();
537 entry->email = e;
538 ARRAY_ADD(mda, entry);
539 }
540
541 closedir(dirp);
542
543 if (SigInt)
544 {
545 SigInt = false;
546 return -2; /* action aborted */
547 }
548
549cleanup:
551
552 return rc;
553}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:155
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:86
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:327
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
void maildir_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:38
struct MaildirEmailData * maildir_edata_new(void)
Create a new MaildirEmailData object.
Definition: edata.c:53
struct MdEmail * maildir_entry_new(void)
Create a new Maildir entry.
Definition: mdemail.c:39
SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:69
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:73
String manipulation buffer.
Definition: buffer.h:34
void * edata
Driver-specific data.
Definition: email.h:72
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:87
bool verbose
Display status messages?
Definition: mailbox.h:114
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_parse_message()

struct Email * mh_parse_message ( const char *  fname,
struct Email e 
)

Actually parse an MH message.

Parameters
fnameMessage filename
eEmail to populate (OPTIONAL)
Return values
ptrPopulated Email

This may also be used to fill out a fake header structure generated by lazy maildir parsing.

Definition at line 574 of file mh.c.

575{
576 FILE *fp = fopen(fname, "r");
577 if (!fp)
578 {
579 return NULL;
580 }
581
582 const long size = mutt_file_get_size_fp(fp);
583 if (size == 0)
584 {
585 mutt_file_fclose(&fp);
586 return NULL;
587 }
588
589 if (!e)
590 {
591 e = email_new();
594 }
595 e->env = mutt_rfc822_read_header(fp, e, false, false);
596
597 if (e->received != 0)
598 e->received = e->date_sent;
599
600 /* always update the length since we have fresh information available. */
601 e->body->length = size - e->body->offset;
602 e->index = -1;
603
604 mutt_file_fclose(&fp);
605 return e;
606}
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1569
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1157
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:58
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:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_delayed_parsing()

void mh_delayed_parsing ( struct Mailbox m,
struct MdEmailArray *  mda,
struct Progress *  progress 
)

This function does the second parsing pass.

Parameters
[in]mMailbox
[out]mdaMaildir array to parse
[in]progressProgress bar

Definition at line 614 of file mh.c.

615{
616 char fn[PATH_MAX] = { 0 };
617
618#ifdef USE_HCACHE
619 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
620 struct HeaderCache *hc = mutt_hcache_open(c_header_cache, mailbox_path(m), NULL);
621#endif
622
623 struct MdEmail *md = NULL;
624 struct MdEmail **mdp = NULL;
625 ARRAY_FOREACH(mdp, mda)
626 {
627 md = *mdp;
628 if (!md || !md->email || md->header_parsed)
629 continue;
630
631 if (m->verbose && progress)
632 progress_update(progress, ARRAY_FOREACH_IDX, -1);
633
634 snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
635
636#ifdef USE_HCACHE
637 struct stat st_lastchanged = { 0 };
638 int rc = 0;
639 const bool c_maildir_header_cache_verify = cs_subset_bool(NeoMutt->sub, "maildir_header_cache_verify");
640 if (c_maildir_header_cache_verify)
641 {
642 rc = stat(fn, &st_lastchanged);
643 }
644
645 const char *key = md->email->path;
646 size_t keylen = strlen(key);
647 struct HCacheEntry hce = mutt_hcache_fetch(hc, key, keylen, 0);
648
649 if (hce.email && (rc == 0) && (st_lastchanged.st_mtime <= hce.uidvalidity))
650 {
653 hce.email->old = md->email->old;
654 hce.email->path = mutt_str_dup(md->email->path);
655 email_free(&md->email);
656 md->email = hce.email;
657 }
658 else
659#endif
660 {
661 if (mh_parse_message(fn, md->email))
662 {
663 md->header_parsed = true;
664#ifdef USE_HCACHE
665 key = md->email->path;
666 keylen = strlen(key);
667 mutt_hcache_store(hc, key, keylen, md->email, 0);
668#endif
669 }
670 else
671 email_free(&md->email);
672 }
673 }
674#ifdef USE_HCACHE
676#endif
677
678 const short c_sort = cs_subset_sort(NeoMutt->sub, "sort");
679 if (m && mda && (ARRAY_SIZE(mda) > 0) && (c_sort == SORT_ORDER))
680 {
681 mutt_debug(LL_DEBUG3, "maildir: sorting %s into natural order\n", mailbox_path(m));
683 }
684}
#define ARRAY_SORT(head, fn)
Sort an array.
Definition: array.h:277
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
int mh_cmp_path(const void *a, const void *b)
Compare two Maildirs by path - Implements sort_t -.
Definition: mh.c:558
int mutt_hcache_store(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition: hcache.c:552
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:432
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:332
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:456
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
struct Email * mh_parse_message(const char *fname, struct Email *e)
Actually parse an MH message.
Definition: mh.c:574
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:48
bool old
Email is seen, but unread.
Definition: email.h:47
Wrapper for Email retrieved from the header cache.
Definition: lib.h:98
uint32_t uidvalidity
IMAP-specific UIDVALIDITY.
Definition: lib.h:99
struct Email * email
Retrieved email.
Definition: lib.h:101
Header cache structure.
Definition: lib.h:87
bool header_parsed
Definition: mdemail.h:37
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_read_dir()

static bool mh_read_dir ( struct Mailbox m)
static

Read an MH mailbox.

Parameters
mMailbox
Return values
trueSuccess
falseError

Definition at line 692 of file mh.c.

693{
694 if (!m)
695 return false;
696
697 struct MhSequences mhs = { 0 };
698 struct Progress *progress = NULL;
699
700 if (m->verbose)
701 {
702 char msg[PATH_MAX] = { 0 };
703 snprintf(msg, sizeof(msg), _("Scanning %s..."), mailbox_path(m));
704 progress = progress_new(msg, MUTT_PROGRESS_READ, 0);
705 }
706
708 if (!mdata)
709 {
711 m->mdata = mdata;
713 }
714
716
717 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
718 int rc = mh_parse_dir(m, &mda, progress);
719 progress_free(&progress);
720 if (rc < 0)
721 return false;
722
723 if (m->verbose)
724 {
725 char msg[PATH_MAX] = { 0 };
726 snprintf(msg, sizeof(msg), _("Reading %s..."), mailbox_path(m));
727 progress = progress_new(msg, MUTT_PROGRESS_READ, ARRAY_SIZE(&mda));
728 }
729 mh_delayed_parsing(m, &mda, progress);
730 progress_free(&progress);
731
732 if (mh_seq_read(&mhs, mailbox_path(m)) < 0)
733 {
734 maildirarray_clear(&mda);
735 return false;
736 }
737 mh_update_maildir(&mda, &mhs);
738 mh_seq_free(&mhs);
739
741
742 if (!mdata->mh_umask)
743 mdata->mh_umask = mh_umask(m);
744
745 return true;
746}
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:57
void maildir_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free()
Definition: mdata.c:37
struct MaildirMboxData * maildir_mdata_new(void)
Create a new MaildirMboxData object.
Definition: mdata.c:47
int maildir_move_to_mailbox(struct Mailbox *m, struct MdEmailArray *mda)
Copy the Maildir list to the Mailbox.
Definition: shared.c:75
void maildirarray_clear(struct MdEmailArray *mda)
Free a Maildir array.
Definition: mdemail.c:64
void mh_update_mtime(struct Mailbox *m)
Update our record of the Maildir modification time.
Definition: mh.c:477
void mh_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
This function does the second parsing pass.
Definition: mh.c:614
void mh_update_maildir(struct MdEmailArray *mda, struct MhSequences *mhs)
Update our record of flags.
Definition: mh.c:260
int mh_parse_dir(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
Read a Maildir mailbox.
Definition: mh.c:502
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: lib.h:49
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:86
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:118
void mh_seq_free(struct MhSequences *mhs)
Free some sequences.
Definition: sequence.c:67
int mh_seq_read(struct MhSequences *mhs, const char *path)
Read a set of MH sequences.
Definition: sequence.c:375
void(* mdata_free)(void **ptr)
Free the private data attached to the Mailbox.
Definition: mailbox.h:142
mode_t mh_umask
umask to use when creating files
Definition: mdata.h:37
Set of MH sequence numbers.
Definition: sequence.h:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_sync_mailbox_message()

int mh_sync_mailbox_message ( struct Mailbox m,
int  msgno,
struct HeaderCache hc 
)

Save changes to the mailbox.

Parameters
mMailbox
msgnoIndex number
hcHeader cache handle
Return values
0Success
-1Error

Definition at line 756 of file mh.c.

757{
758 if (!m || !m->emails || (msgno >= m->msg_count))
759 return -1;
760
761 struct Email *e = m->emails[msgno];
762 if (!e)
763 return -1;
764
765 if (e->deleted)
766 {
767 char path[PATH_MAX] = { 0 };
768 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
769 const bool c_mh_purge = cs_subset_bool(NeoMutt->sub, "mh_purge");
770 if (c_mh_purge)
771 {
772#ifdef USE_HCACHE
773 if (hc)
774 {
775 const char *key = e->path;
776 size_t keylen = strlen(key);
777 mutt_hcache_delete_record(hc, key, keylen);
778 }
779#endif
780 unlink(path);
781 }
782 else
783 {
784 /* MH just moves files out of the way when you delete them */
785 if (*e->path != ',')
786 {
787 char tmp[PATH_MAX] = { 0 };
788 snprintf(tmp, sizeof(tmp), "%s/,%s", mailbox_path(m), e->path);
789 unlink(tmp);
790 if (rename(path, tmp) != 0)
791 {
792 return -1;
793 }
794 }
795 }
796 }
797 else if (e->changed || e->attach_del)
798 {
799 if (mh_sync_message(m, msgno) == -1)
800 return -1;
801 }
802
803#ifdef USE_HCACHE
804 if (hc && e->changed)
805 {
806 const char *key = e->path;
807 size_t keylen = strlen(key);
808 mutt_hcache_store(hc, key, keylen, e, 0);
809 }
810#endif
811
812 return 0;
813}
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:631
int mh_sync_message(struct Mailbox *m, int msgno)
Sync an email to an MH folder.
Definition: mh.c:451
bool changed
Email has been edited.
Definition: email.h:75
bool deleted
Email is deleted.
Definition: email.h:76
+ Here is the call graph for this function:
+ Here is the caller graph for this function: