2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2001 Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 GHashTable *msgnum_table;
37 MsgCache *msgcache_new()
41 cache = g_new0(MsgCache, 1),
42 cache->msgnum_table = g_hash_table_new(NULL, NULL);
43 cache->last_access = time(NULL);
48 static gboolean msgcache_msginfo_free_func(gpointer num, gpointer msginfo, gpointer user_data)
50 procmsg_msginfo_free((MsgInfo *)msginfo);
54 void msgcache_destroy(MsgCache *cache)
56 g_return_if_fail(cache != NULL);
58 g_hash_table_foreach_remove(cache->msgnum_table, msgcache_msginfo_free_func, NULL);
59 g_hash_table_destroy(cache->msgnum_table);
63 void msgcache_add_msg(MsgCache *cache, MsgInfo *msginfo)
67 g_return_if_fail(cache != NULL);
68 g_return_if_fail(msginfo != NULL);
70 newmsginfo = procmsg_msginfo_new_ref(msginfo);
71 g_hash_table_insert(cache->msgnum_table, GINT_TO_POINTER(msginfo->msgnum), newmsginfo);
72 cache->memusage += procmsg_msginfo_memusage(msginfo);
73 cache->last_access = time(NULL);
75 debug_print(_("Cache size: %d messages, %d byte\n"), g_hash_table_size(cache->msgnum_table), cache->memusage);
78 void msgcache_remove_msg(MsgCache *cache, guint msgnum)
82 g_return_if_fail(cache != NULL);
83 g_return_if_fail(msgnum > 0);
85 msginfo = (MsgInfo *) g_hash_table_lookup(cache->msgnum_table, GINT_TO_POINTER(msgnum));
89 cache->memusage -= procmsg_msginfo_memusage(msginfo);
90 procmsg_msginfo_free(msginfo);
91 g_hash_table_remove(cache->msgnum_table, GINT_TO_POINTER(msgnum));
92 cache->last_access = time(NULL);
94 debug_print(_("Cache size: %d messages, %d byte\n"), g_hash_table_size(cache->msgnum_table), cache->memusage);
97 void msgcache_update_msg(MsgCache *cache, MsgInfo *msginfo)
99 MsgInfo *oldmsginfo, *newmsginfo;
101 g_return_if_fail(cache != NULL);
102 g_return_if_fail(msginfo != NULL);
104 oldmsginfo = g_hash_table_lookup(cache->msgnum_table, GINT_TO_POINTER(msginfo->msgnum));
106 g_hash_table_remove(cache->msgnum_table, GINT_TO_POINTER(oldmsginfo->msgnum));
107 procmsg_msginfo_free(oldmsginfo);
109 cache->memusage -= procmsg_msginfo_memusage(oldmsginfo);
111 newmsginfo = procmsg_msginfo_new_ref(msginfo);
112 g_hash_table_insert(cache->msgnum_table, GINT_TO_POINTER(msginfo->msgnum), newmsginfo);
113 cache->memusage += procmsg_msginfo_memusage(newmsginfo);
114 cache->last_access = time(NULL);
116 debug_print(_("Cache size: %d messages, %d byte\n"), g_hash_table_size(cache->msgnum_table), cache->memusage);
121 static gint msgcache_read_cache_data_str(FILE *fp, gchar **str)
127 if (fread(&len, sizeof(len), 1, fp) == 1) {
134 size_t size = MIN(len, BUFFSIZE - 1);
136 if (fread(buf, size, 1, fp) != 1) {
138 if (tmp) g_free(tmp);
145 *str = g_strconcat(tmp, buf, NULL);
149 tmp = *str = g_strdup(buf);
158 g_warning(_("Cache data is corrupted\n"));
164 #define READ_CACHE_DATA(data, fp) \
166 if (msgcache_read_cache_data_str(fp, &data) < 0) { \
167 procmsg_msginfo_free(msginfo); \
173 #define READ_CACHE_DATA_INT(n, fp) \
175 if (fread(&n, sizeof(n), 1, fp) != 1) { \
176 g_warning(_("Cache data is corrupted\n")); \
177 procmsg_msginfo_free(msginfo); \
183 MsgCache *msgcache_read_cache(FolderItem *item, const gchar *cache_file)
188 /* MsgFlags default_flags; */
189 gchar file_buf[BUFFSIZE];
192 gboolean error = FALSE;
194 g_return_val_if_fail(cache_file != NULL, NULL);
195 g_return_val_if_fail(item != NULL, NULL);
197 if ((fp = fopen(cache_file, "rb")) == NULL) {
198 debug_print(_("\tNo cache file\n"));
201 setvbuf(fp, file_buf, _IOFBF, sizeof(file_buf));
203 debug_print(_("\tReading message cache from %s...\n"), cache_file);
205 /* compare cache version */
206 if (fread(&ver, sizeof(ver), 1, fp) != 1 ||
207 CACHE_VERSION != ver) {
208 debug_print(_("Cache version is different. Discarding it.\n"));
213 cache = msgcache_new();
215 g_hash_table_freeze(cache->msgnum_table);
217 while (fread(&num, sizeof(num), 1, fp) == 1) {
218 msginfo = procmsg_msginfo_new();
219 msginfo->msgnum = num;
220 READ_CACHE_DATA_INT(msginfo->size, fp);
221 READ_CACHE_DATA_INT(msginfo->mtime, fp);
222 READ_CACHE_DATA_INT(msginfo->date_t, fp);
223 READ_CACHE_DATA_INT(msginfo->flags.tmp_flags, fp);
225 READ_CACHE_DATA(msginfo->fromname, fp);
227 READ_CACHE_DATA(msginfo->date, fp);
228 READ_CACHE_DATA(msginfo->from, fp);
229 READ_CACHE_DATA(msginfo->to, fp);
230 READ_CACHE_DATA(msginfo->cc, fp);
231 READ_CACHE_DATA(msginfo->newsgroups, fp);
232 READ_CACHE_DATA(msginfo->subject, fp);
233 READ_CACHE_DATA(msginfo->msgid, fp);
234 READ_CACHE_DATA(msginfo->inreplyto, fp);
235 READ_CACHE_DATA(msginfo->references, fp);
236 READ_CACHE_DATA(msginfo->xref, fp);
239 MSG_SET_PERM_FLAGS(msginfo->flags, default_flags.perm_flags);
240 MSG_SET_TMP_FLAGS(msginfo->flags, default_flags.tmp_flags);
242 msginfo->folder = item;
244 g_hash_table_insert(cache->msgnum_table, GINT_TO_POINTER(msginfo->msgnum), msginfo);
245 cache->memusage += procmsg_msginfo_memusage(msginfo);
250 g_hash_table_thaw(cache->msgnum_table);
251 msgcache_destroy(cache);
255 cache->last_access = time(NULL);
256 g_hash_table_thaw(cache->msgnum_table);
258 debug_print(_("done. (%d items read)\n"), g_hash_table_size(cache->msgnum_table));
259 debug_print(_("Cache size: %d messages, %d byte\n"), g_hash_table_size(cache->msgnum_table), cache->memusage);
264 void msgcache_read_mark(MsgCache *cache, const gchar *mark_file)
268 MsgPermFlags perm_flags;
272 if ((fp = fopen(mark_file, "rb")) == NULL) {
273 debug_print(_("Mark file not found.\n"));
275 } else if (fread(&ver, sizeof(ver), 1, fp) != 1 || MARK_VERSION != ver) {
276 debug_print(_("Mark version is different (%d != %d). "
277 "Discarding it.\n"), ver, MARK_VERSION);
279 debug_print(_("\tReading message marks from %s...\n"), mark_file);
281 while (fread(&num, sizeof(num), 1, fp) == 1) {
282 if (fread(&perm_flags, sizeof(perm_flags), 1, fp) != 1) break;
284 msginfo = g_hash_table_lookup(cache->msgnum_table, GUINT_TO_POINTER(num));
286 msginfo->flags.perm_flags = perm_flags;
293 #define WRITE_CACHE_DATA_INT(n, fp) \
294 fwrite(&n, sizeof(n), 1, fp)
296 #define WRITE_CACHE_DATA(data, fp) \
300 if (data == NULL || (len = strlen(data)) == 0) { \
302 WRITE_CACHE_DATA_INT(len, fp); \
304 len = strlen(data); \
305 WRITE_CACHE_DATA_INT(len, fp); \
306 fwrite(data, len, 1, fp); \
310 void msgcache_write_cache(MsgInfo *msginfo, FILE *fp)
312 MsgTmpFlags flags = msginfo->flags.tmp_flags & MSG_CACHED_FLAG_MASK;
314 WRITE_CACHE_DATA_INT(msginfo->msgnum, fp);
315 WRITE_CACHE_DATA_INT(msginfo->size, fp);
316 WRITE_CACHE_DATA_INT(msginfo->mtime, fp);
317 WRITE_CACHE_DATA_INT(msginfo->date_t, fp);
318 WRITE_CACHE_DATA_INT(flags, fp);
320 WRITE_CACHE_DATA(msginfo->fromname, fp);
322 WRITE_CACHE_DATA(msginfo->date, fp);
323 WRITE_CACHE_DATA(msginfo->from, fp);
324 WRITE_CACHE_DATA(msginfo->to, fp);
325 WRITE_CACHE_DATA(msginfo->cc, fp);
326 WRITE_CACHE_DATA(msginfo->newsgroups, fp);
327 WRITE_CACHE_DATA(msginfo->subject, fp);
328 WRITE_CACHE_DATA(msginfo->msgid, fp);
329 WRITE_CACHE_DATA(msginfo->inreplyto, fp);
330 WRITE_CACHE_DATA(msginfo->references, fp);
331 WRITE_CACHE_DATA(msginfo->xref, fp);
334 static void msgcache_write_flags(MsgInfo *msginfo, FILE *fp)
336 MsgPermFlags flags = msginfo->flags.perm_flags;
338 WRITE_CACHE_DATA_INT(msginfo->msgnum, fp);
339 WRITE_CACHE_DATA_INT(flags, fp);
348 static void msgcache_write_func(gpointer key, gpointer value, gpointer user_data)
351 struct write_fps *write_fps;
353 msginfo = (MsgInfo *)value;
354 write_fps = user_data;
356 msgcache_write_cache(msginfo, write_fps->cache_fp);
357 msgcache_write_flags(msginfo, write_fps->mark_fp);
360 gint msgcache_write(const gchar *cache_file, const gchar *mark_file, MsgCache *cache)
363 struct write_fps write_fps;
366 g_return_val_if_fail(cache_file != NULL, -1);
367 g_return_val_if_fail(mark_file != NULL, -1);
368 g_return_val_if_fail(cache != NULL, -1);
370 debug_print(_("\tWriting message cache to %s and %s...\n"), cache_file, mark_file);
372 if ((fp = fopen(cache_file, "wb")) == NULL) {
373 FILE_OP_ERROR(cache_file, "fopen");
376 if (change_file_mode_rw(fp, cache_file) < 0)
377 FILE_OP_ERROR(cache_file, "chmod");
380 WRITE_CACHE_DATA_INT(ver, fp);
381 write_fps.cache_fp = fp;
383 if ((fp = fopen(mark_file, "wb")) == NULL) {
384 FILE_OP_ERROR(mark_file, "fopen");
385 fclose(write_fps.cache_fp);
390 WRITE_CACHE_DATA_INT(ver, fp);
391 write_fps.mark_fp = fp;
393 g_hash_table_foreach(cache->msgnum_table, msgcache_write_func, (gpointer)&write_fps);
395 fclose(write_fps.cache_fp);
396 fclose(write_fps.mark_fp);
398 cache->last_access = time(NULL);
400 debug_print(_("done.\n"));
403 MsgInfo *msgcache_get_msg(MsgCache *cache, guint num)
407 g_return_val_if_fail(cache != NULL, NULL);
409 msginfo = g_hash_table_lookup(cache->msgnum_table, GINT_TO_POINTER(num));
412 cache->last_access = time(NULL);
414 return procmsg_msginfo_new_ref(msginfo);
417 static void msgcache_get_msg_list_func(gpointer key, gpointer value, gpointer user_data)
419 GSList **listptr = user_data;
420 MsgInfo *msginfo = value;
422 *listptr = g_slist_prepend(*listptr, procmsg_msginfo_new_ref(msginfo));
425 GSList *msgcache_get_msg_list(MsgCache *cache)
427 GSList *msg_list = NULL;
429 g_return_val_if_fail(cache != NULL, NULL);
431 g_hash_table_foreach((GHashTable *)cache->msgnum_table, msgcache_get_msg_list_func, (gpointer)&msg_list);
432 cache->last_access = time(NULL);
437 time_t msgcache_get_last_access_time(MsgCache *cache)
439 g_return_val_if_fail(cache != NULL, 0);
441 return cache->last_access;
444 gint msgcache_get_memory_usage(MsgCache *cache)
446 g_return_val_if_fail(cache != NULL, 0);
448 return cache->memusage;