2 * Copyright notice from original mutt:
3 * Copyright (C) 2004 Thomas Glanzmann <sithglan@stud.uni-erlangen.de>
4 * Copyright (C) 2004 Tobias Werth <sitowert@stud.uni-erlangen.de>
5 * Copyright (C) 2004 Brian Fundakowski Feldman <green@FreeBSD.org>
7 * This file is part of mutt-ng, see http://www.muttng.org/.
8 * It's licensed under the GNU General Public License,
9 * please see the file GPL in the top level source directory.
12 #include <lib-lib/lib-lib.h>
16 #define MUTTNG_HCACHE_ID "0x004"
18 #if defined(HAVE_QDBM)
22 #elif defined(HAVE_GDBM)
26 #include <imap/message.h>
33 #if defined(HAVE_QDBM)
35 #elif defined(HAVE_GDBM)
43 struct timeval timeval;
44 unsigned long uid_validity;
47 #define UPPER4K(i) ((i & ~(4096 - 1)) + 4096)
49 static unsigned char *lazy_malloc(ssize_t siz)
51 return p_new(unsigned char, UPPER4K(siz));
54 static void lazy_realloc(unsigned char **p, ssize_t siz)
56 p_realloc(p, UPPER4K(siz));
59 static unsigned char *dump_int (unsigned int i, unsigned char *d, int *off)
61 lazy_realloc (&d, *off + sizeof (int));
62 memcpy (d + *off, &i, sizeof (int));
63 (*off) += sizeof (int);
68 static void restore_int (unsigned int *i, const unsigned char *d, int *off)
70 memcpy (i, d + *off, sizeof (int));
71 (*off) += sizeof (int);
74 static unsigned char *dump_char (char *c, unsigned char *d, int *off)
80 d = dump_int (size, d, off);
84 size = m_strlen(c) + 1;
85 d = dump_int (size, d, off);
86 lazy_realloc (&d, *off + size);
87 memcpy (d + *off, c, size);
93 static void restore_char (char **c, const unsigned char *d, int *off)
97 restore_int (&size, d, off);
104 *c = p_dup(d + *off, size);
108 static unsigned char *dump_address (address_t * a, unsigned char *d, int *off)
110 unsigned int counter = 0;
111 unsigned int start_off = *off;
113 d = dump_int (0xdeadbeef, d, off);
116 d = dump_char (a->personal, d, off);
117 d = dump_char (a->mailbox, d, off);
118 d = dump_int (a->group, d, off);
123 memcpy (d + start_off, &counter, sizeof (int));
128 static void restore_address (address_t ** a, const unsigned char *d, int *off)
130 unsigned int counter;
132 restore_int (&counter, d, off);
135 *a = p_new(address_t, 1);
136 restore_char (&(*a)->personal, d, off);
137 restore_char (&(*a)->mailbox, d, off);
138 restore_int ((unsigned int *) &(*a)->group, d, off);
146 static unsigned char *dump_list (string_list_t * l, unsigned char *d, int *off)
148 unsigned int counter = 0;
149 unsigned int start_off = *off;
151 d = dump_int (0xdeadbeef, d, off);
154 d = dump_char (l->data, d, off);
159 memcpy (d + start_off, &counter, sizeof (int));
164 static void restore_list (string_list_t ** l, const unsigned char *d, int *off)
166 unsigned int counter;
168 restore_int (&counter, d, off);
171 *l = p_new(string_list_t, 1);
172 restore_char (&(*l)->data, d, off);
180 static unsigned char *dump_parameter (parameter_t * p, unsigned char *d,
183 unsigned int counter = 0;
184 unsigned int start_off = *off;
186 d = dump_int (0xdeadbeef, d, off);
189 d = dump_char (p->attribute, d, off);
190 d = dump_char (p->value, d, off);
195 memcpy (d + start_off, &counter, sizeof (int));
201 restore_parameter (parameter_t ** p, const unsigned char *d, int *off)
203 unsigned int counter;
205 restore_int (&counter, d, off);
208 *p = parameter_new();
209 restore_char (&(*p)->attribute, d, off);
210 restore_char (&(*p)->value, d, off);
216 static unsigned char *dump_body (BODY * c, unsigned char *d, int *off)
218 lazy_realloc (&d, *off + sizeof (BODY));
219 memcpy (d + *off, c, sizeof (BODY));
220 *off += sizeof (BODY);
222 d = dump_char (c->xtype, d, off);
223 d = dump_char (c->subtype, d, off);
225 d = dump_parameter (c->parameter, d, off);
227 d = dump_char (c->description, d, off);
228 d = dump_char (c->form_name, d, off);
229 d = dump_char (c->filename, d, off);
230 d = dump_char (c->d_filename, d, off);
235 static void restore_body (BODY * c, const unsigned char *d, int *off)
237 memcpy (c, d + *off, sizeof (BODY));
238 *off += sizeof (BODY);
240 restore_char (&c->xtype, d, off);
241 restore_char (&c->subtype, d, off);
243 restore_parameter (&c->parameter, d, off);
245 restore_char (&c->description, d, off);
246 restore_char (&c->form_name, d, off);
247 restore_char (&c->filename, d, off);
248 restore_char (&c->d_filename, d, off);
251 static unsigned char *dump_envelope (ENVELOPE * e, unsigned char *d, int *off)
253 d = dump_address (e->return_path, d, off);
254 d = dump_address (e->from, d, off);
255 d = dump_address (e->to, d, off);
256 d = dump_address (e->cc, d, off);
257 d = dump_address (e->bcc, d, off);
258 d = dump_address (e->sender, d, off);
259 d = dump_address (e->reply_to, d, off);
260 d = dump_address (e->mail_followup_to, d, off);
262 d = dump_char (e->subject, d, off);
264 d = dump_int (e->real_subj - e->subject, d, off);
267 d = dump_int (-1, d, off);
269 d = dump_char (e->message_id, d, off);
270 d = dump_char (e->supersedes, d, off);
271 d = dump_char (e->date, d, off);
272 d = dump_char (e->x_label, d, off);
273 d = dump_char (e->list_post, d, off);
276 d = dump_char (e->newsgroups, d, off);
277 d = dump_char (e->xref, d, off);
278 d = dump_char (e->followup_to, d, off);
279 d = dump_char (e->x_comment_to, d, off);
282 d = dump_list (e->references, d, off);
283 d = dump_list (e->in_reply_to, d, off);
284 d = dump_list (e->userhdrs, d, off);
289 static void restore_envelope (ENVELOPE * e, const unsigned char *d, int *off)
293 restore_address (&e->return_path, d, off);
294 restore_address (&e->from, d, off);
295 restore_address (&e->to, d, off);
296 restore_address (&e->cc, d, off);
297 restore_address (&e->bcc, d, off);
298 restore_address (&e->sender, d, off);
299 restore_address (&e->reply_to, d, off);
300 restore_address (&e->mail_followup_to, d, off);
302 restore_char (&e->subject, d, off);
303 restore_int ((unsigned int *) (&real_subj_off), d, off);
304 if (0 <= real_subj_off) {
305 e->real_subj = e->subject + real_subj_off;
310 restore_char (&e->message_id, d, off);
311 restore_char (&e->supersedes, d, off);
312 restore_char (&e->date, d, off);
313 restore_char (&e->x_label, d, off);
314 restore_char (&e->list_post, d, off);
317 restore_char (&e->newsgroups, d, off);
318 restore_char (&e->xref, d, off);
319 restore_char (&e->followup_to, d, off);
320 restore_char (&e->x_comment_to, d, off);
323 restore_list (&e->references, d, off);
324 restore_list (&e->in_reply_to, d, off);
325 restore_list (&e->userhdrs, d, off);
329 unsigned int crc32 (unsigned int crc, unsigned char const *p, ssize_t len)
335 for (i = 0; i < 8; i++)
336 crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
341 static int generate_crc32 ()
345 crc = crc32 (crc, (unsigned char const *)
346 MUTTNG_HCACHE_ID "sithglan@stud.uni-erlangen.de[sithglan]|hcache.c|20041108231548|29613",
348 (MUTTNG_HCACHE_ID "sithglan@stud.uni-erlangen.de[sithglan]|hcache.c|20041108231548|29613"));
350 #ifdef HAVE_LANGINFO_CODESET
351 crc = crc32(crc, (unsigned char const *) MCharset.charset, m_strlen(MCharset.charset));
352 crc = crc32(crc, (unsigned char const *) "HAVE_LANGINFO_CODESET",
353 m_strlen("HAVE_LANGINFO_CODESET"));
356 crc = crc32(crc, (unsigned char const *) "USE_POP", m_strlen("USE_POP"));
358 crc = crc32(crc, (unsigned char const *) "MIXMASTER",
359 m_strlen("MIXMASTER"));
361 crc = crc32(crc, (unsigned char const *) "USE_IMAP", m_strlen("USE_IMAP"));
364 crc = crc32(crc, (unsigned char const *) "USE_NNTP", m_strlen("USE_NNTP"));
369 static int crc32_matches (const char *d, unsigned int crc)
371 int off = sizeof (validate);
372 unsigned int mycrc = 0;
378 restore_int (&mycrc, (unsigned char *) d, &off);
380 return (crc == mycrc);
384 mutt_hcache_per_folder(const char *path, const char *folder)
386 static char buf[_POSIX_PATH_MAX];
390 if (stat(path, &st) < 0 || !S_ISDIR(st.st_mode)) {
394 pos = m_strcpy(buf, sizeof(buf), path);
395 pos += m_strputc(buf + pos, sizeof(buf) - pos, '/');
398 if (isalnum((unsigned char)*folder) || *folder == '.') {
399 pos += m_strputc(buf + pos, sizeof(buf) - pos, *folder);
401 pos += m_strputc(buf + pos, sizeof(buf) - pos, '_');
405 pos += m_strcpy(buf + pos, sizeof(buf) - pos, ".hdb");
409 /* This function transforms a header into a char so that it is useable by
411 static void *mutt_hcache_dump (void *_db, HEADER * h, int *off,
412 unsigned long uid_validity)
414 struct hcache_t *db = _db;
415 unsigned char *d = NULL;
419 d = lazy_malloc (sizeof (validate));
422 memcpy (d, &uid_validity, sizeof (unsigned long));
427 gettimeofday (&now, NULL);
428 memcpy (d, &now, sizeof (struct timeval));
430 *off += sizeof (validate);
432 d = dump_int (db->crc, d, off);
434 lazy_realloc (&d, *off + sizeof (HEADER));
435 memcpy (d + *off, h, sizeof (HEADER));
436 *off += sizeof (HEADER);
438 d = dump_envelope (h->env, d, off);
439 d = dump_body (h->content, d, off);
440 d = dump_char (h->maildir_flags, d, off);
445 HEADER *mutt_hcache_restore (const unsigned char *d, HEADER ** oh)
448 HEADER *h = header_new();
451 off += sizeof (validate);
454 off += sizeof (unsigned int);
456 memcpy (h, d + off, sizeof (HEADER));
457 off += sizeof (HEADER);
459 h->env = envelope_new();
460 restore_envelope (h->env, d, &off);
462 h->content = body_new();
463 restore_body (h->content, d, &off);
465 restore_char (&h->maildir_flags, d, &off);
467 /* this is needed for maildir style mailboxes */
470 h->path = m_strdup((*oh)->path);
477 hcache_t *mutt_hcache_open(const char *path, const char *folder)
479 hcache_t *h = p_new(hcache_t, 1);
481 h->folder = m_strdup(folder);
482 h->crc = generate_crc32();
484 if (m_strisempty(path)) {
485 p_delete(&h->folder);
490 path = mutt_hcache_per_folder(path, folder);
493 #if defined(HAVE_QDBM)
494 int flags = VL_OWRITER | VL_OCREAT;
495 if (option(OPTHCACHECOMPRESS))
498 h->db = vlopen(path, flags, VL_CMPLEX);
499 #elif defined(HAVE_GDBM)
500 int pagesize = atoi(HeaderCachePageSize) ?: 16384;
502 h->db = gdbm_open((char *) path, pagesize, GDBM_WRCREAT, 00600, NULL);
507 p_delete(&h->folder);
513 void mutt_hcache_close(hcache_t **db)
518 #if defined(HAVE_QDBM)
520 #elif defined(HAVE_GDBM)
521 gdbm_close((*db)->db);
524 p_delete(&(*db)->folder);
528 #if defined(HAVE_QDBM)
530 mutt_hcache_fetch(hcache_t *db, const char *filename,
531 ssize_t(*keylen) (const char *fn))
534 char path[_POSIX_PATH_MAX];
541 m_strcpy(path, sizeof(path), h->folder);
542 m_strcat(path, sizeof(path), filename);
544 ksize = strlen(h->folder) + keylen(path + strlen(h->folder));
546 data = vlget(h->db, path, ksize, NULL);
548 if (!crc32_matches(data, h->crc))
558 mutt_hcache_store(hcache_t *db, const char *filename, HEADER * header,
559 unsigned long uid_validity,
560 ssize_t(*keylen) (const char *fn))
563 char path[_POSIX_PATH_MAX];
571 m_strcpy(path, sizeof(path), h->folder);
572 m_strcat(path, sizeof(path), filename);
574 ksize = strlen(h->folder) + keylen(path + strlen(h->folder));
576 data = mutt_hcache_dump(db, header, &dsize, uid_validity);
578 ret = vlput(h->db, path, ksize, data, dsize, VL_DOVER);
586 mutt_hcache_delete(hcache_t *db, const char *filename,
587 ssize_t(*keylen) (const char *fn))
590 char path[_POSIX_PATH_MAX];
596 m_strcpy(path, sizeof(path), h->folder);
597 m_strcat(path, sizeof(path), filename);
599 ksize = strlen(h->folder) + keylen(path + strlen(h->folder));
601 return vlout(h->db, path, ksize);
604 #elif defined(HAVE_GDBM)
606 void *mutt_hcache_fetch (hcache_t *db, const char *filename,
607 ssize_t (*keylen) (const char *fn))
612 char path[_POSIX_PATH_MAX];
618 m_strcpy(path, sizeof(path), h->folder);
619 strncat (path, filename, sizeof (path) - m_strlen(path));
622 key.dsize = keylen (path);
624 data = gdbm_fetch (h->db, key);
626 if (!crc32_matches (data.dptr, h->crc)) {
627 p_delete(&data.dptr);
635 mutt_hcache_store (hcache_t *db, const char *filename, HEADER * header,
636 unsigned long uid_validity, ssize_t (*keylen) (const char *fn))
641 char path[_POSIX_PATH_MAX];
648 m_strcpy(path, sizeof(path), h->folder);
649 strncat (path, filename, sizeof (path) - m_strlen(path));
652 key.dsize = keylen (path);
654 data.dptr = mutt_hcache_dump (db, header, &data.dsize, uid_validity);
656 ret = gdbm_store (h->db, key, data, GDBM_REPLACE);
658 p_delete(&data.dptr);
664 mutt_hcache_delete (hcache_t *db, const char *filename,
665 ssize_t (*keylen) (const char *fn))
669 char path[_POSIX_PATH_MAX];
675 m_strcpy(path, sizeof(path), h->folder);
676 strncat (path, filename, sizeof (path) - m_strlen(path));
679 key.dsize = keylen (path);
681 return gdbm_delete (h->db, key);
685 #endif /* USE_HCACHE */