2005-01-14 [colin] 0.9.13cvs33
[claws.git] / src / msgcache.c
index f9fb46671c44ea44ebce3231cc657d877671cca3..f47a951b2bff98faa651473f77fdfb25cdff3b56 100644 (file)
@@ -27,6 +27,7 @@
 #include "msgcache.h"
 #include "utils.h"
 #include "procmsg.h"
+#include "codeconv.h"
 
 typedef enum
 {
@@ -42,6 +43,25 @@ struct _MsgCache {
        time_t           last_access;
 };
 
+typedef struct _StringConverter StringConverter;
+struct _StringConverter {
+       gchar *(*convert) (StringConverter *converter, gchar *srcstr);
+       void   (*free)    (StringConverter *converter);
+};
+
+typedef struct _StrdupConverter StrdupConverter;
+struct _StrdupConverter {
+       StringConverter converter;
+};
+
+typedef struct _CharsetConverter CharsetConverter;
+struct _CharsetConverter {
+       StringConverter converter;
+
+       gchar *srccharset;
+       gchar *dstcharset;
+};
+
 MsgCache *msgcache_new(void)
 {
        MsgCache *cache;
@@ -116,14 +136,13 @@ void msgcache_update_msg(MsgCache *cache, MsgInfo *msginfo)
        g_return_if_fail(msginfo != NULL);
 
        oldmsginfo = g_hash_table_lookup(cache->msgnum_table, &msginfo->msgnum);
-       if(oldmsginfo && oldmsginfo->msgid) {
+       if (oldmsginfo && oldmsginfo->msgid)
                g_hash_table_remove(cache->msgid_table, oldmsginfo->msgid);
+       if (oldmsginfo) {
                g_hash_table_remove(cache->msgnum_table, &oldmsginfo->msgnum);
-       } 
-       if (oldmsginfo)
+               cache->memusage -= procmsg_msginfo_memusage(oldmsginfo);
                procmsg_msginfo_free(oldmsginfo);
-
-       cache->memusage -= procmsg_msginfo_memusage(oldmsginfo);
+       }
 
        newmsginfo = procmsg_msginfo_new_ref(msginfo);
        g_hash_table_insert(cache->msgnum_table, &newmsginfo->msgnum, newmsginfo);
@@ -208,7 +227,7 @@ gint msgcache_get_memory_usage(MsgCache *cache)
 
 #define READ_CACHE_DATA(data, fp) \
 { \
-       if (msgcache_read_cache_data_str(fp, &data) < 0) { \
+       if (msgcache_read_cache_data_str(fp, &data, conv) < 0) { \
                procmsg_msginfo_free(msginfo); \
                error = TRUE; \
                break; \
@@ -218,9 +237,11 @@ gint msgcache_get_memory_usage(MsgCache *cache)
 #define READ_CACHE_DATA_INT(n, fp) \
 { \
        guint32 idata; \
+       size_t ni; \
  \
-       if (fread(&idata, sizeof(idata), 1, fp) != 1) { \
-               g_warning("Cache data is corrupted\n"); \
+       if ((ni = fread(&idata, 1, sizeof(idata), fp)) != sizeof(idata)) { \
+               g_warning("read_int: Cache data corrupted, read %d of %d at " \
+                         "offset %d\n", ni, sizeof(idata), ftell(fp)); \
                procmsg_msginfo_free(msginfo); \
                error = TRUE; \
                break; \
@@ -303,46 +324,63 @@ static FILE *msgcache_open_data_file(const gchar *file, gint version,
        return fp;
 }
 
-static gint msgcache_read_cache_data_str(FILE *fp, gchar **str)
+static gint msgcache_read_cache_data_str(FILE *fp, gchar **str, 
+                                        StringConverter *conv)
 {
-       gchar buf[BUFFSIZE];
-       gint ret = 0;
+       gchar *tmpstr = NULL;
+       size_t ni;
        guint32 len;
 
-       if (fread(&len, sizeof(len), 1, fp) == 1) {
-               if (len > G_MAXINT)
-                       ret = -1;
-               else {
-                       gchar *tmp = NULL;
-
-                       while (len > 0) {
-                               size_t size = MIN(len, BUFFSIZE - 1);
-
-                               if (fread(buf, size, 1, fp) != 1) {
-                                       ret = -1;
-                                       if (tmp) g_free(tmp);
-                                       *str = NULL;
-                                       break;
-                               }
-
-                               buf[size] = '\0';
-                               if (tmp) {
-                                       *str = g_strconcat(tmp, buf, NULL);
-                                       g_free(tmp);
-                                       tmp = *str;
-                               } else
-                                       tmp = *str = g_strdup(buf);
-
-                               len -= size;
-                       }
-               }
-       } else
-               ret = -1;
+       *str = NULL;
+       if ((ni = fread(&len, 1, sizeof(len), fp) != sizeof(len)) ||
+           len > G_MAXINT) {
+               g_warning("read_data_str: Cache data (len) corrupted, read %d "
+                         "of %d bytes at offset %d\n", ni, sizeof(len), 
+                         ftell(fp));
+               return -1;
+       }
+
+       if (len == 0)
+               return 0;
+
+       tmpstr = g_malloc(len + 1);
+
+       if ((ni = fread(tmpstr, 1, len, fp)) != len) {
+               g_warning("read_data_str: Cache data corrupted, read %d of %d "
+                         "bytes at offset %d\n", 
+                         ni, len, ftell(fp));
+               g_free(tmpstr);
+               return -1;
+       }
+       tmpstr[len] = 0;
 
-       if (ret < 0)
-               g_warning("Cache data is corrupted\n");
+       if (conv != NULL) {
+               *str = conv->convert(conv, tmpstr);
+               g_free(tmpstr);
+       } else 
+               *str = tmpstr;
 
-       return ret;
+       return 0;
+}
+
+gchar *strconv_strdup_convert(StringConverter *conv, gchar *srcstr)
+{
+       return g_strdup(srcstr);
+}
+
+gchar *strconv_charset_convert(StringConverter *conv, gchar *srcstr)
+{
+       CharsetConverter *charsetconv = (CharsetConverter *) conv;
+
+       return conv_codeset_strdup(srcstr, charsetconv->srccharset, charsetconv->dstcharset);
+}
+
+void strconv_charset_free(StringConverter *conv)
+{
+       CharsetConverter *charsetconv = (CharsetConverter *) conv;
+
+       g_free(charsetconv->srccharset);
+       g_free(charsetconv->dstcharset);
 }
 
 MsgCache *msgcache_read_cache(FolderItem *item, const gchar *cache_file)
@@ -354,6 +392,9 @@ MsgCache *msgcache_read_cache(FolderItem *item, const gchar *cache_file)
        gchar file_buf[BUFFSIZE];
        guint num;
        gboolean error = FALSE;
+       StringConverter *conv = NULL;
+       gchar *srccharset = NULL;
+       const gchar *dstcharset = NULL;
 
        g_return_val_if_fail(cache_file != NULL, NULL);
        g_return_val_if_fail(item != NULL, NULL);
@@ -370,8 +411,37 @@ MsgCache *msgcache_read_cache(FolderItem *item, const gchar *cache_file)
                tmp_flags |= MSG_DRAFT;
        }
 
-       cache = msgcache_new();
+       if (msgcache_read_cache_data_str(fp, &srccharset, NULL) < 0)
+               return NULL;
+       dstcharset = conv_get_current_charset_str();
+       if (srccharset == NULL || dstcharset == NULL) {
+               conv = NULL;
+       } else if (strcmp(srccharset, dstcharset) == 0) {
+               StrdupConverter *strdupconv;
+
+               debug_print("using StrdupConverter\n");
+
+               strdupconv = g_new0(StrdupConverter, 1);
+               strdupconv->converter.convert = strconv_strdup_convert;
+               strdupconv->converter.free = NULL;
 
+               conv = (StringConverter *) strdupconv;
+       } else {
+               CharsetConverter *charsetconv;
+
+               debug_print("using CharsetConverter\n");
+
+               charsetconv = g_new0(CharsetConverter, 1);
+               charsetconv->converter.convert = strconv_charset_convert;
+               charsetconv->converter.free = strconv_charset_free;
+               charsetconv->srccharset = g_strdup(srccharset);
+               charsetconv->dstcharset = g_strdup(dstcharset);
+
+               conv = (StringConverter *) charsetconv;
+       }
+       g_free(srccharset);
+
+       cache = msgcache_new();
        g_hash_table_freeze(cache->msgnum_table);
 
        while (fread(&num, sizeof(num), 1, fp) == 1) {
@@ -395,6 +465,7 @@ MsgCache *msgcache_read_cache(FolderItem *item, const gchar *cache_file)
                READ_CACHE_DATA(msginfo->references, fp);
                READ_CACHE_DATA(msginfo->xref, fp);
                READ_CACHE_DATA_INT(msginfo->planned_download, fp);
+               READ_CACHE_DATA_INT(msginfo->total_size, fp);
 
                msginfo->folder = item;
                msginfo->flags.tmp_flags |= tmp_flags;
@@ -407,7 +478,13 @@ MsgCache *msgcache_read_cache(FolderItem *item, const gchar *cache_file)
        fclose(fp);
        g_hash_table_thaw(cache->msgnum_table);
 
-       if(error) {
+       if (conv != NULL) {
+               if (conv->free != NULL)
+                       conv->free(conv);
+               g_free(conv);
+       }
+
+       if (error) {
                msgcache_destroy(cache);
                return NULL;
        }
@@ -466,6 +543,7 @@ void msgcache_write_cache(MsgInfo *msginfo, FILE *fp)
        WRITE_CACHE_DATA(msginfo->references, fp);
        WRITE_CACHE_DATA(msginfo->xref, fp);
        WRITE_CACHE_DATA_INT(msginfo->planned_download, fp);
+       WRITE_CACHE_DATA_INT(msginfo->total_size, fp);
 }
 
 static void msgcache_write_flags(MsgInfo *msginfo, FILE *fp)
@@ -507,6 +585,8 @@ gint msgcache_write(const gchar *cache_file, const gchar *mark_file, MsgCache *c
        if (write_fps.cache_fp == NULL)
                return -1;
 
+       WRITE_CACHE_DATA(conv_get_current_charset_str(), write_fps.cache_fp);
+
        write_fps.mark_fp = msgcache_open_data_file(mark_file, MARK_VERSION,
                DATA_WRITE, NULL, 0);
        if (write_fps.mark_fp == NULL) {