NeoMutt  2025-12-11-980-ge38c27
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
message.c
Go to the documentation of this file.
1
22
28
29#include "config.h"
30#include <dirent.h>
31#include <errno.h>
32#include <fcntl.h>
33#include <inttypes.h>
34#include <limits.h>
35#include <stdio.h>
36#include <string.h>
37#include <sys/stat.h>
38#include <sys/types.h>
39#include <unistd.h>
40#include <utime.h>
41#include "mutt/lib.h"
42#include "config/lib.h"
43#include "email/lib.h"
44#include "core/lib.h"
45#include "message.h"
46#include "edata.h"
47#include "globals.h"
48#include "hcache.h"
49#include "mx.h"
50#include "shared.h"
51
52struct HeaderCache;
53
54int nm_update_filename(struct Mailbox *m, const char *old_file,
55 const char *new_file, struct Email *e);
56
60static int maildir_sort_flags(const void *a, const void *b, void *sdata)
61{
62 return mutt_numeric_cmp(*((const char *) a), *((const char *) b));
63}
64
71void maildir_gen_flags(char *dest, size_t destlen, struct Email *e)
72{
73 *dest = '\0';
74
75 const char *flags = NULL;
76
78 if (edata)
79 flags = edata->custom_flags;
80
81 /* The maildir specification requires that all files in the cur
82 * subdirectory have the :unique string appended, regardless of whether
83 * or not there are any flags. If .old is set, we know that this message
84 * will end up in the cur directory, so we include it in the following
85 * test even though there is no associated flag. */
86
87 if (e->flagged || e->replied || e->read || e->deleted || e->old || flags)
88 {
89 char tmp[1024] = { 0 };
90 snprintf(tmp, sizeof(tmp), "%s%s%s%s%s", e->flagged ? "F" : "", e->replied ? "R" : "",
91 e->read ? "S" : "", e->deleted ? "T" : "", NONULL(flags));
92 if (flags)
93 mutt_qsort_r(tmp, strlen(tmp), 1, maildir_sort_flags, NULL);
94
95 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
96 snprintf(dest, destlen, "%c2,%s", c_maildir_field_delimiter, tmp);
97 }
98}
99
112static FILE *maildir_open_find_message_dir(const char *folder, const char *unique,
113 const char *subfolder, char **newname)
114{
115 struct Buffer *dirname = buf_pool_get();
116 struct Buffer *tunique = buf_pool_get();
117 struct Buffer *fname = buf_pool_get();
118
119 struct dirent *de = NULL;
120
121 FILE *fp = NULL;
122 int oe = ENOENT;
123
124 buf_printf(dirname, "%s/%s", folder, subfolder);
125
127 if (!dir)
128 {
129 errno = ENOENT;
130 goto cleanup;
131 }
132
133 while ((de = readdir(dir)))
134 {
135 maildir_canon_filename(tunique, de->d_name);
136
137 if (mutt_str_equal(buf_string(tunique), unique))
138 {
139 buf_printf(fname, "%s/%s/%s", folder, subfolder, de->d_name);
140 fp = mutt_file_fopen(buf_string(fname), "r");
141 oe = errno;
142 break;
143 }
144 }
145
146 closedir(dir);
147
148 if (newname && fp)
149 *newname = buf_strdup(fname);
150
151 errno = oe;
152
153cleanup:
154 buf_pool_release(&dirname);
155 buf_pool_release(&tunique);
156 buf_pool_release(&fname);
157
158 return fp;
159}
160
168FILE *maildir_open_find_message(const char *folder, const char *msg, char **newname)
169{
170 static unsigned int new_hits = 0;
171 static unsigned int cur_hits = 0; /* simple dynamic optimization */
172
173 struct Buffer *unique = buf_pool_get();
174 maildir_canon_filename(unique, msg);
175
176 /* Prevent counter saturation by halving both when either gets large */
177 if ((new_hits > (UINT_MAX / 2)) || (cur_hits > (UINT_MAX / 2)))
178 {
179 new_hits /= 2;
180 cur_hits /= 2;
181 }
182
183 FILE *fp = maildir_open_find_message_dir(folder, buf_string(unique),
184 (new_hits > cur_hits) ? "new" : "cur", newname);
185 if (fp || (errno != ENOENT))
186 {
187 if (new_hits > cur_hits)
188 new_hits++;
189 else
190 cur_hits++;
191
192 goto cleanup;
193 }
194 fp = maildir_open_find_message_dir(folder, buf_string(unique),
195 (new_hits > cur_hits) ? "cur" : "new", newname);
196 if (fp || (errno != ENOENT))
197 {
198 if (new_hits > cur_hits)
199 cur_hits++;
200 else
201 new_hits++;
202
203 goto cleanup;
204 }
205
206 fp = NULL;
207
208cleanup:
209 buf_pool_release(&unique);
210
211 return fp;
212}
213
221static int maildir_sync_message(struct Mailbox *m, struct Email *e)
222{
223 if (!m || !e)
224 return -1;
225
226 struct Buffer *newpath = NULL;
227 struct Buffer *partpath = NULL;
228 struct Buffer *fullpath = NULL;
229 struct Buffer *oldpath = NULL;
230 char suffix[PATH_MAX] = { 0 };
231 int rc = 0;
232
233 if (e->attach_del || e->env->changed)
234 {
235 /* when doing attachment deletion/rethreading, fall back to the maildir case. */
236 if (maildir_rewrite_message(m, e) != 0)
237 return -1;
238 e->env->changed = false;
239 }
240 else
241 {
242 /* we just have to rename the file. */
243
244 char *p = strrchr(e->path, '/');
245 if (!p)
246 {
247 mutt_debug(LL_DEBUG1, "%s: unable to find subdir!\n", e->path);
248 return -1;
249 }
250 p++;
251 newpath = buf_pool_get();
252 partpath = buf_pool_get();
253 fullpath = buf_pool_get();
254 oldpath = buf_pool_get();
255
256 buf_strcpy(newpath, p);
257
258 /* kill the previous flags */
259 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
260 p = strchr(newpath->data, c_maildir_field_delimiter);
261 if (p)
262 {
263 *p = '\0';
264 newpath->dptr = p; /* fix buffer up, just to be safe */
265 }
266
267 maildir_gen_flags(suffix, sizeof(suffix), e);
268
269 buf_printf(partpath, "%s/%s%s", (e->read || e->old) ? "cur" : "new",
270 buf_string(newpath), suffix);
271 buf_printf(fullpath, "%s/%s", mailbox_path(m), buf_string(partpath));
272 buf_printf(oldpath, "%s/%s", mailbox_path(m), e->path);
273
274 if (mutt_str_equal(buf_string(fullpath), buf_string(oldpath)))
275 {
276 /* message hasn't really changed */
277 goto cleanup;
278 }
279
280 /* record that the message is possibly marked as trashed on disk */
281 e->trash = e->deleted;
282
283 struct stat st = { 0 };
284 if (stat(buf_string(oldpath), &st) == -1)
285 {
286 mutt_debug(LL_DEBUG1, "File already removed (just continuing)\n");
287 goto cleanup;
288 }
289
290 if (rename(buf_string(oldpath), buf_string(fullpath)) != 0)
291 {
292 mutt_perror("rename");
293 rc = -1;
294 goto cleanup;
295 }
296 mutt_str_replace(&e->path, buf_string(partpath));
297 }
298
299cleanup:
300 buf_pool_release(&newpath);
301 buf_pool_release(&partpath);
302 buf_pool_release(&fullpath);
303 buf_pool_release(&oldpath);
304
305 return rc;
306}
307
316bool maildir_sync_mailbox_message(struct Mailbox *m, struct Email *e, struct HeaderCache *hc)
317{
318 if (!e)
319 return false;
320
321 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
322 if (e->deleted && !c_maildir_trash)
323 {
324 char path[PATH_MAX] = { 0 };
325 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
327 unlink(path);
328 }
329 else if (e->changed || e->attach_del ||
330 ((c_maildir_trash || e->trash) && (e->deleted != e->trash)))
331 {
332 if (maildir_sync_message(m, e) == -1)
333 return false;
334 }
335
336 if (e->changed)
338
339 return true;
340}
341
365static int maildir_commit_message(struct Mailbox *m, struct Message *msg, struct Email *e)
366{
367 char subdir[4] = { 0 };
368 char suffix[PATH_MAX] = { 0 };
369 int rc = 0;
370
371 if (mutt_file_fsync_close(&msg->fp))
372 {
373 mutt_perror(_("Could not flush message to disk"));
374 return -1;
375 }
376
377 /* extract the subdir */
378 char *s = strrchr(msg->path, '/');
379 if (!s)
380 {
381 mutt_debug(LL_DEBUG1, "path '%s' lacks expected '/'\n", msg->path);
382 return -1;
383 }
384 s++;
385 mutt_str_copy(subdir, s, 4);
386
387 /* extract the flags */
388 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
389 s = strchr(s, c_maildir_field_delimiter);
390 if (s)
391 mutt_str_copy(suffix, s, sizeof(suffix));
392 else
393 suffix[0] = '\0';
394
395 /* construct a new file name. */
396 struct Buffer *path = buf_pool_get();
397 struct Buffer *full = buf_pool_get();
398 for (int retries = 0; retries < 16; retries++)
399 {
400 buf_printf(path, "%s/%lld.R%" PRIu64 ".%s%s", subdir, (long long) mutt_date_now(),
401 mutt_rand64(), NONULL(ShortHostname), suffix);
402 buf_printf(full, "%s/%s", mailbox_path(m), buf_string(path));
403
404 mutt_debug(LL_DEBUG2, "renaming %s to %s\n", msg->path, buf_string(full));
405
406 if (mutt_file_safe_rename(msg->path, buf_string(full)) == 0)
407 {
408 /* Adjust the mtime on the file to match the time at which this
409 * message was received. Currently this is only set when copying
410 * messages between mailboxes, so we test to ensure that it is
411 * actually set. */
412 if (msg->received != 0)
413 {
414 struct utimbuf ut = { 0 };
415 int rc_utime;
416
417 ut.actime = msg->received;
418 ut.modtime = msg->received;
419 do
420 {
421 rc_utime = utime(buf_string(full), &ut);
422 } while ((rc_utime == -1) && (errno == EINTR));
423 if (rc_utime == -1)
424 {
425 mutt_perror(_("maildir_commit_message(): unable to set time on file"));
426 rc = -1;
427 goto cleanup;
428 }
429 }
430
431#ifdef USE_NOTMUCH
432 if (m->type == MUTT_NOTMUCH)
433 nm_update_filename(m, e->path, buf_string(full), e);
434#endif
435 if (e)
436 mutt_str_replace(&e->path, buf_string(path));
438 FREE(&msg->path);
439
440 goto cleanup;
441 }
442 else if (errno != EEXIST)
443 {
444 mutt_perror("%s", mailbox_path(m));
445 rc = -1;
446 goto cleanup;
447 }
448 }
449
450 /* All retries exhausted */
451 mutt_debug(LL_DEBUG1, "failed after 16 retries\n");
452 rc = -1;
453
454cleanup:
455 buf_pool_release(&path);
456 buf_pool_release(&full);
457
458 return rc;
459}
460
468int maildir_rewrite_message(struct Mailbox *m, struct Email *e)
469{
470 if (!m || !e)
471 return -1;
472
473 bool restore = true;
474
475 long old_body_offset = e->body->offset;
476 long old_body_length = e->body->length;
477 long old_hdr_lines = e->lines;
478
479 struct Message *src = mx_msg_open(m, e);
480 struct Message *dest = mx_msg_open_new(m, e, MUTT_MSG_NONE);
481 if (!src || !dest)
482 {
483 mx_msg_close(m, &src);
484 mx_msg_close(m, &dest);
485 return -1;
486 }
487
488 int rc = mutt_copy_message(dest->fp, e, src, MUTT_CM_UPDATE, CH_UPDATE | CH_UPDATE_LEN, 0);
489 if (rc == 0)
490 {
491 char oldpath[PATH_MAX] = { 0 };
492 char partpath[PATH_MAX] = { 0 };
493 snprintf(oldpath, sizeof(oldpath), "%s/%s", mailbox_path(m), e->path);
494 mutt_str_copy(partpath, e->path, sizeof(partpath));
495
496 rc = maildir_commit_message(m, dest, e);
497
498 if (rc == 0)
499 {
500 unlink(oldpath);
501 restore = false;
502 }
503 }
504 mx_msg_close(m, &src);
505 mx_msg_close(m, &dest);
506
507 if ((rc == -1) && restore)
508 {
509 e->body->offset = old_body_offset;
510 e->body->length = old_body_length;
511 e->lines = old_hdr_lines;
512 }
513
515 return rc;
516}
517
518// Mailbox API -----------------------------------------------------------------
519
523bool maildir_msg_open(struct Mailbox *m, struct Message *msg, struct Email *e)
524{
525 char path[PATH_MAX] = { 0 };
526
527 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
528
529 msg->fp = mutt_file_fopen(path, "r");
530 if (!msg->fp && (errno == ENOENT))
531 msg->fp = maildir_open_find_message(mailbox_path(m), e->path, NULL);
532
533 if (!msg->fp)
534 {
535 mutt_perror("%s", path);
536 return false;
537 }
538
539 return true;
540}
541
550bool maildir_msg_open_new(struct Mailbox *m, struct Message *msg, const struct Email *e)
551{
552 int fd;
553 char path[PATH_MAX] = { 0 };
554 char suffix[PATH_MAX] = { 0 };
555 char subdir[16] = { 0 };
556
557 if (e)
558 {
559 struct Email tmp = *e;
560 tmp.deleted = false;
561 tmp.edata = NULL;
562 maildir_gen_flags(suffix, sizeof(suffix), &tmp);
563 }
564 else
565 {
566 *suffix = '\0';
567 }
568
569 if (e && (e->read || e->old))
570 mutt_str_copy(subdir, "cur", sizeof(subdir));
571 else
572 mutt_str_copy(subdir, "new", sizeof(subdir));
573
574 mode_t new_umask = maildir_umask(m);
575 mode_t old_umask = umask(new_umask);
576 mutt_debug(LL_DEBUG3, "umask set to %03o\n", new_umask);
577
578 for (int retries = 0; retries < 16; retries++)
579 {
580 snprintf(path, sizeof(path), "%s/tmp/%s.%lld.R%" PRIu64 ".%s%s",
581 mailbox_path(m), subdir, (long long) mutt_date_now(),
582 mutt_rand64(), NONULL(ShortHostname), suffix);
583
584 mutt_debug(LL_DEBUG2, "Trying %s\n", path);
585
586 fd = open(path, O_WRONLY | O_EXCL | O_CREAT, 0666);
587 if (fd == -1)
588 {
589 if (errno != EEXIST)
590 {
591 umask(old_umask);
592 mutt_debug(LL_DEBUG3, "umask set to %03o\n", old_umask);
593 mutt_perror("%s", path);
594 return false;
595 }
596 }
597 else
598 {
599 mutt_debug(LL_DEBUG2, "Success\n");
600 msg->path = mutt_str_dup(path);
601 break;
602 }
603 }
604
605 if (fd == -1)
606 {
607 umask(old_umask);
608 mutt_debug(LL_DEBUG1, "%s: failed after 16 retries\n", __func__);
609 return false;
610 }
611 umask(old_umask);
612 mutt_debug(LL_DEBUG3, "umask set to %03o\n", old_umask);
613
614 msg->fp = fdopen(fd, "w");
615 if (!msg->fp)
616 {
617 FREE(&msg->path);
618 close(fd);
619 unlink(path);
620 return false;
621 }
622
623 return true;
624}
625
629int maildir_msg_commit(struct Mailbox *m, struct Message *msg)
630{
631 return maildir_commit_message(m, msg, NULL);
632}
633
639int maildir_msg_close(struct Mailbox *m, struct Message *msg)
640{
641 return mutt_file_fclose(&msg->fp);
642}
643
647int maildir_msg_save_hcache(struct Mailbox *m, struct Email *e)
648{
649 int rc = 0;
650
651 struct HeaderCache *hc = maildir_hcache_open(m);
652 rc = maildir_hcache_store(hc, e);
654
655 return rc;
656}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
#define mutt_numeric_cmp(a, b)
Compare two numbers, return -1, 0, or 1.
Definition sort.h:27
const char * cc_maildir_field_delimiter(void)
Get the cached value of $maildir_field_delimiter.
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_email.c:920
@ MUTT_CM_UPDATE
Update structs on sync.
Definition copy_email.h:46
@ CH_UPDATE
Update the status and x-status fields?
Definition copy_email.h:66
@ CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition copy_email.h:76
Convenience wrapper for the core headers.
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:216
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition mailbox.h:50
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
Structs that make up an email.
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition file.c:310
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition file.c:535
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition file.c:128
@ MUTT_OPENDIR_CREATE
Create the directory if it doesn't exist.
Definition file.h:69
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
char * ShortHostname
Short version of the hostname.
Definition globals.c:36
Global variables.
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
int maildir_msg_close(struct Mailbox *m, struct Message *msg)
Close an email - Implements MxOps::msg_close() -.
Definition message.c:639
int maildir_msg_commit(struct Mailbox *m, struct Message *msg)
Save changes to an email - Implements MxOps::msg_commit() -.
Definition message.c:629
bool maildir_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() -.
Definition message.c:550
bool maildir_msg_open(struct Mailbox *m, struct Message *msg, struct Email *e)
Open an email message in a Mailbox - Implements MxOps::msg_open() -.
Definition message.c:523
int maildir_msg_save_hcache(struct Mailbox *m, struct Email *e)
Save message to the header cache - Implements MxOps::msg_save_hcache() -.
Definition message.c:647
static int maildir_sort_flags(const void *a, const void *b, void *sdata)
Compare two flag characters - Implements sort_t -.
Definition message.c:60
Maildir Header Cache.
@ LL_DEBUG3
Log at debug level 3.
Definition logging2.h:47
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
struct MaildirEmailData * maildir_edata_get(struct Email *e)
Get the private data for this Email.
Definition edata.c:63
Maildir-specific Email data.
int maildir_hcache_store(struct HeaderCache *hc, struct Email *e)
Save an Email to the Header Cache.
Definition hcache.c:163
struct HeaderCache * maildir_hcache_open(struct Mailbox *m)
Open the Header Cache.
Definition hcache.c:104
int maildir_hcache_delete(struct HeaderCache *hc, struct Email *e)
Delete an Email from the Header Cache.
Definition hcache.c:89
void maildir_hcache_close(struct HeaderCache **ptr)
Close the Header Cache.
Definition hcache.c:77
static int maildir_sync_message(struct Mailbox *m, struct Email *e)
Sync an email to a Maildir folder.
Definition message.c:221
int nm_update_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Change the filename.
Definition notmuch.c:1811
int maildir_rewrite_message(struct Mailbox *m, struct Email *e)
Sync a message in an Maildir folder.
Definition message.c:468
FILE * maildir_open_find_message(const char *folder, const char *msg, char **newname)
Find a message by name.
Definition message.c:168
static FILE * maildir_open_find_message_dir(const char *folder, const char *unique, const char *subfolder, char **newname)
Find a message in a maildir folder.
Definition message.c:112
bool maildir_sync_mailbox_message(struct Mailbox *m, struct Email *e, struct HeaderCache *hc)
Save changes to the mailbox.
Definition message.c:316
void maildir_gen_flags(char *dest, size_t destlen, struct Email *e)
Generate the Maildir flags for an email.
Definition message.c:71
static int maildir_commit_message(struct Mailbox *m, struct Message *msg, struct Email *e)
Commit a message to a maildir folder.
Definition message.c:365
Maildir Message.
mode_t maildir_umask(struct Mailbox *m)
Create a umask from the mailbox directory.
Definition shared.c:46
void maildir_canon_filename(struct Buffer *dest, const char *src)
Generate the canonical filename for a Maildir folder.
Definition shared.c:72
Maildir shared functions.
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:459
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
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:587
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
#define PATH_MAX
Definition mutt.h:49
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1185
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition mx.c:1139
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition mx.c:1044
API for mailboxes.
@ MUTT_MSG_NONE
No flags are set.
Definition mx.h:42
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
void mutt_qsort_r(void *base, size_t nmemb, size_t size, sort_t compar, void *sdata)
Sort an array, where the comparator has access to opaque data rather than requiring global variables.
Definition qsort_r.c:72
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition random.c:123
#define NONULL(x)
Definition string2.h:44
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
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
String manipulation buffer.
Definition buffer.h:36
char * dptr
Current read/write position.
Definition buffer.h:38
char * data
Pointer to data.
Definition buffer.h:37
The envelope/body of an email.
Definition email.h:39
bool read
Email is read.
Definition email.h:50
struct Envelope * env
Envelope information.
Definition email.h:68
void * edata
Driver-specific data.
Definition email.h:74
int lines
How many lines in the body of this message?
Definition email.h:62
struct Body * body
List of MIME parts.
Definition email.h:69
bool old
Email is seen, but unread.
Definition email.h:49
bool changed
Email has been edited.
Definition email.h:77
bool attach_del
Has an attachment marked for deletion.
Definition email.h:99
bool flagged
Marked important?
Definition email.h:47
bool replied
Email has been replied to.
Definition email.h:51
char * path
Path of Email (for local Mailboxes)
Definition email.h:70
bool deleted
Email is deleted.
Definition email.h:78
bool trash
Message is marked as trashed on disk (used by the maildir_trash option)
Definition email.h:53
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition envelope.h:90
Header Cache.
Definition lib.h:87
A mailbox.
Definition mailbox.h:81
enum MailboxType type
Mailbox type.
Definition mailbox.h:104
Maildir-specific Email data -.
Definition edata.h:32
A local copy of an email.
Definition message.h:34
FILE * fp
pointer to the message data
Definition message.h:35
char * path
path to temp file
Definition message.h:36
char * committed_path
the final path generated by mx_msg_commit()
Definition message.h:37
time_t received
Time at which this message was received.
Definition message.h:46
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49