NeoMutt  2023-03-22-27-g3cb248
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 "globals.h"
#include "mdata.h"
#include "mdemail.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...
 
static 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...
 
static void mh_update_maildir (struct MdEmailArray *mda, struct MhSequences *mhs)
 Update our record of flags. More...
 
static int mh_commit_msg (struct Mailbox *m, struct Message *msg, struct Email *e, bool updseq)
 Commit a message to an MH folder. More...
 
static int mh_rewrite_message (struct Mailbox *m, int msgno)
 Sync a message in an MH folder. More...
 
static int mh_sync_message (struct Mailbox *m, int msgno)
 Sync an email to an MH folder. More...
 
static void mh_update_mtime (struct Mailbox *m)
 Update our record of the Maildir modification time. More...
 
static int mh_parse_dir (struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
 Read a Maildir mailbox. More...
 
static int mh_cmp_path (const void *a, const void *b)
 Compare two Maildirs by path - Implements sort_t -. More...
 
static struct Emailmh_parse_message (const char *fname, struct Email *e)
 Actually parse an MH message. More...
 
static 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...
 
static int mh_msg_save_hcache (struct Mailbox *m, struct Email *e)
 Save message to the header cache - Implements MxOps::msg_save_hcache() -. More...
 
static 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...
 
static 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...
 
static enum MxStatus mh_mbox_check (struct Mailbox *m)
 Check for new mail - Implements MxOps::mbox_check() -. More...
 
static enum MxStatus mh_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -. More...
 
static 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...
 
static int mh_msg_close (struct Mailbox *m, struct Message *msg)
 Close an email - Implements MxOps::msg_close() -. More...
 
static int mh_path_canon (char *buf, size_t buflen)
 Canonicalise a Mailbox path - Implements MxOps::path_canon() -. More...
 
static int mh_path_parent (char *buf, size_t buflen)
 Find the parent of a Mailbox path - Implements MxOps::path_parent() -. More...
 
static 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}
char * ShortHostname
Short version of the hostname.
Definition: globals.c:39
#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:209
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:41
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:1638
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:64
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()

static bool mh_valid_message ( const char *  s)
static

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 *dir = mutt_file_opendir(path, MUTT_OPENDIR_NONE);
172 if (!dir)
173 return -1;
174 while ((de = readdir(dir)))
175 {
176 if (mh_valid_message(de->d_name))
177 {
178 rc = 0;
179 break;
180 }
181 }
182 closedir(dir);
183
184 return rc;
185}
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:614
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:73
static 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()

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

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()

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

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
308 if (!dir)
309 {
311 return -1;
312 }
313
314 /* figure out what the next message number is */
315 while ((de = readdir(dir)))
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(dir);
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:203
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:343
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:165
#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()

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

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:875
#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
static 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:1200
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1154
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1062
#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:110
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()

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

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}
static 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:98
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()

