2 * Copyright (C) 2004 Thomas Glanzmann <sithglan@stud.uni-erlangen.de>
3 * Copyright (C) 2004 Tobias Werth <sitowert@stud.uni-erlangen.de>
4 * Copyright (C) 2004 Brian Fundakowski Feldman <green@FreeBSD.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 # include <inttypes.h>
31 #endif /* HAVE_CONFIG_H */
71 char lockfile[_POSIX_PATH_MAX];
77 struct timeval timeval;
78 uint64_t uid_validity;
82 lazy_malloc(size_t siz)
84 if (0 < siz && siz < 4096) {
88 return safe_malloc(siz);
92 lazy_realloc(void *ptr, size_t siz)
94 void **p = (void **)ptr;
102 safe_realloc(ptr, siz);
105 static unsigned char *
106 dump_int(unsigned int i, unsigned char *d, int *off)
108 lazy_realloc(&d, *off + sizeof(int));
109 memcpy(d + *off, &i, sizeof(int));
110 (*off) += sizeof(int);
116 restore_int(unsigned int *i, const unsigned char *d, int *off)
118 memcpy(i, d + *off, sizeof(int));
119 (*off) += sizeof(int);
122 static unsigned char *
123 dump_char(char *c, unsigned char *d, int *off)
129 d = dump_int(size, d, off);
133 size = mutt_strlen(c) + 1;
134 d = dump_int(size, d, off);
135 lazy_realloc(&d, *off + size);
136 memcpy(d + *off, c, size);
143 static unsigned char *
144 dump_char_size(char *c, unsigned char *d, int *off, ssize_t size)
148 d = dump_int(size, d, off);
152 d = dump_int(size, d, off);
153 lazy_realloc(&d, *off + size);
154 memcpy(d + *off, c, size);
162 restore_char(char **c, const unsigned char *d, int *off)
165 restore_int(&size, d, off);
172 *c = safe_malloc(size);
173 memcpy(*c, d + *off, size);
177 static unsigned char *
178 dump_address(ADDRESS *a, unsigned char *d, int *off)
180 unsigned int counter = 0;
181 unsigned int start_off = *off;
183 d = dump_int(0xdeadbeef, d, off);
187 d = dump_char(a->val, d, off);
189 d = dump_char(a->personal, d, off);
190 d = dump_char(a->mailbox, d, off);
191 d = dump_int(a->group, d, off);
196 memcpy(d + start_off, &counter, sizeof(int));
202 restore_address(ADDRESS **a, const unsigned char *d, int *off)
204 unsigned int counter;
206 restore_int(&counter, d, off);
209 *a = safe_malloc(sizeof(ADDRESS));
211 restore_char(&(*a)->val, d, off);
213 restore_char(&(*a)->personal, d, off);
214 restore_char(&(*a)->mailbox, d, off);
215 restore_int((unsigned int *)&(*a)->group, d, off);
223 static unsigned char *
224 dump_list(LIST *l, unsigned char *d, int *off)
226 unsigned int counter = 0;
227 unsigned int start_off = *off;
229 d = dump_int(0xdeadbeef, d, off);
232 d = dump_char(l->data, d, off);
237 memcpy(d + start_off, &counter, sizeof(int));
243 restore_list(LIST **l, const unsigned char *d, int *off)
245 unsigned int counter;
247 restore_int(&counter, d, off);
250 *l = safe_malloc(sizeof(LIST));
251 restore_char(&(*l)->data, d, off);
260 static unsigned char *
261 dump_buffer(BUFFER *b, unsigned char *d, int *off)
264 d = dump_int(0, d, off);
267 d = dump_int(1, d, off);
270 d = dump_char_size(b->data, d, off, b->dsize + 1);
271 d = dump_int(b->dptr - b->data, d, off);
272 d = dump_int(b->dsize, d, off);
273 d = dump_int(b->destroy, d, off);
279 restore_buffer(BUFFER **b, const unsigned char *d, int *off)
283 restore_int(&used, d, off);
288 *b = safe_malloc(sizeof(BUFFER));
290 restore_char(& (*b)->data, d, off);
291 restore_int(& offset, d, off);
292 (*b)->dptr = (*b)->data + offset;
293 restore_int(& (*b)->dsize, d, off);
294 restore_int((unsigned int *) & (*b)->destroy, d, off);
298 static unsigned char *
299 dump_parameter(PARAMETER *p, unsigned char *d, int *off)
301 unsigned int counter = 0;
302 unsigned int start_off = *off;
304 d = dump_int(0xdeadbeef, d, off);
307 d = dump_char(p->attribute, d, off);
308 d = dump_char(p->value, d, off);
313 memcpy(d + start_off, &counter, sizeof(int));
319 restore_parameter(PARAMETER **p, const unsigned char *d, int *off)
321 unsigned int counter;
323 restore_int(&counter, d, off);
326 *p = safe_malloc(sizeof(PARAMETER));
327 restore_char(&(*p)->attribute, d, off);
328 restore_char(&(*p)->value, d, off);
336 static unsigned char *
337 dump_body(BODY *c, unsigned char *d, int *off)
339 lazy_realloc(&d, *off + sizeof(BODY));
340 memcpy(d + *off, c, sizeof(BODY));
341 *off += sizeof(BODY);
343 d = dump_char(c->xtype, d, off);
344 d = dump_char(c->subtype, d, off);
346 d = dump_parameter(c->parameter, d, off);
348 d = dump_char(c->description, d, off);
349 d = dump_char(c->form_name, d, off);
350 d = dump_char(c->filename, d, off);
351 d = dump_char(c->d_filename, d, off);
357 restore_body(BODY *c, const unsigned char *d, int *off)
359 memcpy(c, d + *off, sizeof(BODY));
360 *off += sizeof(BODY);
362 restore_char(& c->xtype, d, off);
363 restore_char(& c->subtype, d, off);
365 restore_parameter(& c->parameter, d, off);
367 restore_char(& c->description, d, off);
368 restore_char(& c->form_name, d, off);
369 restore_char(& c->filename, d, off);
370 restore_char(& c->d_filename, d, off);
373 static unsigned char *
374 dump_envelope(ENVELOPE *e, unsigned char *d, int *off)
376 d = dump_address(e->return_path, d, off);
377 d = dump_address(e->from, d, off);
378 d = dump_address(e->to, d, off);
379 d = dump_address(e->cc, d, off);
380 d = dump_address(e->bcc, d, off);
381 d = dump_address(e->sender, d, off);
382 d = dump_address(e->reply_to, d, off);
383 d = dump_address(e->mail_followup_to, d, off);
385 d = dump_char(e->subject, d, off);
387 d = dump_int(e->real_subj - e->subject, d, off);
389 d = dump_int(-1, d, off);
391 d = dump_char(e->message_id, d, off);
392 d = dump_char(e->supersedes, d, off);
393 d = dump_char(e->date, d, off);
394 d = dump_char(e->x_label, d, off);
396 d = dump_list(e->references, d, off);
397 d = dump_list(e->in_reply_to, d, off);
398 d = dump_list(e->userhdrs, d, off);
404 restore_envelope(ENVELOPE *e, const unsigned char *d, int *off)
408 restore_address(& e->return_path, d, off);
409 restore_address(& e->from, d, off);
410 restore_address(& e->to, d, off);
411 restore_address(& e->cc, d, off);
412 restore_address(& e->bcc, d, off);
413 restore_address(& e->sender, d, off);
414 restore_address(& e->reply_to, d, off);
415 restore_address(& e->mail_followup_to, d, off);
417 restore_char(& e->subject, d, off);
418 restore_int((unsigned int *) (& real_subj_off), d, off);
419 if (0 <= real_subj_off) {
420 e->real_subj = e->subject + real_subj_off;
424 restore_char(& e->message_id, d, off);
425 restore_char(& e->supersedes, d, off);
426 restore_char(& e->date, d, off);
427 restore_char(& e->x_label, d, off);
429 restore_list(& e->references, d, off);
430 restore_list(& e->in_reply_to, d, off);
431 restore_list(& e->userhdrs, d, off);
435 unsigned int crc32(unsigned int crc, unsigned char const *p, size_t len)
440 for (i = 0; i < 8; i++)
441 crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
451 crc = crc32(crc, (unsigned char const *) "sithglan@stud.uni-erlangen.de[sithglan]|hcache.c|20041108231548|29613", mutt_strlen("sithglan@stud.uni-erlangen.de[sithglan]|hcache.c|20041108231548|29613"));
453 #if HAVE_LANGINFO_CODESET
454 crc = crc32(crc, (unsigned char const *) Charset, mutt_strlen(Charset));
455 crc = crc32(crc, (unsigned char const *) "HAVE_LANGINFO_CODESET", mutt_strlen("HAVE_LANGINFO_CODESET"));
459 crc = crc32(crc, (unsigned char const *) "EXACT_ADDRESS", mutt_strlen("EXACT_ADDRESS"));
463 crc = crc32(crc, (unsigned char const *) "USE_POP", mutt_strlen("USE_POP"));
467 crc = crc32(crc, (unsigned char const *) "MIXMASTER", mutt_strlen("MIXMASTER"));
471 crc = crc32(crc, (unsigned char const *) "USE_IMAP", mutt_strlen("USE_IMAP"));
477 crc32_matches(const char *d, unsigned int crc)
479 int off = sizeof(validate);
480 unsigned int mycrc = 0;
486 restore_int(&mycrc, (unsigned char *) d, &off);
488 return (crc == mycrc);
491 /* Append md5sumed folder to path if path is a directory. */
493 mutt_hcache_per_folder(const char *path, const char *folder)
495 static char mutt_hcache_per_folder_path[_POSIX_PATH_MAX];
496 struct stat path_stat;
498 unsigned char md5sum[16];
501 ret = stat(path, &path_stat);
506 if (! S_ISDIR(path_stat.st_mode)) {
511 MD5Update(&md5, (unsigned char *) folder, strlen(folder));
512 MD5Final(md5sum, &md5);
514 ret = snprintf(mutt_hcache_per_folder_path, _POSIX_PATH_MAX,
515 "%s/%02x%02x%02x%02x%02x%02x%02x%02x"
516 "%02x%02x%02x%02x%02x%02x%02x%02x",
517 path, md5sum[0], md5sum[1], md5sum[2], md5sum[3],
518 md5sum[4], md5sum[5], md5sum[6], md5sum[7], md5sum[8],
519 md5sum[9], md5sum[10], md5sum[11], md5sum[12],
520 md5sum[13], md5sum[14], md5sum[15]);
526 return mutt_hcache_per_folder_path;
529 /* This function transforms a header into a char so that it is useable by
532 mutt_hcache_dump(void *_db, HEADER *h, int *off, uint64_t uid_validity)
534 struct header_cache *db = _db;
535 unsigned char *d = NULL;
538 d = lazy_malloc(sizeof(validate));
541 memcpy(d, &uid_validity, sizeof(uint64_t));
544 gettimeofday(&now, NULL);
545 memcpy(d, &now, sizeof(struct timeval));
547 *off += sizeof(validate);
549 d = dump_int(db->crc, d, off);
551 lazy_realloc(&d, *off + sizeof(HEADER));
552 memcpy(d + *off, h, sizeof(HEADER));
553 *off += sizeof(HEADER);
555 d = dump_envelope(h->env, d, off);
556 d = dump_body(h->content, d, off);
557 d = dump_char(h->maildir_flags, d, off);
563 mutt_hcache_restore(const unsigned char *d, HEADER **oh)
566 HEADER *h = mutt_new_header();
569 off += sizeof(validate);
572 off += sizeof(unsigned int);
574 memcpy(h, d + off, sizeof(HEADER));
575 off += sizeof(HEADER);
577 h->env = mutt_new_envelope();
578 restore_envelope(h->env, d, &off);
580 h->content = mutt_new_body();
581 restore_body(h->content, d, &off);
583 restore_char(&h->maildir_flags, d, &off);
585 /* this is needed for maildir style mailboxes */
588 h->path = safe_strdup((*oh)->path);
589 mutt_free_header (oh);
598 mutt_hcache_open(const char *path, const char *folder)
600 struct header_cache *h = safe_calloc(1, sizeof(HEADER_CACHE));
601 int pagesize = atoi(HeaderCachePageSize) ? atoi(HeaderCachePageSize) : 16384;
603 h->folder = safe_strdup (folder);
604 h->crc = generate_crc32();
606 if (! path || path[0] == '\0') {
612 path = mutt_hcache_per_folder(path, folder);
614 h->db = gdbm_open((char *) path, pagesize, GDBM_WRCREAT, 00600, NULL);
619 /* if rw failed try ro */
620 h->db = gdbm_open((char *) path, pagesize, GDBM_READER, 00600, NULL);
632 mutt_hcache_close(void *db)
634 struct header_cache *h = db;
646 mutt_hcache_fetch(void *db, const char *filename, size_t (*keylen)(const char *fn))
648 struct header_cache *h = db;
651 char path[_POSIX_PATH_MAX];
657 strncpy(path, h->folder, sizeof(path));
658 strncat(path, filename, sizeof(path) - mutt_strlen(path));
661 key.dsize = keylen(path);
663 data = gdbm_fetch(h->db, key);
665 if (! crc32_matches(data.dptr, h->crc)) {
674 mutt_hcache_store(void *db, const char *filename, HEADER *header, uint64_t uid_validity, size_t (*keylen)(const char *fn))
676 struct header_cache *h = db;
679 char path[_POSIX_PATH_MAX];
686 strncpy(path, h->folder, sizeof(path));
687 strncat(path, filename, sizeof(path) - mutt_strlen(path));
690 key.dsize = keylen(path);
692 data.dptr = mutt_hcache_dump(db, header, &data.dsize, uid_validity);
694 ret = gdbm_store(h->db, key, data, GDBM_REPLACE);
702 mutt_hcache_delete(void *db, const char *filename, size_t (*keylen)(const char *fn))
705 struct header_cache *h = db;
706 char path[_POSIX_PATH_MAX];
712 strncpy(path, h->folder, sizeof(path));
713 strncat(path, filename, sizeof(path) - mutt_strlen(path));
716 key.dsize = keylen(path);
718 return gdbm_delete(h->db, key);
723 mutt_hcache_dbt_init(DBT *dbt, void *data, size_t len)
726 dbt->size = dbt->ulen = len;
727 dbt->dlen = dbt->doff = 0;
728 dbt->flags = DB_DBT_USERMEM;
732 mutt_hcache_dbt_empty_init(DBT *dbt)
735 dbt->size = dbt->ulen = dbt->dlen = dbt->doff = 0;
740 mutt_hcache_open(const char *path, const char *folder)
743 u_int32_t createflags = DB_CREATE;
745 struct header_cache *h = calloc(1, sizeof(HEADER_CACHE));
746 int pagesize = atoi(HeaderCachePageSize);
749 h->crc = generate_crc32();
751 if (! path || path[0] == '\0') {
756 path = mutt_hcache_per_folder(path, folder);
758 snprintf (h->lockfile, _POSIX_PATH_MAX, "%s-lock-hack", path);
760 h->fd = open(h->lockfile, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
766 if (mx_lock_file(h->lockfile, h->fd, 1, 0, 5)) {
772 ret = db_env_create(&h->env, 0);
774 mx_unlock_file(h->lockfile, h->fd, 0);
780 ret = h->env->open(h->env, NULL, DB_INIT_MPOOL | DB_CREATE | DB_PRIVATE, 0600);
782 ret = db_create(&h->db, h->env, 0);
784 h->env->close(h->env, 0);
785 mx_unlock_file(h->lockfile, h->fd, 0);
792 if (stat(path, &sb) != 0 && errno == ENOENT) {
793 createflags |= DB_EXCL;
794 h->db->set_pagesize(h->db, pagesize);
797 ret = h->db->open(h->db, NULL, path, folder, DB_BTREE, createflags, 0600);
799 h->db->close(h->db, 0);
800 h->env->close(h->env, 0);
801 mx_unlock_file(h->lockfile, h->fd, 0);
811 mutt_hcache_close(void *db)
813 struct header_cache *h = db;
820 h->db->close(h->db, 0);
821 h->env->close(h->env, 0);
822 mx_unlock_file(h->lockfile, h->fd, 0);
828 mutt_hcache_fetch(void *db, const char *filename, size_t (*keylen)(const char *fn))
832 struct header_cache *h = db;
838 filename++; /* skip '/' */
840 mutt_hcache_dbt_init(&key, (void *) filename, keylen(filename));
841 mutt_hcache_dbt_empty_init(&data);
842 data.flags = DB_DBT_MALLOC;
844 h->db->get(h->db, NULL, &key, &data, 0);
846 if (! crc32_matches(data.data, h->crc)) {
855 mutt_hcache_store(void *db, const char *filename, HEADER *header, uint64_t uid_validity, size_t (*keylen)(const char *fn))
860 struct header_cache *h = db;
866 filename++; /* skip '/' */
868 mutt_hcache_dbt_init(&key, (void *) filename, keylen(filename));
870 mutt_hcache_dbt_empty_init(&data);
871 data.flags = DB_DBT_USERMEM;
872 data.data = mutt_hcache_dump(db, header, (signed int *) &data.size, uid_validity);
873 data.ulen = data.size;
875 ret = h->db->put(h->db, NULL, &key, &data, 0);
883 mutt_hcache_delete(void *db, const char *filename, size_t (*keylen)(const char *fn))
886 struct header_cache *h = db;
892 filename++; /* skip '/' */
894 mutt_hcache_dbt_init(&key, (void *) filename, keylen(filename));
895 return h->db->del(h->db, NULL, &key, 0);
899 #endif /* USE_HCACHE */