NeoMutt  2024-04-25-1-g3de005
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
hcache.c
Go to the documentation of this file.
1
33#include "config.h"
34#include <assert.h>
35#include <errno.h>
36#include <limits.h>
37#include <stdbool.h>
38#include <stdint.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <sys/stat.h>
43#include <unistd.h>
44#include "mutt/lib.h"
45#include "config/lib.h"
46#include "email/lib.h"
47#include "core/lib.h"
48#include "lib.h"
49#include "compress/lib.h"
50#include "store/lib.h"
51#include "hcache/hcversion.h" // path needed by out-of-tree build
52#include "muttlib.h"
53#include "serialize.h"
54
55#if !(defined(HAVE_BDB) || defined(HAVE_GDBM) || defined(HAVE_KC) || \
56 defined(HAVE_LMDB) || defined(HAVE_QDBM) || defined(HAVE_ROCKSDB) || \
57 defined(HAVE_TC) || defined(HAVE_TDB))
58#error "No hcache backend defined"
59#endif
60
62static unsigned int HcacheVer = 0x0;
63
67struct RealKey
68{
69 char key[1024];
70 size_t keylen;
71};
72
81static struct RealKey *realkey(struct HeaderCache *hc, const char *key,
82 size_t keylen, bool compress)
83{
84 static struct RealKey rk;
85
86 rk.keylen = snprintf(rk.key, sizeof(rk.key), "%s/%.*s", hc->folder, (int) keylen, key);
87
88#ifdef USE_HCACHE_COMPRESSION
89 if (compress && hc->compr_ops)
90 {
91 // Append the compression type, e.g. "-zstd"
92 rk.keylen += snprintf(rk.key + rk.keylen, sizeof(rk.key) - rk.keylen, "-%s",
93 hc->compr_ops->name);
94 }
95#endif
96
97 return &rk;
98}
99
104static void hcache_free(struct HeaderCache **ptr)
105{
106 if (!ptr || !*ptr)
107 return;
108
109 struct HeaderCache *hc = *ptr;
110 FREE(&hc->folder);
111
112 FREE(ptr);
113}
114
119static struct HeaderCache *hcache_new(void)
120{
121 return mutt_mem_calloc(1, sizeof(struct HeaderCache));
122}
123
128static size_t header_size(void)
129{
130 return sizeof(int) + sizeof(uint32_t);
131}
132
140static inline uint32_t email_pack_flags(const struct Email *e)
141{
142 if (!e)
143 return 0;
144
145 // clang-format off
146 return e->security +
147 (e->expired << 16) +
148 (e->flagged << 17) +
149 (e->mime << 18) +
150 (e->old << 19) +
151 (e->read << 20) +
152 (e->replied << 21) +
153 (e->superseded << 22) +
154 (e->trash << 23);
155 // clang-format on
156}
157
165static inline void email_unpack_flags(struct Email *e, uint32_t packed)
166{
167 if (!e)
168 return;
169
170 // clang-format off
171 e->security = (packed & ((1 << 16) - 1)); // bits 0-15
172 e->expired = (packed & (1 << 16));
173 e->flagged = (packed & (1 << 17));
174 e->mime = (packed & (1 << 18));
175 e->old = (packed & (1 << 19));
176 e->read = (packed & (1 << 20));
177 e->replied = (packed & (1 << 21));
178 e->superseded = (packed & (1 << 22));
179 e->trash = (packed & (1 << 23));
180 // clang-format on
181}
182
190static inline uint32_t email_pack_timezone(const struct Email *e)
191{
192 if (!e)
193 return 0;
194
195 return e->zhours + (e->zminutes << 5) + (e->zoccident << 11);
196}
197
205static inline void email_unpack_timezone(struct Email *e, uint32_t packed)
206{
207 if (!e)
208 return;
209
210 // clang-format off
211 e->zhours = (packed & ((1 << 5) - 1)); // bits 0-4 (5)
212 e->zminutes = ((packed >> 5) & ((1 << 6) - 1)); // bits 5-10 (6)
213 e->zoccident = (packed & (1 << 11)); // bit 11 (1)
214 // clang-format on
215}
216
228static void *dump_email(struct HeaderCache *hc, const struct Email *e, int *off, uint32_t uidvalidity)
229{
230 bool convert = !CharsetIsUtf8;
231
232 *off = 0;
233 unsigned char *d = mutt_mem_malloc(4096);
234
235 d = serial_dump_uint32_t((uidvalidity != 0) ? uidvalidity : mutt_date_now(), d, off);
236 d = serial_dump_int(hc->crc, d, off);
237
238 assert((size_t) *off == header_size());
239
240 uint32_t packed = email_pack_flags(e);
241 d = serial_dump_uint32_t(packed, d, off);
242
243 packed = email_pack_timezone(e);
244 d = serial_dump_uint32_t(packed, d, off);
245
246 uint64_t big = e->date_sent;
247 d = serial_dump_uint64_t(big, d, off);
248 big = e->received;
249 d = serial_dump_uint64_t(big, d, off);
250
251 d = serial_dump_int(e->lines, d, off);
252
253 d = serial_dump_envelope(e->env, d, off, convert);
254 d = serial_dump_body(e->body, d, off, convert);
255 d = serial_dump_tags(&e->tags, d, off);
256
257 return d;
258}
259
268static struct Email *restore_email(const unsigned char *d)
269{
270 int off = 0;
271 struct Email *e = email_new();
272 bool convert = !CharsetIsUtf8;
273
274 off += sizeof(uint32_t); // skip validate
275 off += sizeof(unsigned int); // skip crc
276
277 uint32_t packed = 0;
278 serial_restore_uint32_t(&packed, d, &off);
279 email_unpack_flags(e, packed);
280
281 packed = 0;
282 serial_restore_uint32_t(&packed, d, &off);
283 email_unpack_timezone(e, packed);
284
285 uint64_t big = 0;
286 serial_restore_uint64_t(&big, d, &off);
287 e->date_sent = big;
288
289 big = 0;
290 serial_restore_uint64_t(&big, d, &off);
291 e->received = big;
292
293 unsigned int num = 0;
294 serial_restore_int(&num, d, &off);
295 e->lines = num;
296
297 e->env = mutt_env_new();
298 serial_restore_envelope(e->env, d, &off, convert);
299
300 e->body = mutt_body_new();
301 serial_restore_body(e->body, d, &off, convert);
302 serial_restore_tags(&e->tags, d, &off);
303
304 return e;
305}
306
313static bool create_hcache_dir(const char *path)
314{
315 char *dir = mutt_str_dup(path);
316 if (!dir)
317 return false;
318
319 char *p = strrchr(dir, '/');
320 if (!p)
321 {
322 FREE(&dir);
323 return true;
324 }
325
326 *p = '\0';
327
328 int rc = mutt_file_mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO);
329 if (rc != 0)
330 mutt_error(_("Can't create %s: %s"), dir, strerror(errno));
331
332 FREE(&dir);
333 return (rc == 0);
334}
335
357static void hcache_per_folder(struct HeaderCache *hc, struct Buffer *hcpath,
358 const char *path, hcache_namer_t namer)
359{
360 struct stat st = { 0 };
361
362 int plen = mutt_str_len(path);
363 int rc = stat(path, &st);
364 bool slash = (path[plen - 1] == '/');
365
366 if (((rc == 0) && !S_ISDIR(st.st_mode)) || ((rc == -1) && !slash))
367 {
368 /* An existing file or a non-existing path not ending with a slash */
369 mutt_encode_path(hcpath, path);
371 return;
372 }
373
374 /* We have a directory - no matter whether it exists, or not */
375 struct Buffer *hcfile = buf_pool_get();
376 if (namer)
377 {
378 namer(hc->folder, hcfile);
379 mutt_encode_path(hcfile, buf_string(hcfile));
380 buf_concat_path(hcpath, path, buf_string(hcfile));
381 }
382 else
383 {
384 unsigned char m[16]; /* binary md5sum */
385 struct Buffer *name = buf_pool_get();
386
387#ifdef USE_HCACHE_COMPRESSION
388 const char *cm = hc->compr_ops ? hc->compr_ops->name : "";
389 buf_printf(name, "%s|%s%s", hc->store_ops->name, hc->folder, cm);
390#else
391 buf_printf(name, "%s|%s", hc->store_ops->name, hc->folder);
392#endif
393 mutt_md5(buf_string(name), m);
394 buf_reset(name);
395 mutt_md5_toascii(m, name->data);
396 mutt_encode_path(name, buf_string(name));
397 buf_printf(hcpath, "%s%s%s", path, slash ? "" : "/", buf_string(name));
398 buf_pool_release(&name);
399 }
400
402 buf_pool_release(&hcfile);
403}
404
410static char *get_foldername(const char *folder)
411{
412 /* if the folder is local, canonify the path to ensure equivalent paths share
413 * the hcache */
414 char *p = mutt_mem_malloc(PATH_MAX + 1);
415 if (!realpath(folder, p))
416 mutt_str_replace(&p, folder);
417
418 return p;
419}
420
424static void free_raw(struct HeaderCache *hc, void **data)
425{
426 hc->store_ops->free(hc->store_handle, data);
427}
428
433static unsigned int generate_hcachever(void)
434{
435 union
436 {
437 unsigned char charval[16];
438 unsigned int intval;
439 } digest;
440 struct Md5Ctx md5ctx = { 0 };
441
442 mutt_md5_init_ctx(&md5ctx);
443
444 /* Seed with the compiled-in header structure hash */
445 unsigned int ver = HCACHEVER;
446 mutt_md5_process_bytes(&ver, sizeof(ver), &md5ctx);
447
448 /* Mix in user's spam list */
449 struct Replace *sp = NULL;
450 STAILQ_FOREACH(sp, &SpamList, entries)
451 {
452 mutt_md5_process(sp->regex->pattern, &md5ctx);
453 mutt_md5_process(sp->templ, &md5ctx);
454 }
455
456 /* Mix in user's nospam list */
457 struct RegexNode *np = NULL;
458 STAILQ_FOREACH(np, &NoSpamList, entries)
459 {
460 mutt_md5_process(np->regex->pattern, &md5ctx);
461 }
462
463 /* Get a hash and take its bytes as an (unsigned int) hash version */
464 mutt_md5_finish_ctx(&md5ctx, digest.charval);
465
466 return digest.intval;
467}
468
472struct HeaderCache *hcache_open(const char *path, const char *folder, hcache_namer_t namer)
473{
474 if (!path || (path[0] == '\0'))
475 return NULL;
476
477 if (HcacheVer == 0x0)
479
480 struct HeaderCache *hc = hcache_new();
481
483 hc->crc = HcacheVer;
484
485 const char *const c_header_cache_backend = cs_subset_string(NeoMutt->sub, "header_cache_backend");
486 hc->store_ops = store_get_backend_ops(c_header_cache_backend);
487 if (!hc->store_ops)
488 {
489 hcache_free(&hc);
490 return NULL;
491 }
492
493#ifdef USE_HCACHE_COMPRESSION
494 const char *const c_header_cache_compress_method = cs_subset_string(NeoMutt->sub, "header_cache_compress_method");
495 if (c_header_cache_compress_method)
496 {
497 hc->compr_ops = compress_get_ops(c_header_cache_compress_method);
498
499 const short c_header_cache_compress_level = cs_subset_number(NeoMutt->sub, "header_cache_compress_level");
500 hc->compr_handle = hc->compr_ops->open(c_header_cache_compress_level);
501 if (!hc->compr_handle)
502 {
503 hcache_free(&hc);
504 return NULL;
505 }
506
507 /* remember the buffer of database backend */
508 mutt_debug(LL_DEBUG3, "Header cache will use %s compression\n",
509 hc->compr_ops->name);
510 }
511#endif
512
513 struct Buffer *hcpath = buf_pool_get();
514 hcache_per_folder(hc, hcpath, path, namer);
515
516 hc->store_handle = hc->store_ops->open(buf_string(hcpath));
517 if (!hc->store_handle)
518 {
519 /* remove a possibly incompatible version */
520 if (unlink(buf_string(hcpath)) == 0)
521 {
522 hc->store_handle = hc->store_ops->open(buf_string(hcpath));
523 if (!hc->store_handle)
524 {
525 if (hc->compr_ops)
526 {
527 hc->compr_ops->close(&hc->compr_handle);
528 }
529 hcache_free(&hc);
530 }
531 }
532 }
533
534 buf_pool_release(&hcpath);
535 return hc;
536}
537
541void hcache_close(struct HeaderCache **ptr)
542{
543 if (!ptr || !*ptr)
544 return;
545
546 struct HeaderCache *hc = *ptr;
547
548#ifdef USE_HCACHE_COMPRESSION
549 if (hc->compr_ops)
550 hc->compr_ops->close(&hc->compr_handle);
551#endif
552
553 hc->store_ops->close(&hc->store_handle);
554
555 hcache_free(ptr);
556}
557
561struct HCacheEntry hcache_fetch_email(struct HeaderCache *hc, const char *key,
562 size_t keylen, uint32_t uidvalidity)
563{
564 struct HCacheEntry hce = { 0 };
565 if (!hc)
566 return hce;
567
568 size_t dlen = 0;
569 struct RealKey *rk = realkey(hc, key, keylen, true);
570 void *data = hc->store_ops->fetch(hc->store_handle, rk->key, rk->keylen, &dlen);
571 void *to_free = data;
572 if (!data)
573 {
574 goto end;
575 }
576
577 /* restore uidvalidity and crc */
578 size_t hlen = header_size();
579 if (hlen > dlen)
580 {
581 goto end;
582 }
583 int off = 0;
584 serial_restore_uint32_t(&hce.uidvalidity, data, &off);
585 serial_restore_int(&hce.crc, data, &off);
586 assert((size_t) off == hlen);
587 if ((hce.crc != hc->crc) || ((uidvalidity != 0) && (uidvalidity != hce.uidvalidity)))
588 {
589 goto end;
590 }
591
592#ifdef USE_HCACHE_COMPRESSION
593 if (hc->compr_ops)
594 {
595 void *dblob = hc->compr_ops->decompress(hc->compr_handle,
596 (char *) data + hlen, dlen - hlen);
597 if (!dblob)
598 {
599 goto end;
600 }
601 data = (char *) dblob - hlen; /* restore skips uidvalidity and crc */
602 }
603#endif
604
605 hce.email = restore_email(data);
606
607end:
608 free_raw(hc, &to_free);
609 return hce;
610}
611
622bool hcache_fetch_raw_obj_full(struct HeaderCache *hc, const char *key,
623 size_t keylen, void *dst, size_t dstlen)
624{
625 bool rc = true;
626 size_t srclen = 0;
627
628 struct RealKey *rk = realkey(hc, key, keylen, false);
629 void *src = hc->store_ops->fetch(hc->store_handle, rk->key, rk->keylen, &srclen);
630
631 if (src && (srclen == dstlen))
632 {
633 memcpy(dst, src, dstlen);
634 }
635 else
636 {
637 rc = false;
638 }
639 free_raw(hc, &src);
640 return rc;
641}
642
651char *hcache_fetch_raw_str(struct HeaderCache *hc, const char *key, size_t keylen)
652{
653 char *res = NULL;
654 size_t dlen = 0;
655
656 struct RealKey *rk = realkey(hc, key, keylen, false);
657 void *data = hc->store_ops->fetch(hc->store_handle, rk->key, rk->keylen, &dlen);
658 if (data)
659 {
660 res = mutt_strn_dup(data, dlen);
661 free_raw(hc, &data);
662 }
663 return res;
664}
665
669int hcache_store_email(struct HeaderCache *hc, const char *key, size_t keylen,
670 struct Email *e, uint32_t uidvalidity)
671{
672 if (!hc)
673 return -1;
674
675 int dlen = 0;
676 char *data = dump_email(hc, e, &dlen, uidvalidity);
677
678#ifdef USE_HCACHE_COMPRESSION
679 if (hc->compr_ops)
680 {
681 /* We don't compress uidvalidity and the crc, so we can check them before
682 * decompressing on fetch(). */
683 size_t hlen = header_size();
684
685 /* data / dlen gets ptr to compressed data here */
686 size_t clen = dlen;
687 void *cdata = hc->compr_ops->compress(hc->compr_handle, data + hlen, dlen - hlen, &clen);
688 if (!cdata)
689 {
690 FREE(&data);
691 return -1;
692 }
693
694 char *whole = mutt_mem_malloc(hlen + clen);
695 memcpy(whole, data, hlen);
696 memcpy(whole + hlen, cdata, clen);
697
698 FREE(&data);
699
700 data = whole;
701 dlen = hlen + clen;
702 }
703#endif
704
705 struct RealKey *rk = realkey(hc, key, keylen, true);
706 int rc = hc->store_ops->store(hc->store_handle, rk->key, rk->keylen, data, dlen);
707
708 FREE(&data);
709
710 return rc;
711}
712
723int hcache_store_raw(struct HeaderCache *hc, const char *key, size_t keylen,
724 void *data, size_t dlen)
725{
726 if (!hc)
727 return -1;
728
729 struct RealKey *rk = realkey(hc, key, keylen, false);
730 int rc = hc->store_ops->store(hc->store_handle, rk->key, rk->keylen, data, dlen);
731
732 return rc;
733}
734
738int hcache_delete_email(struct HeaderCache *hc, const char *key, size_t keylen)
739{
740 if (!hc)
741 return -1;
742
743 struct RealKey *rk = realkey(hc, key, keylen, true);
744
745 return hc->store_ops->delete_record(hc->store_handle, rk->key, rk->keylen);
746}
747
751int hcache_delete_raw(struct HeaderCache *hc, const char *key, size_t keylen)
752{
753 if (!hc)
754 return -1;
755
756 struct RealKey *rk = realkey(hc, key, keylen, false);
757
758 return hc->store_ops->delete_record(hc->store_handle, rk->key, rk->keylen);
759}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:75
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:508
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
const struct ComprOps * compress_get_ops(const char *compr)
Get the API functions for a compress backend.
Definition: compress.c:81
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:292
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:144
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:44
struct Email * email_new(void)
Create a new Email.
Definition: email.c:80
struct ReplaceList SpamList
List of regexes to match subscribed mailing lists.
Definition: globals.c:46
struct RegexList NoSpamList
List of regexes and patterns to match spam emails.
Definition: globals.c:44
Structs that make up an email.
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:46
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:971
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
static unsigned int HcacheVer
Header Cache version.
Definition: hcache.c:62
static struct Email * restore_email(const unsigned char *d)
Restore an Email from data retrieved from the cache.
Definition: hcache.c:268
static void hcache_free(struct HeaderCache **ptr)
Free a header cache.
Definition: hcache.c:104
static struct HeaderCache * hcache_new(void)
Create a new header cache.
Definition: hcache.c:119
static void email_unpack_flags(struct Email *e, uint32_t packed)
Unpack the Email flags from a uint32_t.
Definition: hcache.c:165
static bool create_hcache_dir(const char *path)
Create parent dirs for the hcache database.
Definition: hcache.c:313
struct HeaderCache * hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:472
static void email_unpack_timezone(struct Email *e, uint32_t packed)
Unpack the Email timezone from a uint32_t.
Definition: hcache.c:205
int hcache_delete_email(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:738
void hcache_close(struct HeaderCache **ptr)
Multiplexor for StoreOps::close.
Definition: hcache.c:541
static void free_raw(struct HeaderCache *hc, void **data)
Multiplexor for StoreOps::free.
Definition: hcache.c:424
static void * dump_email(struct HeaderCache *hc, const struct Email *e, int *off, uint32_t uidvalidity)
Serialise an Email object.
Definition: hcache.c:228
struct HCacheEntry hcache_fetch_email(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:561
static uint32_t email_pack_flags(const struct Email *e)
Pack the Email flags into a uint32_t.
Definition: hcache.c:140
static unsigned int generate_hcachever(void)
Calculate hcache version from dynamic configuration.
Definition: hcache.c:433
static uint32_t email_pack_timezone(const struct Email *e)
Pack the Email timezone into a uint32_t.
Definition: hcache.c:190
int hcache_store_email(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition: hcache.c:669
char * hcache_fetch_raw_str(struct HeaderCache *hc, const char *key, size_t keylen)
Fetch a string from the cache.
Definition: hcache.c:651
bool hcache_fetch_raw_obj_full(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:622
int hcache_delete_raw(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:751
static struct RealKey * realkey(struct HeaderCache *hc, const char *key, size_t keylen, bool compress)
Compute the real key used in the backend, taking into account the compression method.
Definition: hcache.c:81
static size_t header_size(void)
Compute the size of the header with uuid validity and crc.
Definition: hcache.c:128
int 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:723
static void hcache_per_folder(struct HeaderCache *hc, struct Buffer *hcpath, const char *path, hcache_namer_t namer)
Generate the hcache pathname.
Definition: hcache.c:357
static char * get_foldername(const char *folder)
Where should the cache be stored?
Definition: hcache.c:410
void(* hcache_namer_t)(const char *path, struct Buffer *dest)
Definition: lib.h:113
@ 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:45
bool CharsetIsUtf8
Is the user's current character set utf-8?
Definition: charset.c:66
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:455
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:374
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:490
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:274
#define PATH_MAX
Definition: mutt.h:42
void mutt_encode_path(struct Buffer *buf, const char *src)
Convert a path to 'us-ascii'.
Definition: muttlib.c:907
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_FOREACH(var, head, field)
Definition: queue.h:352
unsigned char * serial_dump_body(const struct Body *b, unsigned char *d, int *off, bool convert)
Pack an Body into a binary blob.
Definition: serialize.c:519
unsigned char * serial_dump_tags(const struct TagList *tl, unsigned char *d, int *off)
Pack a TagList into a binary blob.
Definition: serialize.c:686
void serial_restore_tags(struct TagList *tl, const unsigned char *d, int *off)
Unpack a TagList from a binary blob.
Definition: serialize.c:711
unsigned char * serial_dump_uint64_t(const uint64_t s, unsigned char *d, int *off)
Pack a uint64_t into a binary blob.
Definition: serialize.c:99
unsigned char * serial_dump_int(const unsigned int i, unsigned char *d, int *off)
Pack an integer into a binary blob.
Definition: serialize.c:67
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:632
unsigned char * serial_dump_envelope(const struct Envelope *env, unsigned char *d, int *off, bool convert)
Pack an Envelope into a binary blob.
Definition: serialize.c:584
void serial_restore_uint64_t(uint64_t *s, const unsigned char *d, int *off)
Unpack an uint64_t from a binary blob.
Definition: serialize.c:138
void serial_restore_body(struct Body *b, const unsigned char *d, int *off, bool convert)
Unpack a Body from a binary blob.
Definition: serialize.c:550
unsigned char * serial_dump_uint32_t(const uint32_t s, unsigned char *d, int *off)
Pack a uint32_t into a binary blob.
Definition: serialize.c:83
void serial_restore_int(unsigned int *i, const unsigned char *d, int *off)
Unpack an integer from a binary blob.
Definition: serialize.c:114
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:126
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:107
String manipulation buffer.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:37
ComprHandle *(* open)(short level)
Definition: lib.h:78
const char * name
Compression name.
Definition: lib.h:65
void *(* compress)(ComprHandle *handle, const char *data, size_t dlen, size_t *clen)
Definition: lib.h:95
void(* close)(ComprHandle **ptr)
Definition: lib.h:123
The envelope/body of an email.
Definition: email.h:39
bool read
Email is read.
Definition: email.h:50
unsigned int zminutes
Minutes away from UTC.
Definition: email.h:57
struct Envelope * env
Envelope information.
Definition: email.h:68
bool mime
Has a MIME-Version header?
Definition: email.h:48
int lines
How many lines in the body of this message?
Definition: email.h:62
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:43
struct Body * body
List of MIME parts.
Definition: email.h:69
bool old
Email is seen, but unread.
Definition: email.h:49
bool zoccident
True, if west of UTC, False if east.
Definition: email.h:58
bool flagged
Marked important?
Definition: email.h:47
unsigned int zhours
Hours away from UTC.
Definition: email.h:56
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:60
bool replied
Email has been replied to.
Definition: email.h:51
bool expired
Already expired?
Definition: email.h:46
struct TagList tags
For drivers that support server tagging.
Definition: email.h:72
char * path
Path of Email (for local Mailboxes)
Definition: email.h:70
bool trash
Message is marked as trashed on disk (used by the maildir_trash option)
Definition: email.h:53
bool superseded
Got superseded?
Definition: email.h:52
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:61
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.
Definition: lib.h:86
ComprHandle * compr_handle
Compression handle.
Definition: lib.h:92
unsigned int crc
CRC of the cache entry.
Definition: lib.h:88
char * folder
Folder name.
Definition: lib.h:87
const struct StoreOps * store_ops
Store backend.
Definition: lib.h:89
StoreHandle * store_handle
Store handle.
Definition: lib.h:90
const struct ComprOps * compr_ops
Compression backend.
Definition: lib.h:91
Cursor for the MD5 hashing.
Definition: md5.h:37
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
Hcache key name (including compression method)
Definition: hcache.c:68
char key[1024]
Key name.
Definition: hcache.c:69
size_t keylen
Length of key.
Definition: hcache.c:70
List of regular expressions.
Definition: regex3.h:95
struct Regex * regex
Regex containing a regular expression.
Definition: regex3.h:96
char * pattern
printable version
Definition: regex3.h:86
List of regular expressions.
Definition: regex3.h:105
char * templ
Template to match.
Definition: regex3.h:108
struct Regex * regex
Regex containing a regular expression.
Definition: regex3.h:106
StoreHandle *(* open)(const char *path)
Definition: lib.h:85
void(* close)(StoreHandle **ptr)
Definition: lib.h:146
int(* store)(StoreHandle *store, const char *key, size_t klen, void *value, size_t vlen)
Definition: lib.h:124
const char * name
Store name.
Definition: lib.h:70
int(* delete_record)(StoreHandle *store, const char *key, size_t klen)
Definition: lib.h:137
void *(* fetch)(StoreHandle *store, const char *key, size_t klen, size_t *vlen)
Definition: lib.h:99
void(* free)(StoreHandle *store, void **ptr)
Definition: lib.h:109