X-Git-Url: http://git.claws-mail.org/?p=claws.git;a=blobdiff_plain;f=src%2Fmsgcache.c;h=0a3c956744012449ee52cea557fe5c33029c61db;hp=2d4b696d46800773e61d0536e238e2137e7c7e03;hb=b0a0f2a281e4a86924158062878a4afbbac6eed6;hpb=a2f603ea34417c8cc20515bb70e8d49e49052c7e diff --git a/src/msgcache.c b/src/msgcache.c index 2d4b696d4..0a3c95674 100644 --- a/src/msgcache.c +++ b/src/msgcache.c @@ -28,18 +28,27 @@ #include "utils.h" #include "procmsg.h" +typedef enum +{ + DATA_READ, + DATA_WRITE, + DATA_APPEND +} DataOpenMode; + struct _MsgCache { GHashTable *msgnum_table; + GHashTable *msgid_table; guint memusage; time_t last_access; }; -MsgCache *msgcache_new() +MsgCache *msgcache_new(void) { MsgCache *cache; cache = g_new0(MsgCache, 1), - cache->msgnum_table = g_hash_table_new(NULL, NULL); + cache->msgnum_table = g_hash_table_new(g_int_hash, g_int_equal); + cache->msgid_table = g_hash_table_new(g_str_hash, g_str_equal); cache->last_access = time(NULL); return cache; @@ -56,6 +65,7 @@ void msgcache_destroy(MsgCache *cache) g_return_if_fail(cache != NULL); g_hash_table_foreach_remove(cache->msgnum_table, msgcache_msginfo_free_func, NULL); + g_hash_table_destroy(cache->msgid_table); g_hash_table_destroy(cache->msgnum_table); g_free(cache); } @@ -68,11 +78,13 @@ void msgcache_add_msg(MsgCache *cache, MsgInfo *msginfo) g_return_if_fail(msginfo != NULL); newmsginfo = procmsg_msginfo_new_ref(msginfo); - g_hash_table_insert(cache->msgnum_table, GINT_TO_POINTER(msginfo->msgnum), newmsginfo); + g_hash_table_insert(cache->msgnum_table, &newmsginfo->msgnum, newmsginfo); + if(newmsginfo->msgid != NULL) + g_hash_table_insert(cache->msgid_table, newmsginfo->msgid, newmsginfo); cache->memusage += procmsg_msginfo_memusage(msginfo); cache->last_access = time(NULL); - debug_print(_("Cache size: %d messages, %d byte\n"), g_hash_table_size(cache->msgnum_table), cache->memusage); + debug_print("Cache size: %d messages, %d bytes\n", g_hash_table_size(cache->msgnum_table), cache->memusage); } void msgcache_remove_msg(MsgCache *cache, guint msgnum) @@ -82,16 +94,18 @@ void msgcache_remove_msg(MsgCache *cache, guint msgnum) g_return_if_fail(cache != NULL); g_return_if_fail(msgnum > 0); - msginfo = (MsgInfo *) g_hash_table_lookup(cache->msgnum_table, GINT_TO_POINTER(msgnum)); + msginfo = (MsgInfo *) g_hash_table_lookup(cache->msgnum_table, &msgnum); if(!msginfo) return; cache->memusage -= procmsg_msginfo_memusage(msginfo); + if(msginfo->msgid) + g_hash_table_remove(cache->msgid_table, msginfo->msgid); + g_hash_table_remove(cache->msgnum_table, &msginfo->msgnum); procmsg_msginfo_free(msginfo); - g_hash_table_remove(cache->msgnum_table, GINT_TO_POINTER(msgnum)); cache->last_access = time(NULL); - debug_print(_("Cache size: %d messages, %d byte\n"), g_hash_table_size(cache->msgnum_table), cache->memusage); + debug_print("Cache size: %d messages, %d byte\n", g_hash_table_size(cache->msgnum_table), cache->memusage); } void msgcache_update_msg(MsgCache *cache, MsgInfo *msginfo) @@ -101,31 +115,200 @@ void msgcache_update_msg(MsgCache *cache, MsgInfo *msginfo) g_return_if_fail(cache != NULL); g_return_if_fail(msginfo != NULL); - oldmsginfo = g_hash_table_lookup(cache->msgnum_table, GINT_TO_POINTER(msginfo->msgnum)); + oldmsginfo = g_hash_table_lookup(cache->msgnum_table, &msginfo->msgnum); if(msginfo) { - g_hash_table_remove(cache->msgnum_table, GINT_TO_POINTER(oldmsginfo->msgnum)); + g_hash_table_remove(cache->msgid_table, oldmsginfo->msgid); + g_hash_table_remove(cache->msgnum_table, &oldmsginfo->msgnum); procmsg_msginfo_free(oldmsginfo); } cache->memusage -= procmsg_msginfo_memusage(oldmsginfo); newmsginfo = procmsg_msginfo_new_ref(msginfo); - g_hash_table_insert(cache->msgnum_table, GINT_TO_POINTER(msginfo->msgnum), newmsginfo); + g_hash_table_insert(cache->msgnum_table, &newmsginfo->msgnum, newmsginfo); + if(newmsginfo->msgid) + g_hash_table_insert(cache->msgid_table, newmsginfo->msgid, newmsginfo); cache->memusage += procmsg_msginfo_memusage(newmsginfo); cache->last_access = time(NULL); - debug_print(_("Cache size: %d messages, %d byte\n"), g_hash_table_size(cache->msgnum_table), cache->memusage); + debug_print("Cache size: %d messages, %d byte\n", g_hash_table_size(cache->msgnum_table), cache->memusage); return; } +MsgInfo *msgcache_get_msg(MsgCache *cache, guint num) +{ + MsgInfo *msginfo; + + g_return_val_if_fail(cache != NULL, NULL); + + msginfo = g_hash_table_lookup(cache->msgnum_table, &num); + if(!msginfo) + return NULL; + cache->last_access = time(NULL); + + return procmsg_msginfo_new_ref(msginfo); +} + +MsgInfo *msgcache_get_msg_by_id(MsgCache *cache, const gchar *msgid) +{ + MsgInfo *msginfo; + + g_return_val_if_fail(cache != NULL, NULL); + g_return_val_if_fail(msgid != NULL, NULL); + + msginfo = g_hash_table_lookup(cache->msgid_table, msgid); + if(!msginfo) + return NULL; + cache->last_access = time(NULL); + + return procmsg_msginfo_new_ref(msginfo); +} + +static void msgcache_get_msg_list_func(gpointer key, gpointer value, gpointer user_data) +{ + MsgInfoList **listptr = user_data; + MsgInfo *msginfo = value; + + *listptr = g_slist_prepend(*listptr, procmsg_msginfo_new_ref(msginfo)); +} + +MsgInfoList *msgcache_get_msg_list(MsgCache *cache) +{ + MsgInfoList *msg_list = NULL; + + g_return_val_if_fail(cache != NULL, NULL); + + g_hash_table_foreach((GHashTable *)cache->msgnum_table, msgcache_get_msg_list_func, (gpointer)&msg_list); + cache->last_access = time(NULL); + + msg_list = g_slist_reverse(msg_list); + + return msg_list; +} + +time_t msgcache_get_last_access_time(MsgCache *cache) +{ + g_return_val_if_fail(cache != NULL, 0); + + return cache->last_access; +} + +gint msgcache_get_memory_usage(MsgCache *cache) +{ + g_return_val_if_fail(cache != NULL, 0); + + return cache->memusage; +} + +/* + * Cache saving functions + */ + +#define READ_CACHE_DATA(data, fp) \ +{ \ + if (msgcache_read_cache_data_str(fp, &data) < 0) { \ + procmsg_msginfo_free(msginfo); \ + error = TRUE; \ + break; \ + } \ +} + +#define READ_CACHE_DATA_INT(n, fp) \ +{ \ + guint32 idata; \ + \ + if (fread(&idata, sizeof(idata), 1, fp) != 1) { \ + g_warning("Cache data is corrupted\n"); \ + procmsg_msginfo_free(msginfo); \ + error = TRUE; \ + break; \ + } else \ + n = idata;\ +} + +#define WRITE_CACHE_DATA_INT(n, fp) \ +{ \ + guint32 idata; \ + \ + idata = (guint32)n; \ + fwrite(&idata, sizeof(idata), 1, fp); \ +} + +#define WRITE_CACHE_DATA(data, fp) \ +{ \ + size_t len; \ + if (data == NULL) \ + len = 0; \ + else \ + len = strlen(data); \ + WRITE_CACHE_DATA_INT(len, fp); \ + if (len > 0) { \ + fwrite(data, len, 1, fp); \ + } \ +} + +static FILE *msgcache_open_data_file(const gchar *file, gint version, + DataOpenMode mode, + gchar *buf, size_t buf_size) +{ + FILE *fp; + gint data_ver; + + g_return_val_if_fail(file != NULL, NULL); + + if (mode == DATA_WRITE) { + if ((fp = fopen(file, "wb")) == NULL) { + FILE_OP_ERROR(file, "fopen"); + return NULL; + } + if (change_file_mode_rw(fp, file) < 0) + FILE_OP_ERROR(file, "chmod"); + + WRITE_CACHE_DATA_INT(version, fp); + return fp; + } + + /* check version */ + if ((fp = fopen(file, "rb")) == NULL) + debug_print("Mark/Cache file not found\n"); + else { + if (buf && buf_size > 0) + setvbuf(fp, buf, _IOFBF, buf_size); + if (fread(&data_ver, sizeof(data_ver), 1, fp) != 1 || + version != data_ver) { + debug_print("Mark/Cache version is different (%d != %d). " + "Discarding it.\n", data_ver, version); + fclose(fp); + fp = NULL; + } + } + + if (mode == DATA_READ) + return fp; + + if (fp) { + /* reopen with append mode */ + fclose(fp); + if ((fp = fopen(file, "ab")) == NULL) + FILE_OP_ERROR(file, "fopen"); + } else { + /* open with overwrite mode if mark file doesn't exist or + version is different */ + fp = msgcache_open_data_file(file, version, DATA_WRITE, buf, + buf_size); + } + + return fp; +} + static gint msgcache_read_cache_data_str(FILE *fp, gchar **str) { gchar buf[BUFFSIZE]; gint ret = 0; - size_t len; + guint32 len; if (fread(&len, sizeof(len), 1, fp) == 1) { - if (len < 0) + if (len > G_MAXINT) ret = -1; else { gchar *tmp = NULL; @@ -155,59 +338,34 @@ static gint msgcache_read_cache_data_str(FILE *fp, gchar **str) ret = -1; if (ret < 0) - g_warning(_("Cache data is corrupted\n")); + g_warning("Cache data is corrupted\n"); return ret; } - -#define READ_CACHE_DATA(data, fp) \ -{ \ - if (msgcache_read_cache_data_str(fp, &data) < 0) { \ - procmsg_msginfo_free(msginfo); \ - error = TRUE; \ - break; \ - } \ -} - -#define READ_CACHE_DATA_INT(n, fp) \ -{ \ - if (fread(&n, sizeof(n), 1, fp) != 1) { \ - g_warning(_("Cache data is corrupted\n")); \ - procmsg_msginfo_free(msginfo); \ - error = TRUE; \ - break; \ - } \ -} - MsgCache *msgcache_read_cache(FolderItem *item, const gchar *cache_file) { MsgCache *cache; FILE *fp; MsgInfo *msginfo; -/* MsgFlags default_flags; */ + MsgTmpFlags tmp_flags = 0; gchar file_buf[BUFFSIZE]; - gint ver; guint num; gboolean error = FALSE; g_return_val_if_fail(cache_file != NULL, NULL); g_return_val_if_fail(item != NULL, NULL); - if ((fp = fopen(cache_file, "rb")) == NULL) { - debug_print(_("\tNo cache file\n")); + if ((fp = msgcache_open_data_file + (cache_file, CACHE_VERSION, DATA_READ, file_buf, sizeof(file_buf))) == NULL) return NULL; - } - setvbuf(fp, file_buf, _IOFBF, sizeof(file_buf)); - debug_print(_("\tReading message cache from %s...\n"), cache_file); + debug_print("\tReading message cache from %s...\n", cache_file); - /* compare cache version */ - if (fread(&ver, sizeof(ver), 1, fp) != 1 || - CACHE_VERSION != ver) { - debug_print(_("Cache version is different. Discarding it.\n")); - fclose(fp); - return NULL; + if (item->stype == F_QUEUE) { + tmp_flags |= MSG_QUEUED; + } else if (item->stype == F_DRAFT) { + tmp_flags |= MSG_DRAFT; } cache = msgcache_new(); @@ -235,13 +393,12 @@ MsgCache *msgcache_read_cache(FolderItem *item, const gchar *cache_file) READ_CACHE_DATA(msginfo->references, fp); READ_CACHE_DATA(msginfo->xref, fp); -/* - MSG_SET_PERM_FLAGS(msginfo->flags, default_flags.perm_flags); - MSG_SET_TMP_FLAGS(msginfo->flags, default_flags.tmp_flags); -*/ msginfo->folder = item; + msginfo->flags.tmp_flags |= tmp_flags; - g_hash_table_insert(cache->msgnum_table, GINT_TO_POINTER(msginfo->msgnum), msginfo); + g_hash_table_insert(cache->msgnum_table, &msginfo->msgnum, msginfo); + if(msginfo->msgid) + g_hash_table_insert(cache->msgid_table, msginfo->msgid, msginfo); cache->memusage += procmsg_msginfo_memusage(msginfo); } fclose(fp); @@ -255,8 +412,8 @@ MsgCache *msgcache_read_cache(FolderItem *item, const gchar *cache_file) 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); + 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); return cache; } @@ -266,47 +423,24 @@ void msgcache_read_mark(MsgCache *cache, const gchar *mark_file) FILE *fp; MsgInfo *msginfo; MsgPermFlags perm_flags; - gint ver; guint num; - if ((fp = fopen(mark_file, "rb")) == NULL) { - debug_print(_("Mark file not found.\n")); + if ((fp = msgcache_open_data_file(mark_file, MARK_VERSION, DATA_READ, NULL, 0)) == NULL) return; - } else if (fread(&ver, sizeof(ver), 1, fp) != 1 || MARK_VERSION != ver) { - debug_print(_("Mark version is different (%d != %d). " - "Discarding it.\n"), ver, MARK_VERSION); - } else { - debug_print(_("\tReading message marks from %s...\n"), mark_file); - while (fread(&num, sizeof(num), 1, fp) == 1) { - if (fread(&perm_flags, sizeof(perm_flags), 1, fp) != 1) break; + debug_print("\tReading message marks from %s...\n", mark_file); - msginfo = g_hash_table_lookup(cache->msgnum_table, GUINT_TO_POINTER(num)); - if(msginfo) { - msginfo->flags.perm_flags = perm_flags; - } + while (fread(&num, sizeof(num), 1, fp) == 1) { + if (fread(&perm_flags, sizeof(perm_flags), 1, fp) != 1) break; + + msginfo = g_hash_table_lookup(cache->msgnum_table, &num); + if(msginfo) { + msginfo->flags.perm_flags = perm_flags; } } fclose(fp); } -#define WRITE_CACHE_DATA_INT(n, fp) \ - fwrite(&n, sizeof(n), 1, fp) - -#define WRITE_CACHE_DATA(data, fp) \ -{ \ - gint len; \ - \ - if (data == NULL || (len = strlen(data)) == 0) { \ - len = 0; \ - WRITE_CACHE_DATA_INT(len, fp); \ - } else { \ - len = strlen(data); \ - WRITE_CACHE_DATA_INT(len, fp); \ - fwrite(data, len, 1, fp); \ - } \ -} - void msgcache_write_cache(MsgInfo *msginfo, FILE *fp) { MsgTmpFlags flags = msginfo->flags.tmp_flags & MSG_CACHED_FLAG_MASK; @@ -349,7 +483,7 @@ static void msgcache_write_func(gpointer key, gpointer value, gpointer user_data { MsgInfo *msginfo; struct write_fps *write_fps; - + msginfo = (MsgInfo *)value; write_fps = user_data; @@ -359,36 +493,28 @@ static void msgcache_write_func(gpointer key, gpointer value, gpointer user_data gint msgcache_write(const gchar *cache_file, const gchar *mark_file, MsgCache *cache) { - FILE *fp; struct write_fps write_fps; - gint ver; g_return_val_if_fail(cache_file != NULL, -1); g_return_val_if_fail(mark_file != NULL, -1); g_return_val_if_fail(cache != NULL, -1); - debug_print(_("\tWriting message cache to %s and %s...\n"), cache_file, mark_file); - - if ((fp = fopen(cache_file, "wb")) == NULL) { - FILE_OP_ERROR(cache_file, "fopen"); + write_fps.cache_fp = msgcache_open_data_file(cache_file, CACHE_VERSION, + DATA_WRITE, NULL, 0); + if (write_fps.cache_fp == NULL) return -1; - } - if (change_file_mode_rw(fp, cache_file) < 0) - FILE_OP_ERROR(cache_file, "chmod"); - - ver = CACHE_VERSION; - WRITE_CACHE_DATA_INT(ver, fp); - write_fps.cache_fp = fp; - if ((fp = fopen(mark_file, "wb")) == NULL) { - FILE_OP_ERROR(mark_file, "fopen"); + write_fps.mark_fp = msgcache_open_data_file(mark_file, MARK_VERSION, + DATA_WRITE, NULL, 0); + if (write_fps.mark_fp == NULL) { fclose(write_fps.cache_fp); return -1; } - ver = MARK_VERSION; - WRITE_CACHE_DATA_INT(ver, fp); - write_fps.mark_fp = fp; + debug_print("\tWriting message cache to %s and %s...\n", cache_file, mark_file); + + if (change_file_mode_rw(write_fps.cache_fp, cache_file) < 0) + FILE_OP_ERROR(cache_file, "chmod"); g_hash_table_foreach(cache->msgnum_table, msgcache_write_func, (gpointer)&write_fps); @@ -397,53 +523,7 @@ gint msgcache_write(const gchar *cache_file, const gchar *mark_file, MsgCache *c cache->last_access = time(NULL); - debug_print(_("done.\n")); -} - -MsgInfo *msgcache_get_msg(MsgCache *cache, guint num) -{ - MsgInfo *msginfo; - - g_return_val_if_fail(cache != NULL, NULL); - - msginfo = g_hash_table_lookup(cache->msgnum_table, GINT_TO_POINTER(num)); - if(!msginfo) - return NULL; - cache->last_access = time(NULL); - - return procmsg_msginfo_new_ref(msginfo); -} - -static void msgcache_get_msg_list_func(gpointer key, gpointer value, gpointer user_data) -{ - GSList **listptr = user_data; - MsgInfo *msginfo = value; - - *listptr = g_slist_prepend(*listptr, procmsg_msginfo_new_ref(msginfo)); -} - -GSList *msgcache_get_msg_list(MsgCache *cache) -{ - GSList *msg_list = NULL; - - g_return_val_if_fail(cache != NULL, NULL); - - g_hash_table_foreach((GHashTable *)cache->msgnum_table, msgcache_get_msg_list_func, (gpointer)&msg_list); - cache->last_access = time(NULL); - - return msg_list; -} - -time_t msgcache_get_last_access_time(MsgCache *cache) -{ - g_return_val_if_fail(cache != NULL, 0); - - return cache->last_access; + debug_print("done.\n"); + return 0; } -gint msgcache_get_memory_usage(MsgCache *cache) -{ - g_return_val_if_fail(cache != NULL, 0); - - return cache->memusage; -}