NeoMutt  2023-03-22-27-g3cb248
Teaching an old dog new tricks
DOXYGEN
lib.h File Reference

Header cache multiplexor. More...

#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
+ Include dependency graph for lib.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  HeaderCache
 Header cache structure. More...
 
struct  HCacheEntry
 Wrapper for Email retrieved from the header cache. More...
 

Macros

#define mutt_hcache_fetch_obj(hc, key, keylen, dst)   mutt_hcache_fetch_obj_(hc, key, keylen, dst, sizeof(*dst))
 

Typedefs

typedef void(* hcache_namer_t) (const char *path, struct Buffer *dest)
 

Functions

struct HeaderCachemutt_hcache_open (const char *path, const char *folder, hcache_namer_t namer)
 Open the connection to the header cache. More...
 
void mutt_hcache_close (struct HeaderCache *hc)
 Close the connection to the header cache. More...
 
int mutt_hcache_store (struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
 Store a Header along with a validity datum. More...
 
struct HCacheEntry mutt_hcache_fetch (struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
 Fetch and validate a message's header from the cache. More...
 
char * mutt_hcache_fetch_str (struct HeaderCache *hc, const char *key, size_t keylen)
 Fetch a string from the cache. More...
 
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. More...
 
int mutt_hcache_store_raw (struct HeaderCache *hc, const char *key, size_t keylen, void *data, size_t dlen)
 Store a key / data pair. More...
 
int mutt_hcache_delete_record (struct HeaderCache *hc, const char *key, size_t keylen)
 Delete a key / data pair. More...
 

Detailed Description

Header cache multiplexor.

Authors
  • Thomas Glanzmann
  • Tobias Werth
  • Brian Fundakowski Feldman
  • Pietro Cerutti
  • Tino Reichardt

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file lib.h.

Macro Definition Documentation

◆ mutt_hcache_fetch_obj

#define mutt_hcache_fetch_obj (   hc,
  key,
  keylen,
  dst 
)    mutt_hcache_fetch_obj_(hc, key, keylen, dst, sizeof(*dst))

Definition at line 160 of file lib.h.

Typedef Documentation

◆ hcache_namer_t

typedef void(* hcache_namer_t) (const char *path, struct Buffer *dest)

Definition at line 113 of file lib.h.

Function Documentation

◆ mutt_hcache_open()

struct HeaderCache * mutt_hcache_open ( const char *  path,
const char *  folder,
hcache_namer_t  namer 
)

Open the connection to the header cache.

Parameters
pathLocation of the header cache (often as specified by the user)
folderName of the folder containing the messages
namerOptional (might be NULL) client-specific function to form the final name of the hcache database file.
Return values
ptrSuccess, struct HeaderCache struct
NULLOtherwise

Open the connection to the header cache.

< MD5 digest as a string

< MD5 digest as an integer

Definition at line 373 of file hcache.c.

374{
375 const char *const c_header_cache_backend = cs_subset_string(NeoMutt->sub, "header_cache_backend");
376 const struct StoreOps *ops = store_get_backend_ops(c_header_cache_backend);
377 if (!ops)
378 return NULL;
379
380 struct HeaderCache *hc = mutt_mem_calloc(1, sizeof(struct HeaderCache));
381
382 /* Calculate the current hcache version from dynamic configuration */
383 if (hcachever == 0x0)
384 {
385 union
386 {
387 unsigned char charval[16];
388 unsigned int intval;
389 } digest;
390 struct Md5Ctx md5ctx;
391
392 hcachever = HCACHEVER;
393
394 mutt_md5_init_ctx(&md5ctx);
395
396 /* Seed with the compiled-in header structure hash */
397 mutt_md5_process_bytes(&hcachever, sizeof(hcachever), &md5ctx);
398
399 /* Mix in user's spam list */
400 struct Replace *sp = NULL;
401 STAILQ_FOREACH(sp, &SpamList, entries)
402 {
403 mutt_md5_process(sp->regex->pattern, &md5ctx);
404 mutt_md5_process(sp->templ, &md5ctx);
405 }
406
407 /* Mix in user's nospam list */
408 struct RegexNode *np = NULL;
409 STAILQ_FOREACH(np, &NoSpamList, entries)
410 {
411 mutt_md5_process(np->regex->pattern, &md5ctx);
412 }
413
414 /* Get a hash and take its bytes as an (unsigned int) hash version */
415 mutt_md5_finish_ctx(&md5ctx, digest.charval);
416 hcachever = digest.intval;
417 }
418
419 const struct ComprOps *cops = NULL;
420#ifdef USE_HCACHE_COMPRESSION
421 const char *const c_header_cache_compress_method = cs_subset_string(NeoMutt->sub, "header_cache_compress_method");
422 if (c_header_cache_compress_method)
423 {
424 cops = compress_get_ops(c_header_cache_compress_method);
425
426 const short c_header_cache_compress_level = cs_subset_number(NeoMutt->sub, "header_cache_compress_level");
427 hc->cctx = cops->open(c_header_cache_compress_level);
428 if (!hc->cctx)
429 {
430 FREE(&hc);
431 return NULL;
432 }
433
434 /* remember the buffer of database backend */
435 mutt_debug(LL_DEBUG3, "Header cache will use %s compression\n", cops->name);
436 }
437#endif
438
439 hc->folder = get_foldername(folder);
440 hc->crc = hcachever;
441
442 if (!path || (path[0] == '\0'))
443 {
444 if (cops)
445 {
446 cops->close(&hc->cctx);
447 }
448
449 FREE(&hc->folder);
450 FREE(&hc);
451 return NULL;
452 }
453
454 struct Buffer *hcpath = mutt_buffer_pool_get();
455 hcache_per_folder(hcpath, path, hc->folder, namer);
456
457 hc->ctx = ops->open(mutt_buffer_string(hcpath));
458 if (!hc->ctx)
459 {
460 /* remove a possibly incompatible version */
461 if (unlink(mutt_buffer_string(hcpath)) == 0)
462 {
463 hc->ctx = ops->open(mutt_buffer_string(hcpath));
464 if (!hc->ctx)
465 {
466 if (cops)
467 {
468 cops->close(&hc->cctx);
469 }
470 FREE(&hc->folder);
471 FREE(&hc);
472 }
473 }
474 }
475
477 return hc;
478}
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
const struct ComprOps * compress_get_ops(const char *compr)
Get the API functions for a compress backend.
Definition: compress.c:80
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
struct ReplaceList SpamList
List of regexes and patterns to match spam emails.
Definition: globals.c:34
struct RegexList NoSpamList
List of regexes to identify non-spam emails.
Definition: globals.c:33
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
static unsigned int hcachever
Definition: hcache.c:63
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:262
static char * get_foldername(const char *folder)
Where should the cache be stored?
Definition: hcache.c:318
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
void mutt_md5_process_bytes(const void *buf, size_t buflen, struct Md5Ctx *md5ctx)
Process a block of data.
Definition: md5.c:374
void mutt_md5_process(const char *str, struct Md5Ctx *md5ctx)
Process a NULL-terminated string.
Definition: md5.c:356
void mutt_md5_init_ctx(struct Md5Ctx *md5ctx)
Initialise the MD5 computation.
Definition: md5.c:262
void * mutt_md5_finish_ctx(struct Md5Ctx *md5ctx, void *resbuf)
Process the remaining bytes in the buffer.
Definition: md5.c:286
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define FREE(x)
Definition: memory.h:43
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
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:34
Definition: lib.h:60
void(* close)(void **cctx)
Definition: lib.h:119
void *(* open)(short level)
Definition: lib.h:74
const char * name
Compression name.
Definition: lib.h:61
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
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 *(* open)(const char *path)
Definition: lib.h:82
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hcache_close()

void mutt_hcache_close ( struct HeaderCache hc)

Close the connection to the header cache.

Parameters
hcPointer to the struct HeaderCache structure got by mutt_hcache_open()

Close the connection to the header cache.

Definition at line 483 of file hcache.c.

484{
485 const char *const c_header_cache_backend = cs_subset_string(NeoMutt->sub, "header_cache_backend");
486 const struct StoreOps *ops = store_get_backend_ops(c_header_cache_backend);
487 if (!hc || !ops)
488 return;
489
490#ifdef USE_HCACHE_COMPRESSION
491 const char *const c_header_cache_compress_method = cs_subset_string(NeoMutt->sub, "header_cache_compress_method");
492 if (c_header_cache_compress_method)
493 {
494 const struct ComprOps *cops = compress_get_ops(c_header_cache_compress_method);
495 cops->close(&hc->cctx);
496 }
497#endif
498
499 ops->close(&hc->ctx);
500 FREE(&hc->folder);
501 FREE(&hc);
502}
void(* close)(void **ptr)
Definition: lib.h:143
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hcache_store()

int mutt_hcache_store ( struct HeaderCache hc,
const char *  key,
size_t  keylen,
struct Email e,
uint32_t  uidvalidity 
)

Store a Header along with a validity datum.

Parameters
hcPointer to the struct HeaderCache structure got by mutt_hcache_open()
keyMessage identification string
keylenLength of the key string
eEmail to store
uidvalidityIMAP-specific UIDVALIDITY value, or 0 to use the current time
Return values
0Success
numGeneric or backend-specific error code otherwise

Store a Header along with a validity datum.

Definition at line 610 of file hcache.c.

612{
613 if (!hc)
614 return -1;
615
616 int dlen = 0;
617 char *data = dump(hc, e, &dlen, uidvalidity);
618
619#ifdef USE_HCACHE_COMPRESSION
620 const char *const c_header_cache_compress_method = cs_subset_string(NeoMutt->sub, "header_cache_compress_method");
621 if (c_header_cache_compress_method)
622 {
623 /* We don't compress uidvalidity and the crc, so we can check them before
624 * decompressing on fetch(). */
625 size_t hlen = header_size();
626
627 const struct ComprOps *cops = compress_get_ops(c_header_cache_compress_method);
628
629 /* data / dlen gets ptr to compressed data here */
630 size_t clen = dlen;
631 void *cdata = cops->compress(hc->cctx, data + hlen, dlen - hlen, &clen);
632 if (!cdata)
633 {
634 FREE(&data);
635 return -1;
636 }
637
638 char *whole = mutt_mem_malloc(hlen + clen);
639 memcpy(whole, data, hlen);
640 memcpy(whole + hlen, cdata, clen);
641
642 FREE(&data);
643
644 data = whole;
645 dlen = hlen + clen;
646 }
647#endif
648
649 /* store uncompressed data */
650 struct RealKey *rk = realkey(key, keylen);
651 int rc = mutt_hcache_store_raw(hc, rk->key, rk->len, data, dlen);
652
653 FREE(&data);
654
655 return rc;
656}
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:192
static void * dump(struct HeaderCache *hc, const struct Email *e, int *off, uint32_t uidvalidity)
Serialise an Email object.
Definition: hcache.c:85
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:668
static size_t header_size(void)
Compute the size of the header with uuid validity and crc.
Definition: hcache.c:69
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
void *(* compress)(void *cctx, const char *data, size_t dlen, size_t *clen)
Definition: lib.h:91
Hcache key name (including compression method)
Definition: hcache.c:181
char key[1024]
Key name.
Definition: hcache.c:182
size_t len
Length of key.
Definition: hcache.c:183
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hcache_fetch()

struct HCacheEntry mutt_hcache_fetch ( struct HeaderCache hc,
const char *  key,
size_t  keylen,
uint32_t  uidvalidity 
)

Fetch and validate a message's header from the cache.

Parameters
hcPointer to the struct HeaderCache structure got by mutt_hcache_open()
keyMessage identification string
keylenLength of the string pointed to by key
uidvalidityOnly restore if it matches the stored uidvalidity
Return values
objHCacheEntry containing an Email, empty on failure
Note
This function performs a check on the validity of the data found by comparing it with the crc value of the struct HeaderCache structure.

Fetch and validate a message's header from the cache.

Definition at line 507 of file hcache.c.

509{
510 struct RealKey *rk = realkey(key, keylen);
511 struct HCacheEntry entry = { 0 };
512
513 size_t dlen;
514 void *data = fetch_raw(hc, rk->key, rk->len, &dlen);
515 void *to_free = data;
516 if (!data)
517 {
518 goto end;
519 }
520
521 /* restore uidvalidity and crc */
522 size_t hlen = header_size();
523 if (hlen > dlen)
524 {
525 goto end;
526 }
527 int off = 0;
528 serial_restore_uint32_t(&entry.uidvalidity, data, &off);
529 serial_restore_int(&entry.crc, data, &off);
530 assert((size_t) off == hlen);
531 if (entry.crc != hc->crc || ((uidvalidity != 0) && uidvalidity != entry.uidvalidity))
532 {
533 goto end;
534 }
535
536#ifdef USE_HCACHE_COMPRESSION
537 const char *const c_header_cache_compress_method = cs_subset_string(NeoMutt->sub, "header_cache_compress_method");
538 if (c_header_cache_compress_method)
539 {
540 const struct ComprOps *cops = compress_get_ops(c_header_cache_compress_method);
541
542 void *dblob = cops->decompress(hc->cctx, (char *) data + hlen, dlen - hlen);
543 if (!dblob)
544 {
545 goto end;
546 }
547 data = (char *) dblob - hlen; /* restore skips uidvalidity and crc */
548 }
549#endif
550
551 entry.email = restore(data);
552
553end:
554 free_raw(hc, &to_free);
555 return entry;
556}
static struct Email * restore(const unsigned char *d)
Restore an Email from data retrieved from the cache.
Definition: hcache.c:143
static void free_raw(struct HeaderCache *hc, void **data)
Multiplexor for StoreOps::free.
Definition: hcache.c:359
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:341
void serial_restore_int(unsigned int *i, const unsigned char *d, int *off)
Unpack an integer from a binary blob.
Definition: serialize.c:99
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
void *(* decompress)(void *cctx, const char *cbuf, size_t clen)
Definition: lib.h:107
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
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hcache_fetch_str()

char * mutt_hcache_fetch_str ( struct HeaderCache hc,
const char *  key,
size_t  keylen 
)

Fetch a string from the cache.

Parameters
[in]hcPointer to the struct HeaderCache structure got by mutt_hcache_open()
[in]keyMessage identification string
[in]keylenLength of the string pointed to by key
Return values
ptrSuccess, the data if found
NULLOtherwise

Definition at line 594 of file hcache.c.

595{
596 char *res = NULL;
597 size_t dlen = 0;
598 void *data = fetch_raw(hc, key, keylen, &dlen);
599 if (data)
600 {
601 res = mutt_strn_dup(data, dlen);
602 free_raw(hc, &data);
603 }
604 return res;
605}
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:451
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hcache_fetch_obj_()

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.

Parameters
[in]hcPointer to the struct HeaderCache structure got by mutt_hcache_open()
[in]keyMessage identification string
[in]keylenLength of the string pointed to by key
[out]dstPointer to the destination object
[in]dstlenSize of the destination object
Return values
trueSuccess, the data was found and the length matches
falseOtherwise

Definition at line 568 of file hcache.c.

570{
571 bool rc = true;
572 size_t srclen = 0;
573 void *src = fetch_raw(hc, key, keylen, &srclen);
574 if (src && srclen == dstlen)
575 {
576 memcpy(dst, src, dstlen);
577 }
578 else
579 {
580 rc = false;
581 }
582 free_raw(hc, &src);
583 return rc;
584}
+ Here is the call graph for this function:

◆ mutt_hcache_store_raw()

int mutt_hcache_store_raw ( struct HeaderCache hc,
const char *  key,
size_t  keylen,
void *  data,
size_t  dlen 
)

Store a key / data pair.

Parameters
hcPointer to the struct HeaderCache structure got by mutt_hcache_open()
keyMessage identification string
keylenLength of the string pointed to by key
dataPayload to associate with key
dlenLength of the buffer pointed to by the data parameter
Return values
0Success
numGeneric or backend-specific error code otherwise

Definition at line 668 of file hcache.c.

670{
671 const char *const c_header_cache_backend = cs_subset_string(NeoMutt->sub, "header_cache_backend");
672 const struct StoreOps *ops = store_get_backend_ops(c_header_cache_backend);
673
674 if (!hc || !ops)
675 return -1;
676
677 struct Buffer path = mutt_buffer_make(1024);
678
679 keylen = mutt_buffer_printf(&path, "%s%.*s", hc->folder, (int) keylen, key);
680 int rc = ops->store(hc->ctx, mutt_buffer_string(&path), keylen, data, dlen);
681 mutt_buffer_dealloc(&path);
682
683 return rc;
684}
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:67
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:347
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
char * data
Pointer to data.
Definition: buffer.h:35
int(* store)(void *store, const char *key, size_t klen, void *value, size_t vlen)
Definition: lib.h:121
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hcache_delete_record()

int mutt_hcache_delete_record ( struct HeaderCache hc,
const char *  key,
size_t  keylen 
)

Delete a key / data pair.

Parameters
hcPointer to the struct HeaderCache structure got by mutt_hcache_open()
keyMessage identification string
keylenLength of the string pointed to by key
Return values
0Success
numGeneric or backend-specific error code otherwise

Delete a key / data pair.

Definition at line 689 of file hcache.c.

690{
691 if (!hc)
692 return -1;
693
694 const char *const c_header_cache_backend = cs_subset_string(NeoMutt->sub, "header_cache_backend");
695 const struct StoreOps *ops = store_get_backend_ops(c_header_cache_backend);
696
697 struct Buffer path = mutt_buffer_make(1024);
698
699 keylen = mutt_buffer_printf(&path, "%s%s", hc->folder, key);
700
701 int rc = ops->delete_record(hc->ctx, mutt_buffer_string(&path), keylen);
702 mutt_buffer_dealloc(&path);
703 return rc;
704}
int(* delete_record)(void *store, const char *key, size_t klen)
Definition: lib.h:134
+ Here is the call graph for this function:
+ Here is the caller graph for this function: