simplify hcache yet a bit more.
[apps/madmutt.git] / lib-mx / hcache.c
index 846a6cf..413d6c8 100644 (file)
@@ -13,8 +13,6 @@
 
 #ifdef USE_HCACHE
 
-#define MUTTNG_HCACHE_ID        "0x004"
-
 #if defined(HAVE_QDBM)
 #include <depot.h>
 #include <cabin.h>
 
 #include <imap/message.h>
 
-#include "md5.h"
 #include "charset.h"
 #include "mutt.h"
 #include "hcache.h"
 
-struct header_cache {
+struct hcache_t {
 #if defined(HAVE_QDBM)
-  VILLA *db;
-  char *folder;
-  unsigned int crc;
+    VILLA *db;
 #elif defined(HAVE_GDBM)
-  GDBM_FILE db;
-  char *folder;
-  unsigned int crc;
+    GDBM_FILE db;
 #endif
+    char *folder;
+    unsigned int crc;
 };
 
 typedef union {
@@ -328,97 +323,62 @@ static void restore_envelope (ENVELOPE * e, const unsigned char *d, int *off)
   restore_list (&e->userhdrs, d, off);
 }
 
-static
-unsigned int crc32 (unsigned int crc, unsigned char const *p, ssize_t len)
+static unsigned int crc32(unsigned int crc, const void *src, ssize_t len)
 {
-  int i;
+    int i;
+    const unsigned char *p = src;
 
-  while (len--) {
-    crc ^= *p++;
-    for (i = 0; i < 8; i++)
-      crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
-  }
-  return crc;
+    while (len--) {
+        crc ^= *p++;
+        for (i = 0; i < 8; i++)
+            crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
+    }
+    return crc;
 }
 
-static int generate_crc32 ()
+static int generate_crc32(void)
 {
-  int crc = 0;
-
-  crc = crc32 (crc, (unsigned char const *)
-               MUTTNG_HCACHE_ID "sithglan@stud.uni-erlangen.de[sithglan]|hcache.c|20041108231548|29613",
-               m_strlen
-               (MUTTNG_HCACHE_ID "sithglan@stud.uni-erlangen.de[sithglan]|hcache.c|20041108231548|29613"));
+    static int crc = 0;
 
+    crc = crc32(crc, "madmutt.2007.05.13", m_strlen("madmutt.2007.05.13"));
 #ifdef HAVE_LANGINFO_CODESET
-  crc = crc32(crc, (unsigned char const *) MCharset.charset, m_strlen(MCharset.charset));
-  crc = crc32(crc, (unsigned char const *) "HAVE_LANGINFO_CODESET",
-              m_strlen("HAVE_LANGINFO_CODESET"));
+    crc = crc32(crc, MCharset.charset, m_strlen(MCharset.charset));
+    crc = crc32(crc, "HAVE_LANGINFO_CODESET",
+                m_strlen("HAVE_LANGINFO_CODESET"));
 #endif
-
-  crc = crc32(crc, (unsigned char const *) "USE_POP", m_strlen("USE_POP"));
-
-  crc = crc32(crc, (unsigned char const *) "MIXMASTER",
-              m_strlen("MIXMASTER"));
-
-  crc = crc32(crc, (unsigned char const *) "USE_IMAP", m_strlen("USE_IMAP"));
-
+    crc = crc32(crc, "USE_POP",   m_strlen("USE_POP"));
+    crc = crc32(crc, "MIXMASTER", m_strlen("MIXMASTER"));
+    crc = crc32(crc, "USE_IMAP",  m_strlen("USE_IMAP"));
 #ifdef USE_NNTP
-  crc = crc32(crc, (unsigned char const *) "USE_NNTP", m_strlen("USE_NNTP"));
+    crc = crc32(crc, "USE_NNTP",  m_strlen("USE_NNTP"));
 #endif
-  return crc;
+    return crc;
 }
 
-static int crc32_matches (const char *d, unsigned int crc)
+static const char *
+mutt_hcache_per_folder(const char *path, const char *folder)
 {
-  int off = sizeof (validate);
-  unsigned int mycrc = 0;
+    static char buf[_POSIX_PATH_MAX];
+    struct stat st;
+    int pos;
 
-  if (!d) {
-    return 0;
-  }
+    if (stat(path, &st) < 0 || !S_ISDIR(st.st_mode)) {
+        return path;
+    }
 
-  restore_int (&mycrc, (unsigned char *) d, &off);
+    pos  = m_strcpy(buf, sizeof(buf), path);
+    pos += m_strputc(buf + pos, sizeof(buf) - pos, '/');
 
-  return (crc == mycrc);
-}
-
-/* Append md5sumed folder to path if path is a directory. */
-static const char *mutt_hcache_per_folder (const char *path,
-                                           const char *folder)
-{
-  static char mutt_hcache_per_folder_path[_POSIX_PATH_MAX];
-  struct stat path_stat;
-  MD5_CTX md5;
-  unsigned char md5sum[16];
-  int ret;
-
-  ret = stat (path, &path_stat);
-  if (ret < 0) {
-    return path;
-  }
-
-  if (!S_ISDIR (path_stat.st_mode)) {
-    return path;
-  }
-
-  MD5Init (&md5);
-  MD5Update (&md5, (unsigned char *) folder, m_strlen(folder));
-  MD5Final (md5sum, &md5);
-
-  ret = snprintf (mutt_hcache_per_folder_path, _POSIX_PATH_MAX,
-                  "%s/%02x%02x%02x%02x%02x%02x%02x%02x"
-                  "%02x%02x%02x%02x%02x%02x%02x%02x",
-                  path, md5sum[0], md5sum[1], md5sum[2], md5sum[3],
-                  md5sum[4], md5sum[5], md5sum[6], md5sum[7], md5sum[8],
-                  md5sum[9], md5sum[10], md5sum[11], md5sum[12],
-                  md5sum[13], md5sum[14], md5sum[15]);
-
-  if (ret <= 0) {
-    return path;
-  }
-
-  return mutt_hcache_per_folder_path;
+    while (*folder) {
+        if (isalnum((unsigned char)*folder) || *folder == '.') {
+            pos += m_strputc(buf + pos, sizeof(buf) - pos, *folder);
+        } else {
+            pos += m_strputc(buf + pos, sizeof(buf) - pos, '_');
+        }
+        folder++;
+    }
+    pos += m_strcpy(buf + pos, sizeof(buf) - pos, ".hdb");
+    return buf;
 }
 
 /* This function transforms a header into a char so that it is useable by
@@ -426,7 +386,7 @@ static const char *mutt_hcache_per_folder (const char *path,
 static void *mutt_hcache_dump (void *_db, HEADER * h, int *off,
                                unsigned long uid_validity)
 {
-  struct header_cache *db = _db;
+  struct hcache_t *db = _db;
   unsigned char *d = NULL;
 
   *off = 0;
@@ -489,255 +449,141 @@ HEADER *mutt_hcache_restore (const unsigned char *d, HEADER ** oh)
   return h;
 }
 
-#if defined(HAVE_QDBM)
-void *
-mutt_hcache_open(const char *path, const char *folder)
-{
-  struct header_cache *h = p_new(struct header_cache, 1);
-  int    flags = VL_OWRITER | VL_OCREAT;
-  h->db = NULL;
-  h->folder = m_strdup(folder);
-  h->crc = generate_crc32();
-
-  if (!path || path[0] == '\0')
-  {
-    p_delete(&h->folder);
-    p_delete(&h);
-    return NULL;
-  }
-
-  path = mutt_hcache_per_folder(path, folder);
-
-  if (option(OPTHCACHECOMPRESS))
-    flags |= VL_OZCOMP;
-
-  h->db = vlopen(path, flags, VL_CMPLEX);
-  if (h->db)
-    return h;
-  else
-  {
-    p_delete(&h->folder);
-    p_delete(&h);
-
-    return NULL;
-  }
-}
-
-void
-mutt_hcache_close(void *db)
-{
-  struct header_cache *h = db;
-
-  if (!h)
-    return;
-
-  vlclose(h->db);
-  p_delete(&h->folder);
-  p_delete(&h);
-}
-
-void *
-mutt_hcache_fetch(void *db, const char *filename,
-                 ssize_t(*keylen) (const char *fn))
-{
-  struct header_cache *h = db;
-  char path[_POSIX_PATH_MAX];
-  int ksize;
-  char *data = NULL;
-
-  if (!h)
-    return NULL;
-
-  m_strcpy(path, sizeof(path), h->folder);
-  m_strcat(path, sizeof(path), filename);
-
-  ksize = strlen(h->folder) + keylen(path + strlen(h->folder));
-
-  data = vlget(h->db, path, ksize, NULL);
-
-  if (!crc32_matches(data, h->crc))
-  {
-    p_delete(&data);
-    return NULL;
-  }
-
-  return data;
-}
-
-int
-mutt_hcache_store(void *db, const char *filename, HEADER * header,
-                 unsigned long uid_validity,
-                 ssize_t(*keylen) (const char *fn))
-{
-  struct header_cache *h = db;
-  char path[_POSIX_PATH_MAX];
-  int ret;
-  int ksize, dsize;
-  char *data = NULL;
-
-  if (!h)
-    return -1;
-
-  m_strcpy(path, sizeof(path), h->folder);
-  m_strcat(path, sizeof(path), filename);
-
-  ksize = strlen(h->folder) + keylen(path + strlen(h->folder));
-
-  data  = mutt_hcache_dump(db, header, &dsize, uid_validity);
-
-  ret = vlput(h->db, path, ksize, data, dsize, VL_DOVER);
-
-  p_delete(&data);
-
-  return ret;
-}
-
-int
-mutt_hcache_delete(void *db, const char *filename,
-                  ssize_t(*keylen) (const char *fn))
+hcache_t *mutt_hcache_open(const char *path, const char *folder)
 {
-  struct header_cache *h = db;
-  char path[_POSIX_PATH_MAX];
-  int ksize;
+    hcache_t *h = p_new(hcache_t, 1);
 
-  if (!h)
-    return -1;
+    h->folder = m_strdup(folder);
+    h->crc = generate_crc32();
 
-  m_strcpy(path, sizeof(path), h->folder);
-  m_strcat(path, sizeof(path), filename);
+    if (m_strisempty(path)) {
+        p_delete(&h->folder);
+        p_delete(&h);
+        return NULL;
+    }
 
-  ksize = strlen(h->folder) + keylen(path + strlen(h->folder));
+    path = mutt_hcache_per_folder(path, folder);
 
-  return vlout(h->db, path, ksize);
-}
+    {
+#if defined(HAVE_QDBM)
+        int flags = VL_OWRITER | VL_OCREAT;
+        if (option(OPTHCACHECOMPRESS))
+            flags |= VL_OZCOMP;
 
+        h->db = vlopen(path, flags, VL_CMPLEX);
 #elif defined(HAVE_GDBM)
+        int pagesize = atoi(HeaderCachePageSize) ?: 16384;
 
-void *mutt_hcache_open (const char *path, const char *folder)
-{
-  struct header_cache *h = p_new(struct header_cache, 1);
-  int pagesize =
-    atoi (HeaderCachePageSize) ? atoi (HeaderCachePageSize) : 16384;
-  h->db = NULL;
-  h->folder = m_strdup(folder);
-  h->crc = generate_crc32 ();
-
-  if (!path || path[0] == '\0') {
-    p_delete(&h->folder);
-    p_delete(&h);
-    return NULL;
-  }
-
-  path = mutt_hcache_per_folder (path, folder);
-
-  h->db = gdbm_open ((char *) path, pagesize, GDBM_WRCREAT, 00600, NULL);
-  if (h->db) {
-    return h;
-  }
+        h->db = gdbm_open((char *) path, pagesize, GDBM_WRCREAT, 00600, NULL);
+#endif
+    }
 
-  /* if rw failed try ro */
-  h->db = gdbm_open ((char *) path, pagesize, GDBM_READER, 00600, NULL);
-  if (h->db) {
+    if (!h->db) {
+        p_delete(&h->folder);
+        p_delete(&h);
+    }
     return h;
-  }
-  else {
-    p_delete(&h->folder);
-    p_delete(&h);
-
-    return NULL;
-  }
 }
 
-void mutt_hcache_close (void *db)
+void mutt_hcache_close(hcache_t **db)
 {
-  struct header_cache *h = db;
+    if (!*db)
+        return;
 
-  if (!h) {
-    return;
-  }
+#if defined(HAVE_QDBM)
+    vlclose((*db)->db);
+#elif defined(HAVE_GDBM)
+    gdbm_close((*db)->db);
+#endif
 
-  gdbm_close (h->db);
-  p_delete(&h->folder);
-  p_delete(&h);
+    p_delete(&(*db)->folder);
+    p_delete(db);
 }
 
-void *mutt_hcache_fetch (void *db, const char *filename,
-                         ssize_t (*keylen) (const char *fn))
+void *mutt_hcache_fetch(hcache_t *db, const char *filename,
+                        ssize_t (*keylen)(const char *fn))
 {
-  struct header_cache *h = db;
-  datum key;
-  datum data;
-  char path[_POSIX_PATH_MAX];
+    char path[_POSIX_PATH_MAX];
+    void *data = NULL;
 
-  if (!h) {
-    return NULL;
-  }
+    if (!db)
+        return NULL;
+
+    snprintf(path, sizeof(path), "%s%s", db->folder, filename);
 
-  m_strcpy(path, sizeof(path), h->folder);
-  strncat (path, filename, sizeof (path) - m_strlen(path));
+    {
+#if defined(HAVE_QDBM)
+        int ksize = strlen(db->folder) + keylen(path + strlen(db->folder));
+        data  = vlget(db->db, path, ksize, NULL);
+#elif defined(HAVE_GDBM)
+        datum k = { .dptr = path, .dsize = keylen(path) };
 
-  key.dptr = path;
-  key.dsize = keylen (path);
+        data = gdbm_fetch(db->db, k).dtpr;
+#endif
+    }
 
-  data = gdbm_fetch (h->db, key);
+    if (data) {
+        int off = sizeof(validate);
+        unsigned crc = 0;
 
-  if (!crc32_matches (data.dptr, h->crc)) {
-    p_delete(&data.dptr);
-    return NULL;
-  }
+        restore_int(&crc, data, &off);
+        if (crc != db->crc)
+            p_delete(&data);
+    }
 
-  return data.dptr;
+    return data;
 }
 
-int
-mutt_hcache_store (void *db, const char *filename, HEADER * header,
-                   unsigned long uid_validity, ssize_t (*keylen) (const char *fn))
+int mutt_hcache_store(hcache_t *db, const char *filename, HEADER *header,
+                      unsigned long uid_validity,
+                      ssize_t (*keylen)(const char *fn))
 {
-  struct header_cache *h = db;
-  datum key;
-  datum data;
-  char path[_POSIX_PATH_MAX];
-  int ret;
-
-  if (!h) {
-    return -1;
-  }
+    char path[_POSIX_PATH_MAX];
+    int ret, dsize;
+    void *data = NULL;
 
-  m_strcpy(path, sizeof(path), h->folder);
-  strncat (path, filename, sizeof (path) - m_strlen(path));
+    if (!db)
+        return -1;
 
-  key.dptr = path;
-  key.dsize = keylen (path);
+    snprintf(path, sizeof(path), "%s%s", db->folder, filename);
+    data = mutt_hcache_dump(db, header, &dsize, uid_validity);
 
-  data.dptr = mutt_hcache_dump (db, header, &data.dsize, uid_validity);
+    {
+#if defined(HAVE_QDBM)
+        int ksize = strlen(db->folder) + keylen(path + strlen(db->folder));
 
-  ret = gdbm_store (h->db, key, data, GDBM_REPLACE);
+        ret = vlput(db->db, path, ksize, data, dsize, VL_DOVER);
+#elif defined(HAVE_GDBM)
+        datum k = { .dptr = path, .dsize = keylen(path) };
+        datum v = { .dptr = data, .dsize = dsize };
 
-  p_delete(&data.dptr);
+        ret = gdbm_store (db->db, k, v, GDBM_REPLACE);
+#endif
+    }
 
-  return ret;
+    p_delete(&data);
+    return ret;
 }
 
-int
-mutt_hcache_delete (void *db, const char *filename,
-                    ssize_t (*keylen) (const char *fn))
+int mutt_hcache_delete(hcache_t *db, const char *filename,
+                       ssize_t (*keylen)(const char *fn))
 {
-  datum key;
-  struct header_cache *h = db;
-  char path[_POSIX_PATH_MAX];
+    char path[_POSIX_PATH_MAX];
 
-  if (!h) {
-    return -1;
-  }
+    if (!db)
+        return -1;
 
-  m_strcpy(path, sizeof(path), h->folder);
-  strncat (path, filename, sizeof (path) - m_strlen(path));
+    snprintf(path, sizeof(path), "%s%s", db->folder, filename);
 
-  key.dptr = path;
-  key.dsize = keylen (path);
-
-  return gdbm_delete (h->db, key);
-}
+    {
+#if defined(HAVE_QDBM)
+        int ksize = strlen(db->folder) + keylen(path + strlen(db->folder));
+        return vlout(db->db, path, ksize);
+#elif defined(HAVE_GDBM)
+        datum k = { .dptr = path, .dsize = keylen(path) };
+        return gdbm_delete(db->db, k);
 #endif
+    }
+}
 
 #endif /* USE_HCACHE */