static void mh_update_mtime ( struct Mailbox m)
static

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:1598
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()

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

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
513 if (!dir)
514 {
515 rc = -1;
516 goto cleanup;
517 }
518
519 while (((de = readdir(dir))) && !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(dir);
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:365
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: globals.c:58
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
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:86
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()

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

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:149
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1556
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1162
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:109
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()

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

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.

616{
617 char fn[PATH_MAX] = { 0 };
618
619#ifdef USE_HCACHE
620 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
621 struct HeaderCache *hc = mutt_hcache_open(c_header_cache, mailbox_path(m), NULL);
622#endif
623
624 struct MdEmail *md = NULL;
625 struct MdEmail **mdp = NULL;
626 ARRAY_FOREACH(mdp, mda)
627 {
628 md = *mdp;
629 if (!md || !md->email || md->header_parsed)
630 continue;
631
632 if (m->verbose && progress)
633 progress_update(progress, ARRAY_FOREACH_IDX, -1);
634
635 snprintf(fn, sizeof(fn), "%s/%s", mailbox_path(m), md->email->path);
636
637#ifdef USE_HCACHE
638 struct stat st_lastchanged = { 0 };
639 int rc = 0;
640 const bool c_maildir_header_cache_verify = cs_subset_bool(NeoMutt->sub, "maildir_header_cache_verify");
641 if (c_maildir_header_cache_verify)
642 {
643 rc = stat(fn, &st_lastchanged);
644 }
645
646 const char *key = md->email->path;
647 size_t keylen = strlen(key);
648 struct HCacheEntry hce = mutt_hcache_fetch(hc, key, keylen, 0);
649
650 if (hce.email && (rc == 0) && (st_lastchanged.st_mtime <= hce.uidvalidity))
651 {
654 hce.email->old = md->email->old;
655 hce.email->path = mutt_str_dup(md->email->path);
656 email_free(&md->email);
657 md->email = hce.email;
658 }
659 else
660#endif
661 {
662 if (mh_parse_message(fn, md->email))
663 {
664 md->header_parsed = true;
665#ifdef USE_HCACHE
666 key = md->email->path;
667 keylen = strlen(key);
668 mutt_hcache_store(hc, key, keylen, md->email, 0);
669#endif
670 }
671 else
672 {
673 email_free(&md->email);
674 }
675 }
676 }
677#ifdef USE_HCACHE
679#endif
680
681 const short c_sort = cs_subset_sort(NeoMutt->sub, "sort");
682 if (m && mda && (ARRAY_SIZE(mda) > 0) && (c_sort == SORT_ORDER))
683 {
684 mutt_debug(LL_DEBUG3, "maildir: sorting %s into natural order\n", mailbox_path(m));
686 }
687}
#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
static 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:610
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:483
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:373
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:507
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
static 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:44
bool old
Email is seen, but unread.
Definition: email.h:47
Wrapper for Email retrieved from the header cache.
Definition: lib.h:99
uint32_t uidvalidity
IMAP-specific UIDVALIDITY.
Definition: lib.h:100
struct Email * email
Retrieved email.
Definition: lib.h:102
Header cache structure.
Definition: lib.h:88
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 695 of file mh.c.

696{
697 if (!m)
698 return false;
699
700 struct MhSequences mhs = { 0 };
701 struct Progress *progress = NULL;
702
703 if (m->verbose)
704 {
705 char msg[PATH_MAX] = { 0 };
706 snprintf(msg, sizeof(msg), _("Scanning %s..."), mailbox_path(m));
707 progress = progress_new(msg, MUTT_PROGRESS_READ, 0);
708 }
709
711 if (!mdata)
712 {
714 m->mdata = mdata;
716 }
717
719
720 struct MdEmailArray mda = ARRAY_HEAD_INITIALIZER;
721 int rc = mh_parse_dir(m, &mda, progress);
722 progress_free(&progress);
723 if (rc < 0)
724 return false;
725
726 if (m->verbose)
727 {
728 char msg[PATH_MAX] = { 0 };
729 snprintf(msg, sizeof(msg), _("Reading %s..."), mailbox_path(m));
730 progress = progress_new(msg, MUTT_PROGRESS_READ, ARRAY_SIZE(&mda));
731 }
732 mh_delayed_parsing(m, &mda, progress);
733 progress_free(&progress);
734
735 if (mh_seq_read(&mhs, mailbox_path(m)) < 0)
736 {
737 maildirarray_clear(&mda);
738 return false;
739 }
740 mh_update_maildir(&mda, &mhs);
741 mh_seq_free(&mhs);
742
744
745 if (!mdata->mh_umask)
746 mdata->mh_umask = mh_umask(m);
747
748 return true;
749}
#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
static void mh_update_mtime(struct Mailbox *m)
Update our record of the Maildir modification time.
Definition: mh.c:477
static void mh_delayed_parsing(struct Mailbox *m, struct MdEmailArray *mda, struct Progress *progress)
This function does the second parsing pass.
Definition: mh.c:614
static void mh_update_maildir(struct MdEmailArray *mda, struct MhSequences *mhs)
Update our record of flags.
Definition: mh.c:260
static 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:377
void(* mdata_free)(void **ptr)
Free the private data attached to the Mailbox.
Definition: mailbox.h:141
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 759 of file mh.c.

760{
761 if (!m || !m->emails || (msgno >= m->msg_count))
762 return -1;
763
764 struct Email *e = m->emails[msgno];
765 if (!e)
766 return -1;
767
768 if (e->deleted)
769 {
770 char path[PATH_MAX] = { 0 };
771 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
772 const bool c_mh_purge = cs_subset_bool(NeoMutt->sub, "mh_purge");
773 if (c_mh_purge)
774 {
775#ifdef USE_HCACHE
776 if (hc)
777 {
778 const char *key = e->path;
779 size_t keylen = strlen(key);
780 mutt_hcache_delete_record(hc, key, keylen);
781 }
782#endif
783 unlink(path);
784 }
785 else
786 {
787 /* MH just moves files out of the way when you delete them */
788 if (*e->path != ',')
789 {
790 char tmp[PATH_MAX] = { 0 };
791 snprintf(tmp, sizeof(tmp), "%s/,%s", mailbox_path(m), e->path);
792 unlink(tmp);
793 if (rename(path, tmp) != 0)
794 {
795 return -1;
796 }
797 }
798 }
799 }
800 else if (e->changed || e->attach_del)
801 {
802 if (mh_sync_message(m, msgno) == -1)
803 return -1;
804 }
805
806#ifdef USE_HCACHE
807 if (hc && e->changed)
808 {
809 const char *key = e->path;
810 size_t keylen = strlen(key);
811 mutt_hcache_store(hc, key, keylen, e, 0);
812 }
813#endif
814
815 return 0;
816}
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:689
static 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: