NeoMutt  2023-05-17-56-ga67199
Teaching an old dog new tricks
DOXYGEN
hcache.c
Go to the documentation of this file.
1
35#include "config.h"
36#include <assert.h>
37#include <errno.h>
38#include <limits.h>
39#include <stdbool.h>
40#include <stdint.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <sys/stat.h>
45#include <unistd.h>
46#include "mutt/lib.h"
47#include "config/lib.h"
48#include "email/lib.h"
49#include "core/lib.h"
50#include "lib.h"
51#include "compress/lib.h"
52#include "store/lib.h"
53#include "hcache/hcversion.h"
54#include "muttlib.h"
55#include "serialize.h"
56
57#if !(defined(HAVE_BDB) || defined(HAVE_GDBM) || defined(HAVE_KC) || \
58 defined(HAVE_LMDB) || defined(HAVE_QDBM) || defined(HAVE_ROCKSDB) || \
59 defined(HAVE_TC) || defined(HAVE_TDB))
60#error "No hcache backend defined"
61#endif
62
64static unsigned int HcacheVer = 0x0;
65
70static size_t header_size(void)
71{
72 return sizeof(int) + sizeof(uint32_t);
73}
74
86static void *dump_email(struct HeaderCache *hc, const struct Email *e, int *off, uint32_t uidvalidity)
87{
88 struct Email e_dump;
89 bool convert = !CharsetIsUtf8;
90
91 *off = 0;
92 unsigned char *d = mutt_mem_malloc(4096);
93
94 d = serial_dump_uint32_t((uidvalidity != 0) ? uidvalidity : mutt_date_now(), d, off);
95 d = serial_dump_int(hc->crc, d, off);
96
97 assert((size_t) *off == header_size());
98
99 lazy_realloc(&d, *off + sizeof(struct Email));
100 memcpy(&e_dump, e, sizeof(struct Email));
101
102 /* some fields are not safe to cache */
103 e_dump.tagged = false;
104 e_dump.changed = false;
105 e_dump.threaded = false;
106 e_dump.recip_valid = false;
107 e_dump.searched = false;
108 e_dump.matched = false;
109 e_dump.collapsed = false;
110 e_dump.visible = true;
111 e_dump.num_hidden = 0;
112 e_dump.recipient = 0;
113 e_dump.attr_color = NULL;
114 e_dump.attach_valid = false;
115 e_dump.path = NULL;
116 e_dump.tree = NULL;
117 e_dump.thread = NULL;
118 e_dump.sequence = 0;
119 e_dump.notify = NULL;
120 STAILQ_INIT(&e_dump.tags);
121#ifdef MIXMASTER
122 STAILQ_INIT(&e_dump.chain);
123#endif
124 e_dump.edata = NULL;
125
126 memcpy(d + *off, &e_dump, sizeof(struct Email));
127 *off += sizeof(struct Email);
128
129 d = serial_dump_envelope(e_dump.env, d, off, convert);
130 d = serial_dump_body(e_dump.body, d, off, convert);
131 d = serial_dump_tags(&e->tags, d, off);
132
133 return d;
134}
135
144static struct Email *restore_email(const unsigned char *d)
145{
146 int off = 0;
147 struct Email *e = email_new();
148 bool convert = !CharsetIsUtf8;
149
150 /* skip validate */
151 off += sizeof(uint32_t);
152
153 /* skip crc */
154 off += sizeof(unsigned int);
155
156 size_t sequence = e->sequence;
157 struct Notify *notify = e->notify;
158 memcpy(e, d + off, sizeof(struct Email));
159 off += sizeof(struct Email);
160 e->sequence = sequence;
161 e->notify = notify;
162
163 STAILQ_INIT(&e->tags);
164#ifdef MIXMASTER
165 STAILQ_INIT(&e->chain);
166#endif
167
168 e->env = mutt_env_new();
169 serial_restore_envelope(e->env, d, &off, convert);
170
171 e->body = mutt_body_new();
172 serial_restore_body(e->body, d, &off, convert);
173 serial_restore_tags(&e->tags, d, &off);
174
175 return e;
176}
177
182{
183 char key[1024];
184 size_t len;
185};
186
193static struct RealKey *realkey(const char *key, size_t keylen)
194{
195 static struct RealKey rk;
196#ifdef USE_HCACHE_COMPRESSION
197 const char *const c_header_cache_compress_method = cs_subset_string(NeoMutt->sub, "header_cache_compress_method");
198 if (c_header_cache_compress_method)
199 {
200 const struct ComprOps *cops = compress_get_ops(c_header_cache_compress_method);
201
202 rk.len = snprintf(rk.key, sizeof(rk.key), "%s-%s", key, cops->name);
203 }
204 else
205#endif
206 {
207 memcpy(rk.key, key, keylen + 1); // Including NUL byte
208 rk.len = keylen;
209 }
210 return &rk;
211}
212
219static bool create_hcache_dir(const char *path)
220{
221 char *dir = mutt_str_dup(path);
222 if (!dir)
223 return false;
224
225 char *p = strrchr(dir, '/');
226 if (!p)
227 {
228 FREE(&dir);
229 return true;
230 }
231
232 *p = '\0';
233
234 int rc = mutt_file_mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO);
235 if (rc != 0)
236 mutt_error(_("Can't create %s: %s"), dir, strerror(errno));
237
238 FREE(&dir);
239 return (rc == 0);
240}
241
263static void hcache_per_folder(struct Buffer *hcpath, const char *path,
264 const char *folder, hcache_namer_t namer)
265{
266 struct stat st = { 0 };
267
268 int plen = mutt_str_len(path);
269 int rc = stat(path, &st);
270 bool slash = (path[plen - 1] == '/');
271
272 if (((rc == 0) && !S_ISDIR(st.st_mode)) || ((rc == -1) && !slash))
273 {
274 /* An existing file or a non-existing path not ending with a slash */
275 mutt_encode_path(hcpath, path);
277 return;
278 }
279
280 /* We have a directory - no matter whether it exists, or not */
281 struct Buffer *hcfile = buf_pool_get();
282 if (namer)
283 {
284 namer(folder, hcfile);
285 buf_concat_path(hcpath, path, buf_string(hcfile));
286 }
287 else
288 {
289 unsigned char m[16]; /* binary md5sum */
290 struct Buffer *name = buf_pool_get();
291
292 const char *const c_header_cache_backend = cs_subset_string(NeoMutt->sub, "header_cache_backend");
293 const struct StoreOps *ops = store_get_backend_ops(c_header_cache_backend);
294 if (!ops)
295 return;
296
297#ifdef USE_HCACHE_COMPRESSION
298 const char *const c_header_cache_compress_method = cs_subset_string(NeoMutt->sub, "header_cache_compress_method");
299 const char *cm = c_header_cache_compress_method;
300 buf_printf(name, "%s|%s%s", ops->name, folder, cm ? cm : "");
301#else
302 buf_printf(name, "%s|%s", ops->name, folder);
303#endif
306 mutt_md5_toascii(m, name->data);
307 buf_printf(hcpath, "%s%s%s", path, slash ? "" : "/", buf_string(name));
309 }
310
311 mutt_encode_path(hcpath, buf_string(hcpath));
313 buf_pool_release(&hcfile);
314}
315
321static char *get_foldername(const char *folder)
322{
323 /* if the folder is local, canonify the path to avoid
324 * to ensure equivalent paths share the hcache */
325 char *p = mutt_mem_malloc(PATH_MAX + 1);
326 if (!realpath(folder, p))
327 mutt_str_replace(&p, folder);
328
329 return p;
330}
331
344static void *fetch_raw(struct HeaderCache *hc, const char *key, size_t keylen, size_t *dlen)
345{
346 if (!hc)
347 return NULL;
348
349 const char *const c_header_cache_backend = cs_subset_string(NeoMutt->sub, "header_cache_backend");
350 const struct StoreOps *ops = store_get_backend_ops(c_header_cache_backend);
351
352 if (!ops)
353 return NULL;
354
355 struct Buffer path = buf_make(1024);
356 keylen = buf_printf(&path, "%s%.*s", hc->folder, (int) keylen, key);
357 void *blob = ops->fetch(hc->ctx, buf_string(&path), keylen, dlen);
358 buf_dealloc(&path);
359 return blob;
360}
361
365static void free_raw(struct HeaderCache *hc, void **data)
366{
367 const char *const c_header_cache_backend = cs_subset_string(NeoMutt->sub, "header_cache_backend");
368 const struct StoreOps *ops = store_get_backend_ops(c_header_cache_backend);
369
370 if (!hc || !ops || !data || !*data)
371 return;
372
373 ops->free(hc->ctx, data);
374}
375
379struct HeaderCache *mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
380{
381 const char *const c_header_cache_backend = cs_subset_string(NeoMutt->sub, "header_cache_backend");
382 const struct StoreOps *ops = store_get_backend_ops(c_header_cache_backend);
383 if (!ops)
384 return NULL;
385
386 struct HeaderCache *hc = mutt_mem_calloc(1, sizeof(struct HeaderCache));
387
388 /* Calculate the current hcache version from dynamic configuration */
389 if (HcacheVer == 0x0)
390 {
391 union
392 {
393 unsigned char charval[16];
394 unsigned int intval;
395 } digest;
396 struct Md5Ctx md5ctx;
397
398 HcacheVer = HCACHEVER;
399
400 mutt_md5_init_ctx(&md5ctx);
401
402 /* Seed with the compiled-in header structure hash */
403 mutt_md5_process_bytes(&HcacheVer, sizeof(HcacheVer), &md5ctx);
404
405 /* Mix in user's spam list */
406 struct Replace *sp = NULL;
407 STAILQ_FOREACH(sp, &SpamList, entries)
408 {
409 mutt_md5_process(sp->regex->pattern, &md5ctx);
410 mutt_md5_process(sp->templ, &md5ctx);
411 }
412
413 /* Mix in user's nospam list */
414 struct RegexNode *np = NULL;
415 STAILQ_FOREACH(np, &NoSpamList, entries)
416 {
417 mutt_md5_process(np->regex->pattern, &md5ctx);
418 }
419
420 /* Get a hash and take its bytes as an (unsigned int) hash version */
421 mutt_md5_finish_ctx(&md5ctx, digest.charval);
422 HcacheVer = digest.intval;
423 }
424
425 const struct ComprOps *cops = NULL;
426#ifdef USE_HCACHE_COMPRESSION
427 const char *const c_header_cache_compress_method = cs_subset_string(NeoMutt->sub, "header_cache_compress_method");
428 if (c_header_cache_compress_method)
429 {
430 cops = compress_get_ops(c_header_cache_compress_method);
431
432 const short c_header_cache_compress_level = cs_subset_number(NeoMutt->sub, "header_cache_compress_level");
433 hc->cctx = cops->open(c_header_cache_compress_level);
434 if (!hc->cctx)
435 {
436 FREE(&hc);
437 return NULL;
438 }
439
440 /* remember the buffer of database backend */
441 mutt_debug(LL_DEBUG3, "Header cache will use %s compression\n", cops->name);
442 }
443#endif
444
445 hc->folder = get_foldername(folder);
446 hc->crc = HcacheVer;
447
448 if (!path || (path[0] == '\0'))
449 {
450 if (cops)
451 {
452 cops->close(&hc->cctx);
453 }
454
455 FREE(&hc->folder);
456 FREE(&hc);
457 return NULL;
458 }
459
460 struct Buffer *hcpath = buf_pool_get();
461 hcache_per_folder(hcpath, path, hc->folder, namer);
462
463 hc->ctx = ops->open(buf_string(hcpath));
464 if (!hc->ctx)
465 {
466 /* remove a possibly incompatible version */
467 if (unlink(buf_string(hcpath)) == 0)
468 {
469 hc->ctx = ops->open(buf_string(hcpath));
470 if (!hc->ctx)
471 {
472 if (cops)
473 {
474 cops->close(&hc->cctx);
475 }
476 FREE(&hc->folder);
477 FREE(&hc);
478 }
479 }
480 }
481
482 buf_pool_release(&hcpath);
483 return hc;
484}
485
490{
491 const char *const c_header_cache_backend = cs_subset_string(NeoMutt->sub, "header_cache_backend");
492 const struct StoreOps *ops = store_get_backend_ops(c_header_cache_backend);
493 if (!hc || !ops)
494 return;
495
496#ifdef USE_HCACHE_COMPRESSION
497 const char *const c_header_cache_compress_method = cs_subset_string(NeoMutt->sub, "header_cache_compress_method");
498 if (c_header_cache_compress_method)
499 {
500 const struct ComprOps *cops = compress_get_ops(c_header_cache_compress_method);
501 cops->close(&hc->cctx);
502 }
503#endif
504
505 ops->close(&hc->ctx);
506 FREE(&hc->folder);
507 FREE(&hc);
508}
509
513struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key,
514 size_t keylen, uint32_t uidvalidity)
515{
516 struct RealKey *rk = realkey(key, keylen);
517 struct HCacheEntry entry = { 0 };
518
519 size_t dlen;
520 void *data = fetch_raw(hc, rk->key, rk->len, &dlen);
521 void *to_free = data;
522 if (!data)
523 {
524 goto end;
525 }
526
527 /* restore uidvalidity and crc */
528 size_t hlen = header_size();
529 if (hlen > dlen)
530 {
531 goto end;
532 }
533 int off = 0;
534 serial_restore_uint32_t(&entry.uidvalidity, data, &off);
535 serial_restore_int(&entry.crc, data, &off);
536 assert((size_t) off == hlen);
537 if (entry.crc != hc->crc || ((uidvalidity != 0) && uidvalidity != entry.uidvalidity))
538 {
539 goto end;
540 }
541
542#ifdef USE_HCACHE_COMPRESSION
543 const char *const c_header_cache_compress_method = cs_subset_string(NeoMutt->sub, "header_cache_compress_method");
544 if (c_header_cache_compress_method)
545 {
546 const struct ComprOps *cops = compress_get_ops(c_header_cache_compress_method);
547
548 void *dblob = cops->decompress(hc->cctx, (char *) data + hlen, dlen - hlen);
549 if (!dblob)
550 {
551 goto end;
552 }
553 data = (char *) dblob - hlen; /* restore skips uidvalidity and crc */
554 }
555#endif
556
557 entry.email = restore_email(data);
558
559end:
560 free_raw(hc, &to_free);
561 return entry;
562}
563
574bool mutt_hcache_fetch_obj_(struct HeaderCache *hc, const char *key,
575 size_t keylen, void *dst, size_t dstlen)
576{
577 bool rc = true;
578 size_t srclen = 0;
579 void *src = fetch_raw(hc, key, keylen, &srclen);
580 if (src && srclen == dstlen)
581 {
582 memcpy(dst, src, dstlen);
583 }
584 else
585 {
586 rc = false;
587 }
588 free_raw(hc, &src);
589 return rc;
590}
591
600char *mutt_hcache_fetch_str(struct HeaderCache *hc, const char *key, size_t keylen)
601{
602 char *res = NULL;
603 size_t dlen = 0;
604 void *data = fetch_raw(hc, key, keylen, &dlen);
605 if (data)
606 {
607 res = mutt_strn_dup(data, dlen);
608 free_raw(hc, &data);
609 }
610 return res;
611}
612
616int mutt_hcache_store(struct HeaderCache *hc, const char *key, size_t keylen,
617 struct Email *e, uint32_t uidvalidity)
618{
619 if (!hc)
620 return -1;
621
622 int dlen = 0;
623 char *data = dump_email(hc, e, &dlen, uidvalidity);
624
625#ifdef USE_HCACHE_COMPRESSION
626 const char *const c_header_cache_compress_method = cs_subset_string(NeoMutt->sub, "header_cache_compress_method");
627 if (c_header_cache_compress_method)
628 {
629 /* We don't compress uidvalidity and the crc, so we can check them before
630 * decompressing on fetch(). */
631 size_t hlen = header_size();
632
633 const struct ComprOps *cops = compress_get_ops(c_header_cache_compress_method);
634
635 /* data / dlen gets ptr to compressed data here */
636 size_t clen = dlen;
637 void *cdata = cops->compress(hc->cctx, data + hlen, dlen - hlen, &clen);
638 if (!cdata)
639 {
640 FREE(&data);
641 return -1;
642 }
643
644 char *whole = mutt_mem_malloc(hlen + clen);
645 memcpy(whole, data, hlen);
646 memcpy(whole + hlen, cdata, clen);
647
648 FREE(&data);
649
650 data = whole;
651 dlen = hlen + clen;
652 }
653#endif
654
655 /* store uncompressed data */
656 struct RealKey *rk = realkey(key, keylen);
657 int rc = mutt_hcache_store_raw(hc, rk->key, rk->len, data, dlen);
658
659 FREE(&data);
660
661 return rc;
662}
663
674int mutt_hcache_store_raw(struct HeaderCache *hc, const char *key,
675 size_t keylen, void *data, size_t dlen)
676{
677 const char *const c_header_cache_backend = cs_subset_string(NeoMutt->sub, "header_cache_backend");
678 const struct StoreOps *ops = store_get_backend_ops(c_header_cache_backend);
679
680 if (!hc || !ops)
681 return -1;
682
683 struct Buffer path = buf_make(1024);
684
685 keylen = buf_printf(&path, "%s%.*s", hc->folder, (int) keylen, key);
686 int rc = ops->store(hc->ctx, buf_string(&path), keylen, data, dlen);
687 buf_dealloc(&path);
688
689 return rc;
690}
691
695int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
696{
697 if (!hc)
698 return -1;
699
700 const char *const c_header_cache_backend = cs_subset_string(NeoMutt->sub, "header_cache_backend");
701 const struct StoreOps *ops = store_get_backend_ops(c_header_cache_backend);
702 if (!ops)
703 return -1;
704
705 struct Buffer path = buf_make(1024);
706
707 keylen = buf_printf(&path, "%s%s", hc->folder, key);
708
709 int rc = ops->delete_record(hc->ctx, buf_string(&path), keylen);
710 buf_dealloc(&path);
711 return rc;
712}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:173
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:383
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:88
struct Buffer buf_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:70
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:478
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:90
const struct ComprOps * compress_get_ops(const char *compr)
Get the API functions for a compress backend.
Definition: compress.c:79
API for the header cache compression.
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
struct ReplaceList SpamList
List of regexes to match subscribed mailing lists.
Definition: globals.c:45
struct RegexList NoSpamList
List of regexes and patterns to match spam emails.
Definition: globals.c:43
Structs that make up an email.
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:43
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:952
#define mutt_error(...)
Definition: logging2.h:90
#define mutt_debug(LEVEL,...)
Definition: logging2.h:87
void(* hcache_namer_t)(const char *path, struct Buffer *dest)
Definition: lib.h:113
static struct RealKey * realkey(const char *key, size_t keylen)
Compute the real key used in the backend, taking into account the compression method.
Definition: hcache.c:193
static unsigned int HcacheVer
Header Cache version.
Definition: hcache.c:64
bool mutt_hcache_fetch_obj_(struct HeaderCache *hc, const char *key, size_t keylen, void *dst, size_t dstlen)
Fetch a message's header from the cache into a destination object.
Definition: hcache.c:574
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:616
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:489
static struct Email * restore_email(const unsigned char *d)
Restore an Email from data retrieved from the cache.
Definition: hcache.c:144
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:379
static bool create_hcache_dir(const char *path)
Create parent dirs for the hcache database.
Definition: hcache.c:219
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:695
static void free_raw(struct HeaderCache *hc, void **data)
Multiplexor for StoreOps::free.
Definition: hcache.c:365
int mutt_hcache_store_raw(struct HeaderCache *hc, const char *key, size_t keylen, void *data, size_t dlen)
Store a key / data pair.
Definition: hcache.c:674
static void * dump_email(struct HeaderCache *hc, const struct Email *e, int *off, uint32_t uidvalidity)
Serialise an Email object.
Definition: hcache.c:86
static void * fetch_raw(struct HeaderCache *hc, const char *key, size_t keylen, size_t *dlen)
Fetch a message's header from the cache.
Definition: hcache.c:344
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:513
char * mutt_hcache_fetch_str(struct HeaderCache *hc, const char *key, size_t keylen)
Fetch a string from the cache.
Definition: hcache.c:600
static size_t header_size(void)
Compute the size of the header with uuid validity and crc.
Definition: hcache.c:70
static void hcache_per_folder(struct Buffer *hcpath, const char *path, const char *folder, hcache_namer_t namer)
Generate the hcache pathname.
Definition: hcache.c:263
static char * get_foldername(const char *folder)
Where should the cache be stored?
Definition: hcache.c:321
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
void * mutt_md5(const char *str, void *buf)
Calculate the MD5 hash of a NULL-terminated string.
Definition: md5.c:317
void mutt_md5_process_bytes(const void *buf, size_t buflen, struct Md5Ctx *md5ctx)
Process a block of data.
Definition: md5.c:373
void mutt_md5_process(const char *str, struct Md5Ctx *md5ctx)
Process a NULL-terminated string.
Definition: md5.c:355
void mutt_md5_init_ctx(struct Md5Ctx *md5ctx)
Initialise the MD5 computation.
Definition: md5.c:261
void * mutt_md5_finish_ctx(struct Md5Ctx *md5ctx, void *resbuf)
Process the remaining bytes in the buffer.
Definition: md5.c:285
void mutt_md5_toascii(const void *digest, char *resbuf)
Convert a binary MD5 digest into ASCII Hexadecimal.
Definition: md5.c:456
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:43
bool CharsetIsUtf8
Is the user's current character set utf-8?
Definition: charset.c:59
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:446
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:452
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:568
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
#define PATH_MAX
Definition: mutt.h:41
void mutt_encode_path(struct Buffer *buf, const char *src)
Convert a path to 'us-ascii'.
Definition: muttlib.c:1453
Some miscellaneous functions.
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
#define STAILQ_INIT(head)
Definition: queue.h:372
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
void serial_restore_tags(struct TagList *tags, const unsigned char *d, int *off)
Unpack a TagList from a binary blob.
Definition: serialize.c:624
void serial_restore_envelope(struct Envelope *env, const unsigned char *d, int *off, bool convert)
Unpack an Envelope from a binary blob.
Definition: serialize.c:543
unsigned char * serial_dump_uint32_t(uint32_t s, unsigned char *d, int *off)
Pack a uint32_t into a binary blob.
Definition: serialize.c:84
unsigned char * serial_dump_int(unsigned int i, unsigned char *d, int *off)
Pack an integer into a binary blob.
Definition: serialize.c:68
void lazy_realloc(void *ptr, size_t size)
Reallocate some memory.
Definition: serialize.c:51
unsigned char * serial_dump_envelope(struct Envelope *env, unsigned char *d, int *off, bool convert)
Pack an Envelope into a binary blob.
Definition: serialize.c:493
unsigned char * serial_dump_body(struct Body *c, unsigned char *d, int *off, bool convert)
Pack an Body into a binary blob.
Definition: serialize.c:427
void serial_restore_body(struct Body *c, const unsigned char *d, int *off, bool convert)
Unpack a Body from a binary blob.
Definition: serialize.c:467
void serial_restore_int(unsigned int *i, const unsigned char *d, int *off)
Unpack an integer from a binary blob.
Definition: serialize.c:99
unsigned char * serial_dump_tags(const struct TagList *tags, unsigned char *d, int *off)
Pack a TagList into a binary blob.
Definition: serialize.c:599
void serial_restore_uint32_t(uint32_t *s, const unsigned char *d, int *off)
Unpack an uint32_t from a binary blob.
Definition: serialize.c:111
Email-object serialiser.
Key value store.
const struct StoreOps * store_get_backend_ops(const char *str)
Get the API functions for an store backend.
Definition: store.c:106
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
Definition: lib.h:60
void(* close)(void **cctx)
Definition: lib.h:119
void *(* open)(short level)
Definition: lib.h:74
void *(* decompress)(void *cctx, const char *cbuf, size_t clen)
Definition: lib.h:107
void *(* compress)(void *cctx, const char *data, size_t dlen, size_t *clen)
Definition: lib.h:91
const char * name
Compression name.
Definition: lib.h:61
The envelope/body of an email.
Definition: email.h:37
bool searched
Email has been searched.
Definition: email.h:104
bool matched
Search matches this Email.
Definition: email.h:101
bool visible
Is this message part of the view?
Definition: email.h:120
bool recip_valid
Is_recipient is valid.
Definition: email.h:103
bool attach_valid
true when the attachment count is valid
Definition: email.h:99
struct Envelope * env
Envelope information.
Definition: email.h:66
void * edata
Driver-specific data.
Definition: email.h:72
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:119
struct Body * body
List of MIME parts.
Definition: email.h:67
char * tree
Character string to print thread tree.
Definition: email.h:124
size_t num_hidden
Number of hidden messages in this view (only valid when collapsed is set)
Definition: email.h:122
struct AttrColor * attr_color
Color-pair to use when displaying in the index.
Definition: email.h:111
bool changed
Email has been edited.
Definition: email.h:75
bool threaded
Used for threading.
Definition: email.h:107
struct ListHead chain
Mixmaster chain.
Definition: email.h:89
struct TagList tags
For drivers that support server tagging.
Definition: email.h:70
struct Notify * notify
Notifications: NotifyEmail, EventEmail.
Definition: email.h:71
char * path
Path of Email (for local Mailboxes)
Definition: email.h:68
size_t sequence
Sequence number assigned on creation.
Definition: email.h:65
short recipient
User_is_recipient()'s return value, cached.
Definition: email.h:115
bool tagged
Email is tagged.
Definition: email.h:106
struct MuttThread * thread
Thread of Emails.
Definition: email.h:118
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
unsigned int crc
CRC of Email/Body/etc structs.
Definition: lib.h:101
Header cache structure.
Definition: lib.h:88
void * ctx
Store context (handle)
Definition: lib.h:91
unsigned int crc
CRC of the cache entry.
Definition: lib.h:90
char * folder
Folder name.
Definition: lib.h:89
void * cctx
Compression context (handle)
Definition: lib.h:92
Cursor for the MD5 hashing.
Definition: md5.h:37
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Notification API.
Definition: notify.c:51
Hcache key name (including compression method)
Definition: hcache.c:182
char key[1024]
Key name.
Definition: hcache.c:183
size_t len
Length of key.
Definition: hcache.c:184
List of regular expressions.
Definition: regex3.h:99
struct Regex * regex
Regex containing a regular expression.
Definition: regex3.h:100
char * pattern
printable version
Definition: regex3.h:90
List of regular expressions.
Definition: regex3.h:109
char * templ
Template to match.
Definition: regex3.h:112
struct Regex * regex
Regex containing a regular expression.
Definition: regex3.h:110
Definition: lib.h:66
void *(* fetch)(void *store, const char *key, size_t klen, size_t *vlen)
Definition: lib.h:96
void(* free)(void *store, void **ptr)
Definition: lib.h:106
int(* delete_record)(void *store, const char *key, size_t klen)
Definition: lib.h:134
const char * name
Store name.
Definition: lib.h:67
int(* store)(void *store, const char *key, size_t klen, void *value, size_t vlen)
Definition: lib.h:121
void *(* open)(const char *path)
Definition: lib.h:82
void(* close)(void **ptr)
Definition: lib.h:143