#include "msgcache.h"
#include "utils.h"
#include "procmsg.h"
+#include "codeconv.h"
typedef enum
{
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;
g_return_if_fail(msginfo != NULL);
oldmsginfo = g_hash_table_lookup(cache->msgnum_table, &msginfo->msgnum);
- if(msginfo) {
+ if (oldmsginfo && oldmsginfo->msgid)
g_hash_table_remove(cache->msgid_table, oldmsginfo->msgid);
+ if (oldmsginfo) {
g_hash_table_remove(cache->msgnum_table, &oldmsginfo->msgnum);
+ 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);
#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; \
#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; \
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;
- if (ret < 0)
- g_warning("Cache data is corrupted\n");
+ tmpstr = g_malloc(len + 1);
- return ret;
+ 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 (conv != NULL) {
+ *str = conv->convert(conv, tmpstr);
+ g_free(tmpstr);
+ } else
+ *str = tmpstr;
+
+ 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)
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);
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) {
READ_CACHE_DATA(msginfo->inreplyto, fp);
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;
cache->memusage += procmsg_msginfo_memusage(msginfo);
}
fclose(fp);
+ g_hash_table_thaw(cache->msgnum_table);
+
+ if (conv != NULL) {
+ if (conv->free != NULL)
+ conv->free(conv);
+ g_free(conv);
+ }
- if(error) {
- g_hash_table_thaw(cache->msgnum_table);
+ if (error) {
msgcache_destroy(cache);
return NULL;
}
cache->last_access = time(NULL);
- g_hash_table_thaw(cache->msgnum_table);
debug_print("done. (%d items read)\n", g_hash_table_size(cache->msgnum_table));
debug_print("Cache size: %d messages, %d byte\n", g_hash_table_size(cache->msgnum_table), cache->memusage);
WRITE_CACHE_DATA(msginfo->inreplyto, 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)
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) {