NeoMutt  2024-04-25-91-gb0e085
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
message.c
Go to the documentation of this file.
1
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 "copy.h"
47#include "edata.h"
48#include "globals.h"
49#include "hcache.h"
50#include "mx.h"
51#include "shared.h"
52#include "sort.h"
53
54struct HeaderCache;
55
56int nm_update_filename(struct Mailbox *m, const char *old_file,
57 const char *new_file, struct Email *e);
58
62static int maildir_sort_flags(const void *a, const void *b, void *sdata)
63{
64 return mutt_numeric_cmp(*((const char *) a), *((const char *) b));
65}
66
73void maildir_gen_flags(char *dest, size_t destlen, struct Email *e)
74{
75 *dest = '\0';
76
77 const char *flags = NULL;
78
80 if (edata)
81 flags = edata->custom_flags;
82
83 /* The maildir specification requires that all files in the cur
84 * subdirectory have the :unique string appended, regardless of whether
85 * or not there are any flags. If .old is set, we know that this message
86 * will end up in the cur directory, so we include it in the following
87 * test even though there is no associated flag. */
88
89 if (e->flagged || e->replied || e->read || e->deleted || e->old || flags)
90 {
91 char tmp[1024] = { 0 };
92 snprintf(tmp, sizeof(tmp), "%s%s%s%s%s", e->flagged ? "F" : "", e->replied ? "R" : "",
93 e->read ? "S" : "", e->deleted ? "T" : "", NONULL(flags));
94 if (flags)
95 mutt_qsort_r(tmp, strlen(tmp), 1, maildir_sort_flags, NULL);
96
97 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
98 snprintf(dest, destlen, "%c2,%s", c_maildir_field_delimiter, tmp);
99 }
100}
101
114static FILE *maildir_open_find_message_dir(const char *folder, const char *unique,
115 const char *subfolder, char **newname)
116{
117 struct Buffer *dirname = buf_pool_get();
118 struct Buffer *tunique = buf_pool_get();
119 struct Buffer *fname = buf_pool_get();
120
121 struct dirent *de = NULL;
122
123 FILE *fp = NULL;
124 int oe = ENOENT;
125
126 buf_printf(dirname, "%s/%s", folder, subfolder);
127
129 if (!dir)
130 {
131 errno = ENOENT;
132 goto cleanup;
133 }
134
135 while ((de = readdir(dir)))
136 {
137 maildir_canon_filename(tunique, de->d_name);
138
139 if (mutt_str_equal(buf_string(tunique), unique))
140 {
141 buf_printf(fname, "%s/%s/%s", folder, subfolder, de->d_name);
142 fp = mutt_file_fopen(buf_string(fname), "r");
143 oe = errno;
144 break;
145 }
146 }
147
148 closedir(dir);
149
150 if (newname && fp)
151 *newname = buf_strdup(fname);
152
153 errno = oe;
154
155cleanup:
156 buf_pool_release(&dirname);
157 buf_pool_release(&tunique);
158 buf_pool_release(&fname);
159
160 return fp;
161}
162
170FILE *maildir_open_find_message(const char *folder, const char *msg, char **newname)
171{
172 static unsigned int new_hits = 0, cur_hits = 0; /* simple dynamic optimization */
173
174 struct Buffer *unique = buf_pool_get();
175 maildir_canon_filename(unique, msg);
176
177 FILE *fp = maildir_open_find_message_dir(folder, buf_string(unique),
178 (new_hits > cur_hits) ? "new" : "cur", newname);
179 if (fp || (errno != ENOENT))
180 {
181 if ((new_hits < UINT_MAX) && (cur_hits < UINT_MAX))
182 {
183 new_hits += ((new_hits > cur_hits) ? 1 : 0);
184 cur_hits += ((new_hits > cur_hits) ? 0 : 1);
185 }
186
187 goto cleanup;
188 }
189 fp = maildir_open_find_message_dir(folder, buf_string(unique),
190 (new_hits > cur_hits) ? "cur" : "new", newname);
191 if (fp || (errno != ENOENT))
192 {
193 if ((new_hits < UINT_MAX) && (cur_hits < UINT_MAX))
194 {
195 new_hits += ((new_hits > cur_hits) ? 0 : 1);
196 cur_hits += ((new_hits > cur_hits) ? 1 : 0);
197 }
198
199 goto cleanup;
200 }
201
202 fp = NULL;
203
204cleanup:
205 buf_pool_release(&unique);
206
207 return fp;
208}
209
217static int maildir_sync_message(struct Mailbox *m, struct Email *e)
218{
219 if (!m || !e)
220 return -1;
221
222 struct Buffer *newpath = NULL;
223 struct Buffer *partpath = NULL;
224 struct Buffer *fullpath = NULL;
225 struct Buffer *oldpath = NULL;
226 char suffix[16] = { 0 };
227 int rc = 0;
228
229 if (e->attach_del || e->env->changed)
230 {
231 /* when doing attachment deletion/rethreading, fall back to the maildir case. */
232 if (maildir_rewrite_message(m, e) != 0)
233 return -1;
234 e->env->changed = false;
235 }
236 else
237 {
238 /* we just have to rename the file. */
239
240 char *p = strrchr(e->path, '/');
241 if (!p)
242 {
243 mutt_debug(LL_DEBUG1, "%s: unable to find subdir!\n", e->path);
244 return -1;
245 }
246 p++;
247 newpath = buf_pool_get();
248 partpath = buf_pool_get();
249 fullpath = buf_pool_get();
250 oldpath = buf_pool_get();
251
252 buf_strcpy(newpath, p);
253
254 /* kill the previous flags */
255 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
256 p = strchr(newpath->data, c_maildir_field_delimiter);
257 if (p)
258 {
259 *p = '\0';
260 newpath->dptr = p; /* fix buffer up, just to be safe */
261 }
262
263 maildir_gen_flags(suffix, sizeof(suffix), e);
264
265 buf_printf(partpath, "%s/%s%s", (e->read || e->old) ? "cur" : "new",
266 buf_string(newpath), suffix);
267 buf_printf(fullpath, "%s/%s", mailbox_path(m), buf_string(partpath));
268 buf_printf(oldpath, "%s/%s", mailbox_path(m), e->path);
269
270 if (mutt_str_equal(buf_string(fullpath), buf_string(oldpath)))
271 {
272 /* message hasn't really changed */
273 goto cleanup;
274 }
275
276 /* record that the message is possibly marked as trashed on disk */
277 e->trash = e->deleted;
278
279 struct stat st = { 0 };
280 if (stat(buf_string(oldpath), &st) == -1)
281 {
282 mutt_debug(LL_DEBUG1, "File already removed (just continuing)");
283 goto cleanup;
284 }
285
286 if (rename(buf_string(oldpath), buf_string(fullpath)) != 0)
287 {
288 mutt_perror("rename");
289 rc = -1;
290 goto cleanup;
291 }
292 mutt_str_replace(&e->path, buf_string(partpath));
293 }
294
295cleanup:
296 buf_pool_release(&newpath);
297 buf_pool_release(&partpath);
298 buf_pool_release(&fullpath);
299 buf_pool_release(&oldpath);
300
301 return rc;
302}
303
312bool maildir_sync_mailbox_message(struct Mailbox *m, struct Email *e, struct HeaderCache *hc)
313{
314 if (!e)
315 return false;
316
317 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
318 if (e->deleted && !c_maildir_trash)
319 {
320 char path[PATH_MAX] = { 0 };
321 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
323 unlink(path);
324 }
325 else if (e->changed || e->attach_del ||
326 ((c_maildir_trash || e->trash) && (e->deleted != e->trash)))
327 {
328 if (maildir_sync_message(m, e) == -1)
329 return false;
330 }
331
332 if (e->changed)
334
335 return true;
336}
337
361static int maildir_commit_message(struct Mailbox *m, struct Message *msg, struct Email *e)
362{
363 char subdir[4] = { 0 };
364 char suffix[16] = { 0 };
365 int rc = 0;
366
367 if (mutt_file_fsync_close(&msg->fp))
368 {
369 mutt_perror(_("Could not flush message to disk"));
370 return -1;
371 }
372
373 /* extract the subdir */
374 char *s = strrchr(msg->path, '/') + 1;
375 mutt_str_copy(subdir, s, 4);
376
377 /* extract the flags */
378 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
379 s = strchr(s, c_maildir_field_delimiter);
380 if (s)
381 mutt_str_copy(suffix, s, sizeof(suffix));
382 else
383 suffix[0] = '\0';
384
385 /* construct a new file name. */
386 struct Buffer *path = buf_pool_get();
387 struct Buffer *full = buf_pool_get();
388 while (true)
389 {
390 buf_printf(path, "%s/%lld.R%" PRIu64 ".%s%s", subdir, (long long) mutt_date_now(),
391 mutt_rand64(), NONULL(ShortHostname), suffix);
392 buf_printf(full, "%s/%s", mailbox_path(m), buf_string(path));
393
394 mutt_debug(LL_DEBUG2, "renaming %s to %s\n", msg->path, buf_string(full));
395
396 if (mutt_file_safe_rename(msg->path, buf_string(full)) == 0)
397 {
398 /* Adjust the mtime on the file to match the time at which this
399 * message was received. Currently this is only set when copying
400 * messages between mailboxes, so we test to ensure that it is
401 * actually set. */
402 if (msg->received != 0)
403 {
404 struct utimbuf ut = { 0 };
405 int rc_utime;
406
407 ut.actime = msg->received;
408 ut.modtime = msg->received;
409 do
410 {
411 rc_utime = utime(buf_string(full), &ut);
412 } while ((rc_utime == -1) && (errno == EINTR));
413 if (rc_utime == -1)
414 {
415 mutt_perror(_("maildir_commit_message(): unable to set time on file"));
416 rc = -1;
417 goto cleanup;
418 }
419 }
420
421#ifdef USE_NOTMUCH
422 if (m->type == MUTT_NOTMUCH)
423 nm_update_filename(m, e->path, buf_string(full), e);
424#endif
425 if (e)
426 mutt_str_replace(&e->path, buf_string(path));
428 FREE(&msg->path);
429
430 goto cleanup;
431 }
432 else if (errno != EEXIST)
433 {
434 mutt_perror("%s", mailbox_path(m));
435 rc = -1;
436 goto cleanup;
437 }
438 }
439
440cleanup:
441 buf_pool_release(&path);
442 buf_pool_release(&full);
443
444 return rc;
445}
446
454int maildir_rewrite_message(struct Mailbox *m, struct Email *e)
455{
456 if (!m || !e)
457 return -1;
458
459 bool restore = true;
460
461 long old_body_offset = e->body->offset;
462 long old_body_length = e->body->length;
463 long old_hdr_lines = e->lines;
464
465 struct Message *src = mx_msg_open(m, e);
466 struct Message *dest = mx_msg_open_new(m, e, MUTT_MSG_NO_FLAGS);
467 if (!src || !dest)
468 return -1;
469
470 int rc = mutt_copy_message(dest->fp, e, src, MUTT_CM_UPDATE, CH_UPDATE | CH_UPDATE_LEN, 0);
471 if (rc == 0)
472 {
473 char oldpath[PATH_MAX] = { 0 };
474 char partpath[PATH_MAX] = { 0 };
475 snprintf(oldpath, sizeof(oldpath), "%s/%s", mailbox_path(m), e->path);
476 mutt_str_copy(partpath, e->path, sizeof(partpath));
477
478 rc = maildir_commit_message(m, dest, e);
479
480 if (rc == 0)
481 {
482 unlink(oldpath);
483 restore = false;
484 }
485 }
486 mx_msg_close(m, &src);
487 mx_msg_close(m, &dest);
488
489 if ((rc == -1) && restore)
490 {
491 e->body->offset = old_body_offset;
492 e->body->length = old_body_length;
493 e->lines = old_hdr_lines;
494 }
495
497 return rc;
498}
499
500// Mailbox API -----------------------------------------------------------------
501
505bool maildir_msg_open(struct Mailbox *m, struct Message *msg, struct Email *e)
506{
507 char path[PATH_MAX] = { 0 };
508
509 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
510
511 msg->fp = mutt_file_fopen(path, "r");
512 if (!msg->fp && (errno == ENOENT))
513 msg->fp = maildir_open_find_message(mailbox_path(m), e->path, NULL);
514
515 if (!msg->fp)
516 {
517 mutt_perror("%s", path);
518 return false;
519 }
520
521 return true;
522}
523
532bool maildir_msg_open_new(struct Mailbox *m, struct Message *msg, const struct Email *e)
533{
534 int fd;
535 char path[PATH_MAX] = { 0 };
536 char suffix[16] = { 0 };
537 char subdir[16] = { 0 };
538
539 if (e)
540 {
541 struct Email tmp = *e;
542 tmp.deleted = false;
543 tmp.edata = NULL;
544 maildir_gen_flags(suffix, sizeof(suffix), &tmp);
545 }
546 else
547 {
548 *suffix = '\0';
549 }
550
551 if (e && (e->read || e->old))
552 mutt_str_copy(subdir, "cur", sizeof(subdir));
553 else
554 mutt_str_copy(subdir, "new", sizeof(subdir));
555
556 mode_t new_umask = maildir_umask(m);
557 mode_t old_umask = umask(new_umask);
558 mutt_debug(LL_DEBUG3, "umask set to %03o\n", new_umask);
559
560 while (true)
561 {
562 snprintf(path, sizeof(path), "%s/tmp/%s.%lld.R%" PRIu64 ".%s%s",
563 mailbox_path(m), subdir, (long long) mutt_date_now(),
564 mutt_rand64(), NONULL(ShortHostname), suffix);
565
566 mutt_debug(LL_DEBUG2, "Trying %s\n", path);
567
568 fd = open(path, O_WRONLY | O_EXCL | O_CREAT, 0666);
569 if (fd == -1)
570 {
571 if (errno != EEXIST)
572 {
573 umask(old_umask);
574 mutt_debug(LL_DEBUG3, "umask set to %03o\n", old_umask);
575 mutt_perror("%s", path);
576 return false;
577 }
578 }
579 else
580 {
581 mutt_debug(LL_DEBUG2, "Success\n");
582 msg->path = mutt_str_dup(path);
583 break;
584 }
585 }
586 umask(old_umask);
587 mutt_debug(LL_DEBUG3, "umask set to %03o\n", old_umask);
588
589 msg->fp = fdopen(fd, "w");
590 if (!msg->fp)
591 {
592 FREE(&msg->path);
593 close(fd);
594 unlink(path);
595 return false;
596 }
597
598 return true;
599}
600
604int maildir_msg_commit(struct Mailbox *m, struct Message *msg)
605{
606 return maildir_commit_message(m, msg, NULL);
607}
608
614int maildir_msg_close(struct Mailbox *m, struct Message *msg)
615{
616 return mutt_file_fclose(&msg->fp);
617}
618
622int maildir_msg_save_hcache(struct Mailbox *m, struct Email *e)
623{
624 int rc = 0;
625
626 struct HeaderCache *hc = maildir_hcache_open(m);
627 rc = maildir_hcache_store(hc, e);
629
630 return rc;
631}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:571
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.
const char * cc_maildir_field_delimiter(void)
Get the cached value of $maildir_field_delimiter.
Definition: config_cache.c:131
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:907
Duplicate the structure of an entire email.
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:42
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:54
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:64
Convenience wrapper for the core headers.
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:223
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
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:371
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:642
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:193
@ MUTT_OPENDIR_CREATE
Create the directory if it doesn't exist.
Definition: file.h:75
#define mutt_file_fclose(FP)
Definition: file.h:149
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:148
char * ShortHostname
Short version of the hostname.
Definition: globals.c:39
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
int maildir_msg_close(struct Mailbox *m, struct Message *msg)
Close an email - Implements MxOps::msg_close() -.
Definition: message.c:614
int maildir_msg_commit(struct Mailbox *m, struct Message *msg)
Save changes to an email - Implements MxOps::msg_commit() -.
Definition: message.c:604
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:532
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:505
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:622
static int maildir_sort_flags(const void *a, const void *b, void *sdata)
Compare two flag characters - Implements sort_t -.
Definition: message.c:62
Maildir Header Cache.
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
struct MaildirEmailData * maildir_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:64
int maildir_hcache_store(struct HeaderCache *hc, struct Email *e)
Save an Email to the Header Cache.
Definition: hcache.c:155
struct HeaderCache * maildir_hcache_open(struct Mailbox *m)
Open the Header Cache.
Definition: hcache.c:96
int maildir_hcache_delete(struct HeaderCache *hc, struct Email *e)
Delete an Email from the Header Cache.
Definition: hcache.c:81
void maildir_hcache_close(struct HeaderCache **ptr)
Close the Header Cache.
Definition: hcache.c:69
static int maildir_sync_message(struct Mailbox *m, struct Email *e)
Sync an email to a Maildir folder.
Definition: message.c:217
int nm_update_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Change the filename.
Definition: notmuch.c:1763
int maildir_rewrite_message(struct Mailbox *m, struct Email *e)
Sync a message in an Maildir folder.
Definition: message.c:454
FILE * maildir_open_find_message(const char *folder, const char *msg, char **newname)
Find a message by name.
Definition: message.c:170
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:114
bool maildir_sync_mailbox_message(struct Mailbox *m, struct Email *e, struct HeaderCache *hc)
Save changes to the mailbox.
Definition: message.c:312
void maildir_gen_flags(char *dest, size_t destlen, struct Email *e)
Generate the Maildir flags for an email.
Definition: message.c:73
static int maildir_commit_message(struct Mailbox *m, struct Message *msg, struct Email *e)
Commit a message to a maildir folder.
Definition: message.c:361
mode_t maildir_umask(struct Mailbox *m)
Create a umask from the mailbox directory.
Definition: shared.c:47
void maildir_canon_filename(struct Buffer *dest, const char *src)
Generate the canonical filename for a Maildir folder.
Definition: shared.c:73
#define FREE(x)
Definition: memory.h:45
MH shared functions.
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:456
Convenience wrapper for the library headers.
Message logging.
#define _(a)
Definition: message.h:28
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
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:581
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:280
#define PATH_MAX
Definition: mutt.h:42
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1180
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1134
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1040
API for mailboxes.
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:38
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
Pop-specific Email data.
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:67
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: random.c:123
Assorted sorting methods.
#define mutt_numeric_cmp(a, b)
Definition: sort.h:35
#define NONULL(x)
Definition: string2.h:37
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:86
A mailbox.
Definition: mailbox.h:79
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
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:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46