Statistics
| Revision:

root / libsylph / procmsg.c @ 1082

History | View | Annotate | Download (37.2 kB)

1 1 hiro
/*
2 578 hiro
 * LibSylph -- E-Mail client library
3 919 hiro
 * Copyright (C) 1999-2006 Hiroyuki Yamamoto
4 1 hiro
 *
5 578 hiro
 * This library is free software; you can redistribute it and/or
6 578 hiro
 * modify it under the terms of the GNU Lesser General Public
7 578 hiro
 * License as published by the Free Software Foundation; either
8 578 hiro
 * version 2.1 of the License, or (at your option) any later version.
9 1 hiro
 *
10 578 hiro
 * This library is distributed in the hope that it will be useful,
11 1 hiro
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 578 hiro
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 578 hiro
 * Lesser General Public License for more details.
14 1 hiro
 *
15 578 hiro
 * You should have received a copy of the GNU Lesser General Public
16 578 hiro
 * License along with this library; if not, write to the Free Software
17 578 hiro
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 1 hiro
 */
19 1 hiro
20 1 hiro
#include "defs.h"
21 1 hiro
22 1 hiro
#include <glib.h>
23 92 hiro
#include <glib/gi18n.h>
24 1 hiro
#include <stdio.h>
25 1 hiro
#include <stdlib.h>
26 1 hiro
27 1 hiro
#include "utils.h"
28 1 hiro
#include "procmsg.h"
29 1 hiro
#include "procheader.h"
30 1 hiro
#include "account.h"
31 1 hiro
#include "procmime.h"
32 317 hiro
#include "prefs_common.h"
33 1 hiro
#include "folder.h"
34 129 hiro
#include "codeconv.h"
35 1 hiro
36 1 hiro
static void mark_sum_func                        (gpointer         key,
37 1 hiro
                                                 gpointer         value,
38 1 hiro
                                                 gpointer         data);
39 1 hiro
40 1 hiro
static GHashTable *procmsg_read_mark_file        (FolderItem        *item);
41 1 hiro
static void procmsg_write_mark_file                (FolderItem        *item,
42 1 hiro
                                                 GHashTable        *mark_table);
43 1 hiro
44 1 hiro
static FILE *procmsg_open_cache_file_with_buffer(FolderItem        *item,
45 1 hiro
                                                 DataOpenMode         mode,
46 1 hiro
                                                 gchar                *buf,
47 1 hiro
                                                 size_t                 buf_size);
48 1 hiro
49 1 hiro
static gint procmsg_cmp_by_mark                        (gconstpointer         a,
50 1 hiro
                                                 gconstpointer         b);
51 1 hiro
static gint procmsg_cmp_by_unread                (gconstpointer         a,
52 1 hiro
                                                 gconstpointer         b);
53 1 hiro
static gint procmsg_cmp_by_mime                        (gconstpointer         a,
54 1 hiro
                                                 gconstpointer         b);
55 1 hiro
static gint procmsg_cmp_by_label                (gconstpointer         a,
56 1 hiro
                                                 gconstpointer         b);
57 1 hiro
static gint procmsg_cmp_by_number                (gconstpointer         a,
58 1 hiro
                                                 gconstpointer         b);
59 1 hiro
static gint procmsg_cmp_by_size                        (gconstpointer         a,
60 1 hiro
                                                 gconstpointer         b);
61 1 hiro
static gint procmsg_cmp_by_date                        (gconstpointer         a,
62 1 hiro
                                                 gconstpointer         b);
63 1 hiro
static gint procmsg_cmp_by_from                        (gconstpointer         a,
64 1 hiro
                                                 gconstpointer         b);
65 1 hiro
static gint procmsg_cmp_by_to                        (gconstpointer         a,
66 1 hiro
                                                 gconstpointer         b);
67 1 hiro
static gint procmsg_cmp_by_subject                (gconstpointer         a,
68 1 hiro
                                                 gconstpointer         b);
69 1 hiro
70 1 hiro
71 1 hiro
GHashTable *procmsg_msg_hash_table_create(GSList *mlist)
72 1 hiro
{
73 1 hiro
        GHashTable *msg_table;
74 1 hiro
75 1 hiro
        if (mlist == NULL) return NULL;
76 1 hiro
77 1 hiro
        msg_table = g_hash_table_new(NULL, g_direct_equal);
78 1 hiro
        procmsg_msg_hash_table_append(msg_table, mlist);
79 1 hiro
80 1 hiro
        return msg_table;
81 1 hiro
}
82 1 hiro
83 1 hiro
void procmsg_msg_hash_table_append(GHashTable *msg_table, GSList *mlist)
84 1 hiro
{
85 1 hiro
        GSList *cur;
86 1 hiro
        MsgInfo *msginfo;
87 1 hiro
88 1 hiro
        if (msg_table == NULL || mlist == NULL) return;
89 1 hiro
90 1 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
91 1 hiro
                msginfo = (MsgInfo *)cur->data;
92 1 hiro
93 1 hiro
                g_hash_table_insert(msg_table,
94 1 hiro
                                    GUINT_TO_POINTER(msginfo->msgnum),
95 1 hiro
                                    msginfo);
96 1 hiro
        }
97 1 hiro
}
98 1 hiro
99 1 hiro
GHashTable *procmsg_to_folder_hash_table_create(GSList *mlist)
100 1 hiro
{
101 1 hiro
        GHashTable *msg_table;
102 1 hiro
        GSList *cur;
103 1 hiro
        MsgInfo *msginfo;
104 1 hiro
105 1 hiro
        if (mlist == NULL) return NULL;
106 1 hiro
107 1 hiro
        msg_table = g_hash_table_new(NULL, g_direct_equal);
108 1 hiro
109 1 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
110 1 hiro
                msginfo = (MsgInfo *)cur->data;
111 1 hiro
                g_hash_table_insert(msg_table, msginfo->to_folder, msginfo);
112 1 hiro
        }
113 1 hiro
114 1 hiro
        return msg_table;
115 1 hiro
}
116 1 hiro
117 869 hiro
gint procmsg_read_cache_data_str(FILE *fp, gchar **str)
118 1 hiro
{
119 1 hiro
        gchar buf[BUFFSIZE];
120 1 hiro
        gint ret = 0;
121 1 hiro
        guint32 len;
122 1 hiro
123 1 hiro
        if (fread(&len, sizeof(len), 1, fp) == 1) {
124 1 hiro
                if (len > G_MAXINT)
125 1 hiro
                        ret = -1;
126 1 hiro
                else {
127 1 hiro
                        gchar *tmp = NULL;
128 1 hiro
129 1 hiro
                        while (len > 0) {
130 1 hiro
                                size_t size = MIN(len, BUFFSIZE - 1);
131 1 hiro
132 1 hiro
                                if (fread(buf, size, 1, fp) != 1) {
133 1 hiro
                                        ret = -1;
134 1 hiro
                                        if (tmp) g_free(tmp);
135 1 hiro
                                        *str = NULL;
136 1 hiro
                                        break;
137 1 hiro
                                }
138 1 hiro
139 1 hiro
                                buf[size] = '\0';
140 1 hiro
                                if (tmp) {
141 1 hiro
                                        *str = g_strconcat(tmp, buf, NULL);
142 1 hiro
                                        g_free(tmp);
143 1 hiro
                                        tmp = *str;
144 1 hiro
                                } else
145 1 hiro
                                        tmp = *str = g_strdup(buf);
146 1 hiro
147 1 hiro
                                len -= size;
148 1 hiro
                        }
149 1 hiro
                }
150 1 hiro
        } else
151 1 hiro
                ret = -1;
152 1 hiro
153 1 hiro
        return ret;
154 1 hiro
}
155 1 hiro
156 1 hiro
#define READ_CACHE_DATA(data, fp)                                \
157 1 hiro
{                                                                \
158 1 hiro
        if (procmsg_read_cache_data_str(fp, &data) < 0) {        \
159 1 hiro
                procmsg_msginfo_free(msginfo);                        \
160 1 hiro
                procmsg_msg_list_free(mlist);                        \
161 1 hiro
                mlist = NULL;                                        \
162 1 hiro
                break;                                                \
163 1 hiro
        }                                                        \
164 1 hiro
}
165 1 hiro
166 1 hiro
#define READ_CACHE_DATA_INT(n, fp)                                \
167 1 hiro
{                                                                \
168 1 hiro
        guint32 idata;                                                \
169 1 hiro
                                                                \
170 1 hiro
        if (fread(&idata, sizeof(idata), 1, fp) != 1) {                \
171 1 hiro
                g_warning("Cache data is corrupted\n");                \
172 1 hiro
                procmsg_msginfo_free(msginfo);                        \
173 1 hiro
                procmsg_msg_list_free(mlist);                        \
174 1 hiro
                mlist = NULL;                                        \
175 1 hiro
                break;                                                \
176 1 hiro
        } else                                                        \
177 1 hiro
                n = idata;                                        \
178 1 hiro
}
179 1 hiro
180 1 hiro
GSList *procmsg_read_cache(FolderItem *item, gboolean scan_file)
181 1 hiro
{
182 1 hiro
        GSList *mlist = NULL;
183 1 hiro
        GSList *last = NULL;
184 1 hiro
        FILE *fp;
185 1 hiro
        MsgInfo *msginfo;
186 1 hiro
        MsgFlags default_flags;
187 1 hiro
        gchar file_buf[BUFFSIZE];
188 1 hiro
        guint32 num;
189 190 hiro
        guint refnum;
190 1 hiro
        FolderType type;
191 1 hiro
192 1 hiro
        g_return_val_if_fail(item != NULL, NULL);
193 1 hiro
        g_return_val_if_fail(item->folder != NULL, NULL);
194 1 hiro
        type = FOLDER_TYPE(item->folder);
195 1 hiro
196 1 hiro
        default_flags.perm_flags = MSG_NEW|MSG_UNREAD;
197 1 hiro
        default_flags.tmp_flags = 0;
198 1 hiro
        if (type == F_MH || type == F_IMAP) {
199 1 hiro
                if (item->stype == F_QUEUE) {
200 1 hiro
                        MSG_SET_TMP_FLAGS(default_flags, MSG_QUEUED);
201 1 hiro
                } else if (item->stype == F_DRAFT) {
202 1 hiro
                        MSG_SET_TMP_FLAGS(default_flags, MSG_DRAFT);
203 1 hiro
                }
204 1 hiro
        }
205 1 hiro
        if (type == F_IMAP) {
206 1 hiro
                MSG_SET_TMP_FLAGS(default_flags, MSG_IMAP);
207 1 hiro
        } else if (type == F_NEWS) {
208 1 hiro
                MSG_SET_TMP_FLAGS(default_flags, MSG_NEWS);
209 1 hiro
        }
210 1 hiro
211 1 hiro
        if (type == F_MH) {
212 1 hiro
                gchar *path;
213 1 hiro
214 1 hiro
                path = folder_item_get_path(item);
215 1 hiro
                if (change_dir(path) < 0) {
216 1 hiro
                        g_free(path);
217 1 hiro
                        return NULL;
218 1 hiro
                }
219 1 hiro
                g_free(path);
220 1 hiro
        }
221 1 hiro
222 1 hiro
        if ((fp = procmsg_open_cache_file_with_buffer
223 397 hiro
                (item, DATA_READ, file_buf, sizeof(file_buf))) == NULL) {
224 397 hiro
                item->cache_dirty = TRUE;
225 1 hiro
                return NULL;
226 397 hiro
        }
227 1 hiro
228 1 hiro
        debug_print("Reading summary cache...");
229 1 hiro
230 1 hiro
        while (fread(&num, sizeof(num), 1, fp) == 1) {
231 1 hiro
                msginfo = g_new0(MsgInfo, 1);
232 1 hiro
                msginfo->msgnum = num;
233 1 hiro
                READ_CACHE_DATA_INT(msginfo->size, fp);
234 1 hiro
                READ_CACHE_DATA_INT(msginfo->mtime, fp);
235 1 hiro
                READ_CACHE_DATA_INT(msginfo->date_t, fp);
236 1 hiro
                READ_CACHE_DATA_INT(msginfo->flags.tmp_flags, fp);
237 1 hiro
238 1 hiro
                READ_CACHE_DATA(msginfo->fromname, fp);
239 1 hiro
240 1 hiro
                READ_CACHE_DATA(msginfo->date, fp);
241 1 hiro
                READ_CACHE_DATA(msginfo->from, fp);
242 1 hiro
                READ_CACHE_DATA(msginfo->to, fp);
243 1 hiro
                READ_CACHE_DATA(msginfo->newsgroups, fp);
244 1 hiro
                READ_CACHE_DATA(msginfo->subject, fp);
245 1 hiro
                READ_CACHE_DATA(msginfo->msgid, fp);
246 1 hiro
                READ_CACHE_DATA(msginfo->inreplyto, fp);
247 1 hiro
248 190 hiro
                READ_CACHE_DATA_INT(refnum, fp);
249 190 hiro
                for (; refnum != 0; refnum--) {
250 190 hiro
                        gchar *ref;
251 190 hiro
252 190 hiro
                        READ_CACHE_DATA(ref, fp);
253 190 hiro
                        msginfo->references =
254 190 hiro
                                g_slist_prepend(msginfo->references, ref);
255 190 hiro
                }
256 190 hiro
                if (msginfo->references)
257 190 hiro
                        msginfo->references =
258 190 hiro
                                g_slist_reverse(msginfo->references);
259 190 hiro
260 1 hiro
                MSG_SET_PERM_FLAGS(msginfo->flags, default_flags.perm_flags);
261 1 hiro
                MSG_SET_TMP_FLAGS(msginfo->flags, default_flags.tmp_flags);
262 1 hiro
263 1 hiro
                /* if the message file doesn't exist or is changed,
264 1 hiro
                   don't add the data */
265 20 hiro
                if ((type == F_MH && scan_file &&
266 285 hiro
                     folder_item_is_msg_changed(item, msginfo)) || num == 0) {
267 1 hiro
                        procmsg_msginfo_free(msginfo);
268 285 hiro
                        item->cache_dirty = TRUE;
269 285 hiro
                } else {
270 1 hiro
                        msginfo->folder = item;
271 1 hiro
272 1 hiro
                        if (!mlist)
273 1 hiro
                                last = mlist = g_slist_append(NULL, msginfo);
274 1 hiro
                        else {
275 1 hiro
                                last = g_slist_append(last, msginfo);
276 1 hiro
                                last = last->next;
277 1 hiro
                        }
278 1 hiro
                }
279 1 hiro
        }
280 1 hiro
281 1 hiro
        fclose(fp);
282 1 hiro
283 1 hiro
        debug_print("done.\n");
284 1 hiro
285 1 hiro
        return mlist;
286 1 hiro
}
287 1 hiro
288 1 hiro
#undef READ_CACHE_DATA
289 1 hiro
#undef READ_CACHE_DATA_INT
290 1 hiro
291 1 hiro
static void mark_unset_new_func(gpointer key, gpointer value, gpointer data)
292 1 hiro
{
293 1 hiro
        MSG_UNSET_PERM_FLAGS(*((MsgFlags *)value), MSG_NEW);
294 1 hiro
}
295 1 hiro
296 1 hiro
void procmsg_set_flags(GSList *mlist, FolderItem *item)
297 1 hiro
{
298 1 hiro
        GSList *cur;
299 1 hiro
        gint new = 0, unread = 0, total = 0;
300 1 hiro
        gint lastnum = 0;
301 1 hiro
        gint unflagged = 0;
302 1 hiro
        gboolean mark_queue_exist;
303 1 hiro
        MsgInfo *msginfo;
304 1 hiro
        GHashTable *mark_table;
305 1 hiro
        MsgFlags *flags;
306 1 hiro
307 1 hiro
        g_return_if_fail(item != NULL);
308 1 hiro
        g_return_if_fail(item->folder != NULL);
309 1 hiro
310 1 hiro
        debug_print("Marking the messages...\n");
311 1 hiro
312 1 hiro
        mark_queue_exist = (item->mark_queue != NULL);
313 1 hiro
        mark_table = procmsg_read_mark_file(item);
314 1 hiro
        if (!mark_table) {
315 1 hiro
                item->new = item->unread = item->total = g_slist_length(mlist);
316 1 hiro
                item->updated = TRUE;
317 293 hiro
                item->mark_dirty = TRUE;
318 1 hiro
                return;
319 1 hiro
        }
320 1 hiro
321 1 hiro
        /* unset new flags if new (unflagged) messages exist */
322 1 hiro
        if (!mark_queue_exist) {
323 1 hiro
                for (cur = mlist; cur != NULL; cur = cur->next) {
324 1 hiro
                        msginfo = (MsgInfo *)cur->data;
325 1 hiro
                        flags = g_hash_table_lookup
326 1 hiro
                                (mark_table, GUINT_TO_POINTER(msginfo->msgnum));
327 1 hiro
                        if (!flags) {
328 1 hiro
                                g_hash_table_foreach(mark_table,
329 1 hiro
                                                     mark_unset_new_func, NULL);
330 293 hiro
                                item->mark_dirty = TRUE;
331 1 hiro
                                break;
332 1 hiro
                        }
333 1 hiro
                }
334 1 hiro
        }
335 1 hiro
336 1 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
337 1 hiro
                msginfo = (MsgInfo *)cur->data;
338 1 hiro
339 1 hiro
                if (lastnum < msginfo->msgnum)
340 1 hiro
                        lastnum = msginfo->msgnum;
341 1 hiro
342 1 hiro
                flags = g_hash_table_lookup
343 1 hiro
                        (mark_table, GUINT_TO_POINTER(msginfo->msgnum));
344 1 hiro
345 1 hiro
                if (flags != NULL) {
346 1 hiro
                        /* add the permanent flags only */
347 1 hiro
                        msginfo->flags.perm_flags = flags->perm_flags;
348 1 hiro
                        if (MSG_IS_NEW(*flags))
349 1 hiro
                                ++new;
350 1 hiro
                        if (MSG_IS_UNREAD(*flags))
351 1 hiro
                                ++unread;
352 1 hiro
                        if (FOLDER_TYPE(item->folder) == F_IMAP) {
353 1 hiro
                                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_IMAP);
354 1 hiro
                        } else if (FOLDER_TYPE(item->folder) == F_NEWS) {
355 1 hiro
                                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_NEWS);
356 1 hiro
                        }
357 1 hiro
                } else {
358 1 hiro
                        ++unflagged;
359 1 hiro
                        ++new;
360 1 hiro
                        ++unread;
361 1 hiro
                }
362 1 hiro
363 1 hiro
                ++total;
364 1 hiro
        }
365 1 hiro
366 1 hiro
        item->new = new;
367 1 hiro
        item->unread = unread;
368 1 hiro
        item->total = total;
369 1 hiro
        item->unmarked_num = unflagged;
370 1 hiro
        item->last_num = lastnum;
371 1 hiro
        item->updated = TRUE;
372 1 hiro
373 293 hiro
        if (unflagged > 0)
374 293 hiro
                item->mark_dirty = TRUE;
375 293 hiro
376 1 hiro
        debug_print("new: %d unread: %d unflagged: %d total: %d\n",
377 1 hiro
                    new, unread, unflagged, total);
378 1 hiro
379 1 hiro
        hash_free_value_mem(mark_table);
380 1 hiro
        g_hash_table_destroy(mark_table);
381 1 hiro
}
382 1 hiro
383 1082 hiro
static void mark_all_read_func(gpointer key, gpointer value, gpointer data)
384 1082 hiro
{
385 1082 hiro
        MSG_UNSET_PERM_FLAGS(*((MsgFlags *)value), MSG_NEW|MSG_UNREAD);
386 1082 hiro
}
387 1082 hiro
388 1082 hiro
void procmsg_mark_all_read(FolderItem *item)
389 1082 hiro
{
390 1082 hiro
        GHashTable *mark_table;
391 1082 hiro
392 1082 hiro
        debug_print("Marking all messages as read\n");
393 1082 hiro
394 1082 hiro
        mark_table = procmsg_read_mark_file(item);
395 1082 hiro
        if (mark_table) {
396 1082 hiro
                g_hash_table_foreach(mark_table, mark_all_read_func, NULL);
397 1082 hiro
                procmsg_write_mark_file(item, mark_table);
398 1082 hiro
                hash_free_value_mem(mark_table);
399 1082 hiro
                g_hash_table_destroy(mark_table);
400 1082 hiro
        }
401 1082 hiro
402 1082 hiro
        if (item->mark_queue) {
403 1082 hiro
                GSList *cur;
404 1082 hiro
                MsgInfo *msginfo;
405 1082 hiro
406 1082 hiro
                for (cur = item->mark_queue; cur != NULL; cur = cur->next) {
407 1082 hiro
                        msginfo = (MsgInfo *)cur->data;
408 1082 hiro
                        MSG_UNSET_PERM_FLAGS
409 1082 hiro
                                (msginfo->flags, MSG_NEW|MSG_UNREAD);
410 1082 hiro
                }
411 1082 hiro
                item->mark_dirty = TRUE;
412 1082 hiro
        }
413 1082 hiro
414 1082 hiro
        item->new = item->unread = 0;
415 1082 hiro
}
416 1082 hiro
417 1 hiro
static FolderSortType cmp_func_sort_type;
418 1 hiro
419 1 hiro
GSList *procmsg_sort_msg_list(GSList *mlist, FolderSortKey sort_key,
420 1 hiro
                              FolderSortType sort_type)
421 1 hiro
{
422 1 hiro
        GCompareFunc cmp_func;
423 1 hiro
424 1 hiro
        switch (sort_key) {
425 1 hiro
        case SORT_BY_MARK:
426 1 hiro
                cmp_func = procmsg_cmp_by_mark; break;
427 1 hiro
        case SORT_BY_UNREAD:
428 1 hiro
                cmp_func = procmsg_cmp_by_unread; break;
429 1 hiro
        case SORT_BY_MIME:
430 1 hiro
                cmp_func = procmsg_cmp_by_mime; break;
431 1 hiro
        case SORT_BY_LABEL:
432 1 hiro
                cmp_func = procmsg_cmp_by_label; break;
433 1 hiro
        case SORT_BY_NUMBER:
434 1 hiro
                cmp_func = procmsg_cmp_by_number; break;
435 1 hiro
        case SORT_BY_SIZE:
436 1 hiro
                cmp_func = procmsg_cmp_by_size; break;
437 1 hiro
        case SORT_BY_DATE:
438 1 hiro
                cmp_func = procmsg_cmp_by_date; break;
439 1 hiro
        case SORT_BY_FROM:
440 1 hiro
                cmp_func = procmsg_cmp_by_from; break;
441 1 hiro
        case SORT_BY_SUBJECT:
442 1 hiro
                cmp_func = procmsg_cmp_by_subject; break;
443 1 hiro
        case SORT_BY_TO:
444 1 hiro
                cmp_func = procmsg_cmp_by_to; break;
445 1 hiro
        default:
446 1 hiro
                return mlist;
447 1 hiro
        }
448 1 hiro
449 1 hiro
        cmp_func_sort_type = sort_type;
450 1 hiro
451 1 hiro
        mlist = g_slist_sort(mlist, cmp_func);
452 1 hiro
453 1 hiro
        return mlist;
454 1 hiro
}
455 1 hiro
456 1 hiro
gint procmsg_get_last_num_in_msg_list(GSList *mlist)
457 1 hiro
{
458 1 hiro
        GSList *cur;
459 1 hiro
        MsgInfo *msginfo;
460 1 hiro
        gint last = 0;
461 1 hiro
462 1 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
463 1 hiro
                msginfo = (MsgInfo *)cur->data;
464 1 hiro
                if (msginfo && msginfo->msgnum > last)
465 1 hiro
                        last = msginfo->msgnum;
466 1 hiro
        }
467 1 hiro
468 1 hiro
        return last;
469 1 hiro
}
470 1 hiro
471 1 hiro
void procmsg_msg_list_free(GSList *mlist)
472 1 hiro
{
473 1 hiro
        GSList *cur;
474 1 hiro
        MsgInfo *msginfo;
475 1 hiro
476 1 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
477 1 hiro
                msginfo = (MsgInfo *)cur->data;
478 1 hiro
                procmsg_msginfo_free(msginfo);
479 1 hiro
        }
480 1 hiro
        g_slist_free(mlist);
481 1 hiro
}
482 1 hiro
483 1 hiro
void procmsg_write_cache(MsgInfo *msginfo, FILE *fp)
484 1 hiro
{
485 1 hiro
        MsgTmpFlags flags = msginfo->flags.tmp_flags & MSG_CACHED_FLAG_MASK;
486 190 hiro
        GSList *cur;
487 1 hiro
488 1 hiro
        WRITE_CACHE_DATA_INT(msginfo->msgnum, fp);
489 1 hiro
        WRITE_CACHE_DATA_INT(msginfo->size, fp);
490 1 hiro
        WRITE_CACHE_DATA_INT(msginfo->mtime, fp);
491 1 hiro
        WRITE_CACHE_DATA_INT(msginfo->date_t, fp);
492 1 hiro
        WRITE_CACHE_DATA_INT(flags, fp);
493 1 hiro
494 1 hiro
        WRITE_CACHE_DATA(msginfo->fromname, fp);
495 1 hiro
496 1 hiro
        WRITE_CACHE_DATA(msginfo->date, fp);
497 1 hiro
        WRITE_CACHE_DATA(msginfo->from, fp);
498 1 hiro
        WRITE_CACHE_DATA(msginfo->to, fp);
499 1 hiro
        WRITE_CACHE_DATA(msginfo->newsgroups, fp);
500 1 hiro
        WRITE_CACHE_DATA(msginfo->subject, fp);
501 1 hiro
        WRITE_CACHE_DATA(msginfo->msgid, fp);
502 1 hiro
        WRITE_CACHE_DATA(msginfo->inreplyto, fp);
503 190 hiro
504 190 hiro
        WRITE_CACHE_DATA_INT(g_slist_length(msginfo->references), fp);
505 190 hiro
        for (cur = msginfo->references; cur != NULL; cur = cur->next) {
506 190 hiro
                WRITE_CACHE_DATA((gchar *)cur->data, fp);
507 190 hiro
        }
508 1 hiro
}
509 1 hiro
510 1 hiro
void procmsg_write_flags(MsgInfo *msginfo, FILE *fp)
511 1 hiro
{
512 1 hiro
        MsgPermFlags flags = msginfo->flags.perm_flags;
513 1 hiro
514 1 hiro
        WRITE_CACHE_DATA_INT(msginfo->msgnum, fp);
515 1 hiro
        WRITE_CACHE_DATA_INT(flags, fp);
516 1 hiro
}
517 1 hiro
518 806 hiro
void procmsg_write_cache_list(FolderItem *item, GSList *mlist)
519 806 hiro
{
520 806 hiro
        FILE *fp;
521 806 hiro
        GSList *cur;
522 806 hiro
523 806 hiro
        g_return_if_fail(item != NULL);
524 806 hiro
525 806 hiro
        debug_print("Writing summary cache (%s)\n", item->path);
526 806 hiro
527 806 hiro
        fp = procmsg_open_cache_file(item, DATA_WRITE);
528 806 hiro
        if (fp == NULL)
529 806 hiro
                return;
530 806 hiro
531 806 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
532 806 hiro
                MsgInfo *msginfo = (MsgInfo *)cur->data;
533 806 hiro
                procmsg_write_cache(msginfo, fp);
534 806 hiro
        }
535 806 hiro
536 806 hiro
        fclose(fp);
537 806 hiro
        item->cache_dirty = FALSE;
538 806 hiro
}
539 806 hiro
540 806 hiro
void procmsg_write_flags_list(FolderItem *item, GSList *mlist)
541 806 hiro
{
542 806 hiro
        FILE *fp;
543 806 hiro
        GSList *cur;
544 806 hiro
545 806 hiro
        g_return_if_fail(item != NULL);
546 806 hiro
547 806 hiro
        debug_print("Writing summary flags (%s)\n", item->path);
548 806 hiro
549 806 hiro
        fp = procmsg_open_mark_file(item, DATA_WRITE);
550 806 hiro
        if (fp == NULL)
551 806 hiro
                return;
552 806 hiro
553 806 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
554 806 hiro
                MsgInfo *msginfo = (MsgInfo *)cur->data;
555 806 hiro
                procmsg_write_flags(msginfo, fp);
556 806 hiro
        }
557 806 hiro
558 806 hiro
        if (item->mark_queue)
559 806 hiro
                procmsg_flush_mark_queue(item, fp);
560 806 hiro
561 806 hiro
        fclose(fp);
562 806 hiro
        item->mark_dirty = FALSE;
563 806 hiro
}
564 806 hiro
565 850 hiro
static gint cmp_by_item(gconstpointer a, gconstpointer b)
566 850 hiro
{
567 850 hiro
        const MsgInfo *msginfo1 = a;
568 850 hiro
        const MsgInfo *msginfo2 = b;
569 850 hiro
570 850 hiro
        if (msginfo1->folder == msginfo2->folder)
571 850 hiro
                return msginfo1->msgnum - msginfo2->msgnum;
572 850 hiro
573 850 hiro
        return msginfo1->folder - msginfo2->folder;
574 850 hiro
}
575 850 hiro
576 850 hiro
void procmsg_write_flags_for_multiple_folders(GSList *mlist)
577 850 hiro
{
578 850 hiro
        GSList *tmp_list, *cur;
579 850 hiro
        FolderItem *prev_item = NULL;
580 850 hiro
        FILE *fp = NULL;
581 850 hiro
582 850 hiro
        if (!mlist)
583 850 hiro
                return;
584 850 hiro
585 850 hiro
        tmp_list = g_slist_copy(mlist);
586 850 hiro
        tmp_list = g_slist_sort(tmp_list, cmp_by_item);
587 850 hiro
588 850 hiro
        for (cur = tmp_list; cur != NULL; cur = cur->next) {
589 850 hiro
                MsgInfo *msginfo = (MsgInfo *)cur->data;
590 850 hiro
                FolderItem *item = msginfo->folder;
591 850 hiro
592 850 hiro
                if (prev_item != item) {
593 850 hiro
                        if (fp)
594 850 hiro
                                fclose(fp);
595 850 hiro
                        fp = procmsg_open_mark_file(item, DATA_APPEND);
596 850 hiro
                        if (!fp) {
597 850 hiro
                                g_warning("can't open mark file\n");
598 850 hiro
                                break;
599 850 hiro
                        }
600 850 hiro
                        item->updated = TRUE;
601 850 hiro
                }
602 850 hiro
                procmsg_write_flags(msginfo, fp);
603 850 hiro
                prev_item = item;
604 850 hiro
        }
605 850 hiro
606 850 hiro
        if (fp)
607 850 hiro
                fclose(fp);
608 850 hiro
        g_slist_free(tmp_list);
609 850 hiro
}
610 850 hiro
611 1 hiro
void procmsg_flush_mark_queue(FolderItem *item, FILE *fp)
612 1 hiro
{
613 1 hiro
        MsgInfo *flaginfo;
614 1 hiro
615 1 hiro
        g_return_if_fail(item != NULL);
616 1 hiro
        g_return_if_fail(fp != NULL);
617 1 hiro
618 1 hiro
        if (item->mark_queue)
619 1 hiro
                debug_print("flushing mark_queue...\n");
620 1 hiro
621 1 hiro
        while (item->mark_queue != NULL) {
622 1 hiro
                flaginfo = (MsgInfo *)item->mark_queue->data;
623 1 hiro
                procmsg_write_flags(flaginfo, fp);
624 1 hiro
                procmsg_msginfo_free(flaginfo);
625 1 hiro
                item->mark_queue = g_slist_remove(item->mark_queue, flaginfo);
626 1 hiro
        }
627 1 hiro
}
628 1 hiro
629 1 hiro
void procmsg_add_mark_queue(FolderItem *item, gint num, MsgFlags flags)
630 1 hiro
{
631 1 hiro
        MsgInfo *queue_msginfo;
632 1 hiro
633 1 hiro
        queue_msginfo = g_new0(MsgInfo, 1);
634 1 hiro
        queue_msginfo->msgnum = num;
635 1 hiro
        queue_msginfo->flags = flags;
636 1 hiro
        item->mark_queue = g_slist_append
637 1 hiro
                (item->mark_queue, queue_msginfo);
638 1 hiro
        return;
639 1 hiro
}
640 1 hiro
641 1 hiro
void procmsg_add_flags(FolderItem *item, gint num, MsgFlags flags)
642 1 hiro
{
643 1 hiro
        FILE *fp;
644 1 hiro
        MsgInfo msginfo;
645 1 hiro
646 1 hiro
        g_return_if_fail(item != NULL);
647 1 hiro
648 1 hiro
        if (item->opened) {
649 1 hiro
                procmsg_add_mark_queue(item, num, flags);
650 1 hiro
                return;
651 1 hiro
        }
652 1 hiro
653 1 hiro
        if ((fp = procmsg_open_mark_file(item, DATA_APPEND)) == NULL) {
654 1 hiro
                g_warning(_("can't open mark file\n"));
655 1 hiro
                return;
656 1 hiro
        }
657 1 hiro
658 1 hiro
        msginfo.msgnum = num;
659 1 hiro
        msginfo.flags = flags;
660 1 hiro
661 1 hiro
        procmsg_write_flags(&msginfo, fp);
662 1 hiro
        fclose(fp);
663 1 hiro
}
664 1 hiro
665 1 hiro
struct MarkSum {
666 1 hiro
        gint *new;
667 1 hiro
        gint *unread;
668 1 hiro
        gint *total;
669 1 hiro
        gint *min;
670 1 hiro
        gint *max;
671 1 hiro
        gint first;
672 1 hiro
};
673 1 hiro
674 1 hiro
static void mark_sum_func(gpointer key, gpointer value, gpointer data)
675 1 hiro
{
676 1 hiro
        MsgFlags *flags = value;
677 1 hiro
        gint num = GPOINTER_TO_INT(key);
678 1 hiro
        struct MarkSum *marksum = data;
679 1 hiro
680 1 hiro
        if (marksum->first <= num) {
681 1 hiro
                if (MSG_IS_NEW(*flags)) (*marksum->new)++;
682 1 hiro
                if (MSG_IS_UNREAD(*flags)) (*marksum->unread)++;
683 1 hiro
                if (num > *marksum->max) *marksum->max = num;
684 1 hiro
                if (num < *marksum->min || *marksum->min == 0) *marksum->min = num;
685 1 hiro
                (*marksum->total)++;
686 1 hiro
        }
687 1 hiro
688 1 hiro
        g_free(flags);
689 1 hiro
}
690 1 hiro
691 1 hiro
void procmsg_get_mark_sum(FolderItem *item,
692 1 hiro
                          gint *new, gint *unread, gint *total,
693 1 hiro
                          gint *min, gint *max,
694 1 hiro
                          gint first)
695 1 hiro
{
696 1 hiro
        GHashTable *mark_table;
697 1 hiro
        struct MarkSum marksum;
698 1 hiro
699 1 hiro
        *new = *unread = *total = *min = *max = 0;
700 1 hiro
        marksum.new    = new;
701 1 hiro
        marksum.unread = unread;
702 1 hiro
        marksum.total  = total;
703 1 hiro
        marksum.min    = min;
704 1 hiro
        marksum.max    = max;
705 1 hiro
        marksum.first  = first;
706 1 hiro
707 1 hiro
        mark_table = procmsg_read_mark_file(item);
708 1 hiro
709 1 hiro
        if (mark_table) {
710 1 hiro
                g_hash_table_foreach(mark_table, mark_sum_func, &marksum);
711 1 hiro
                g_hash_table_destroy(mark_table);
712 1 hiro
        }
713 1 hiro
}
714 1 hiro
715 1 hiro
static GHashTable *procmsg_read_mark_file(FolderItem *item)
716 1 hiro
{
717 1 hiro
        FILE *fp;
718 1 hiro
        GHashTable *mark_table = NULL;
719 1 hiro
        guint32 idata;
720 1 hiro
        guint num;
721 1 hiro
        MsgFlags *flags;
722 1 hiro
        MsgPermFlags perm_flags;
723 1 hiro
        GSList *cur;
724 1 hiro
725 1 hiro
        if ((fp = procmsg_open_mark_file(item, DATA_READ)) == NULL)
726 1 hiro
                return NULL;
727 1 hiro
728 1 hiro
        mark_table = g_hash_table_new(NULL, g_direct_equal);
729 1 hiro
730 1 hiro
        while (fread(&idata, sizeof(idata), 1, fp) == 1) {
731 1 hiro
                num = idata;
732 1 hiro
                if (fread(&idata, sizeof(idata), 1, fp) != 1) break;
733 1 hiro
                perm_flags = idata;
734 1 hiro
735 1 hiro
                flags = g_hash_table_lookup(mark_table, GUINT_TO_POINTER(num));
736 1 hiro
                if (flags != NULL)
737 1 hiro
                        g_free(flags);
738 1 hiro
739 1 hiro
                flags = g_new0(MsgFlags, 1);
740 1 hiro
                flags->perm_flags = perm_flags;
741 1 hiro
742 1 hiro
                g_hash_table_insert(mark_table, GUINT_TO_POINTER(num), flags);
743 1 hiro
        }
744 1 hiro
745 1 hiro
        fclose(fp);
746 1 hiro
747 1 hiro
        if (item->mark_queue) {
748 1 hiro
                g_hash_table_foreach(mark_table, mark_unset_new_func, NULL);
749 293 hiro
                item->mark_dirty = TRUE;
750 1 hiro
        }
751 1 hiro
752 1 hiro
        for (cur = item->mark_queue; cur != NULL; cur = cur->next) {
753 1 hiro
                MsgInfo *msginfo = (MsgInfo *)cur->data;
754 1 hiro
755 1 hiro
                flags = g_hash_table_lookup(mark_table,
756 1 hiro
                                            GUINT_TO_POINTER(msginfo->msgnum));
757 1 hiro
                if (flags != NULL)
758 1 hiro
                        g_free(flags);
759 1 hiro
760 1 hiro
                flags = g_new0(MsgFlags, 1);
761 1 hiro
                flags->perm_flags = msginfo->flags.perm_flags;
762 1 hiro
763 1 hiro
                g_hash_table_insert(mark_table,
764 1 hiro
                                    GUINT_TO_POINTER(msginfo->msgnum), flags);
765 1 hiro
766 1 hiro
        }
767 1 hiro
768 1 hiro
        if (item->mark_queue && !item->opened) {
769 1 hiro
                procmsg_write_mark_file(item, mark_table);
770 1 hiro
                procmsg_msg_list_free(item->mark_queue);
771 1 hiro
                item->mark_queue = NULL;
772 293 hiro
                item->mark_dirty = FALSE;
773 1 hiro
        }
774 1 hiro
775 1 hiro
        return mark_table;
776 1 hiro
}
777 1 hiro
778 1 hiro
static void write_mark_func(gpointer key, gpointer value, gpointer data)
779 1 hiro
{
780 1 hiro
        MsgInfo msginfo;
781 1 hiro
782 1 hiro
        msginfo.msgnum = GPOINTER_TO_UINT(key);
783 1 hiro
        msginfo.flags.perm_flags = ((MsgFlags *)value)->perm_flags;
784 1 hiro
        procmsg_write_flags(&msginfo, (FILE *)data);
785 1 hiro
}
786 1 hiro
787 1 hiro
static void procmsg_write_mark_file(FolderItem *item, GHashTable *mark_table)
788 1 hiro
{
789 1 hiro
        FILE *fp;
790 1 hiro
791 1 hiro
        fp = procmsg_open_mark_file(item, DATA_WRITE);
792 1 hiro
        g_hash_table_foreach(mark_table, write_mark_func, fp);
793 1 hiro
        fclose(fp);
794 1 hiro
}
795 1 hiro
796 869 hiro
FILE *procmsg_open_data_file(const gchar *file, guint version,
797 869 hiro
                             DataOpenMode mode, gchar *buf, size_t buf_size)
798 1 hiro
{
799 1 hiro
        FILE *fp;
800 1 hiro
        guint32 data_ver;
801 1 hiro
802 1 hiro
        g_return_val_if_fail(file != NULL, NULL);
803 1 hiro
804 1 hiro
        if (mode == DATA_WRITE) {
805 478 hiro
                if ((fp = g_fopen(file, "wb")) == NULL) {
806 1 hiro
                        FILE_OP_ERROR(file, "fopen");
807 1 hiro
                        return NULL;
808 1 hiro
                }
809 1 hiro
                if (change_file_mode_rw(fp, file) < 0)
810 1 hiro
                        FILE_OP_ERROR(file, "chmod");
811 1 hiro
812 1 hiro
                WRITE_CACHE_DATA_INT(version, fp);
813 1 hiro
                return fp;
814 1 hiro
        }
815 1 hiro
816 1 hiro
        /* check version */
817 478 hiro
        if ((fp = g_fopen(file, "rb")) == NULL)
818 191 hiro
                debug_print("Mark/Cache file '%s' not found\n", file);
819 1 hiro
        else {
820 1 hiro
                if (buf && buf_size > 0)
821 1 hiro
                        setvbuf(fp, buf, _IOFBF, buf_size);
822 1 hiro
                if (fread(&data_ver, sizeof(data_ver), 1, fp) != 1 ||
823 1 hiro
                    version != data_ver) {
824 191 hiro
                        g_message("%s: Mark/Cache version is different (%u != %u). Discarding it.\n",
825 191 hiro
                                  file, data_ver, version);
826 1 hiro
                        fclose(fp);
827 1 hiro
                        fp = NULL;
828 1 hiro
                }
829 1 hiro
        }
830 1 hiro
831 1 hiro
        if (mode == DATA_READ)
832 1 hiro
                return fp;
833 1 hiro
834 1 hiro
        if (fp) {
835 1 hiro
                /* reopen with append mode */
836 1 hiro
                fclose(fp);
837 478 hiro
                if ((fp = g_fopen(file, "ab")) == NULL)
838 1 hiro
                        FILE_OP_ERROR(file, "fopen");
839 1 hiro
        } else {
840 1 hiro
                /* open with overwrite mode if mark file doesn't exist or
841 1 hiro
                   version is different */
842 1 hiro
                fp = procmsg_open_data_file(file, version, DATA_WRITE, buf,
843 1 hiro
                                            buf_size);
844 1 hiro
        }
845 1 hiro
846 1 hiro
        return fp;
847 1 hiro
}
848 1 hiro
849 1 hiro
static FILE *procmsg_open_cache_file_with_buffer(FolderItem *item,
850 1 hiro
                                                 DataOpenMode mode,
851 1 hiro
                                                 gchar *buf, size_t buf_size)
852 1 hiro
{
853 1 hiro
        gchar *cachefile;
854 1 hiro
        FILE *fp;
855 1 hiro
856 1 hiro
        cachefile = folder_item_get_cache_file(item);
857 1 hiro
        fp = procmsg_open_data_file(cachefile, CACHE_VERSION, mode, buf,
858 1 hiro
                                    buf_size);
859 1 hiro
        g_free(cachefile);
860 1 hiro
861 1 hiro
        return fp;
862 1 hiro
}
863 1 hiro
864 1 hiro
FILE *procmsg_open_cache_file(FolderItem *item, DataOpenMode mode)
865 1 hiro
{
866 1 hiro
        gchar *cachefile;
867 1 hiro
        FILE *fp;
868 1 hiro
869 1 hiro
        cachefile = folder_item_get_cache_file(item);
870 1 hiro
        fp = procmsg_open_data_file(cachefile, CACHE_VERSION, mode, NULL, 0);
871 1 hiro
        g_free(cachefile);
872 1 hiro
873 1 hiro
        return fp;
874 1 hiro
}
875 1 hiro
876 1 hiro
FILE *procmsg_open_mark_file(FolderItem *item, DataOpenMode mode)
877 1 hiro
{
878 1 hiro
        gchar *markfile;
879 1 hiro
        FILE *fp;
880 1 hiro
881 1 hiro
        markfile = folder_item_get_mark_file(item);
882 1 hiro
        fp = procmsg_open_data_file(markfile, MARK_VERSION, mode, NULL, 0);
883 1 hiro
        g_free(markfile);
884 1 hiro
885 1 hiro
        return fp;
886 1 hiro
}
887 1 hiro
888 423 hiro
void procmsg_clear_cache(FolderItem *item)
889 423 hiro
{
890 423 hiro
        FILE *fp;
891 423 hiro
892 423 hiro
        fp = procmsg_open_cache_file(item, DATA_WRITE);
893 423 hiro
        if (fp)
894 423 hiro
                fclose(fp);
895 423 hiro
}
896 423 hiro
897 423 hiro
void procmsg_clear_mark(FolderItem *item)
898 423 hiro
{
899 423 hiro
        FILE *fp;
900 423 hiro
901 423 hiro
        fp = procmsg_open_mark_file(item, DATA_WRITE);
902 423 hiro
        if (fp)
903 423 hiro
                fclose(fp);
904 423 hiro
}
905 423 hiro
906 1 hiro
/* return the reversed thread tree */
907 1 hiro
GNode *procmsg_get_thread_tree(GSList *mlist)
908 1 hiro
{
909 1 hiro
        GNode *root, *parent, *node, *next;
910 1 hiro
        GHashTable *table;
911 1 hiro
        MsgInfo *msginfo;
912 1 hiro
        const gchar *msgid;
913 190 hiro
        GSList *reflist;
914 1 hiro
915 1 hiro
        root = g_node_new(NULL);
916 1 hiro
        table = g_hash_table_new(g_str_hash, g_str_equal);
917 1 hiro
918 1 hiro
        for (; mlist != NULL; mlist = mlist->next) {
919 1 hiro
                msginfo = (MsgInfo *)mlist->data;
920 191 hiro
                parent = root;
921 1 hiro
922 191 hiro
                /* only look for the real parent first */
923 191 hiro
                if (msginfo->inreplyto) {
924 1 hiro
                        parent = g_hash_table_lookup(table, msginfo->inreplyto);
925 191 hiro
                        if (parent == NULL)
926 191 hiro
                                parent = root;
927 1 hiro
                }
928 190 hiro
929 1 hiro
                node = g_node_insert_data_before
930 1 hiro
                        (parent, parent == root ? parent->children : NULL,
931 1 hiro
                         msginfo);
932 1 hiro
                if ((msgid = msginfo->msgid) &&
933 1 hiro
                    g_hash_table_lookup(table, msgid) == NULL)
934 1 hiro
                        g_hash_table_insert(table, (gchar *)msgid, node);
935 1 hiro
        }
936 1 hiro
937 1 hiro
        /* complete the unfinished threads */
938 1 hiro
        for (node = root->children; node != NULL; ) {
939 1 hiro
                next = node->next;
940 1 hiro
                msginfo = (MsgInfo *)node->data;
941 190 hiro
                parent = NULL;
942 190 hiro
943 190 hiro
                if (msginfo->inreplyto)
944 1 hiro
                        parent = g_hash_table_lookup(table, msginfo->inreplyto);
945 190 hiro
946 191 hiro
                /* try looking for the indirect parent */
947 190 hiro
                if (!parent && msginfo->references) {
948 190 hiro
                        for (reflist = msginfo->references;
949 190 hiro
                             reflist != NULL; reflist = reflist->next)
950 190 hiro
                                if ((parent = g_hash_table_lookup
951 190 hiro
                                        (table, reflist->data)) != NULL)
952 190 hiro
                                        break;
953 1 hiro
                }
954 190 hiro
955 190 hiro
                /* node should not be the parent, and node should not
956 190 hiro
                   be an ancestor of parent (circular reference) */
957 190 hiro
                if (parent && parent != node &&
958 190 hiro
                    !g_node_is_ancestor(node, parent)) {
959 190 hiro
                        g_node_unlink(node);
960 190 hiro
                        g_node_insert_before
961 190 hiro
                                (parent, parent->children, node);
962 190 hiro
                }
963 1 hiro
                node = next;
964 1 hiro
        }
965 1 hiro
966 1 hiro
        g_hash_table_destroy(table);
967 1 hiro
968 1 hiro
        return root;
969 1 hiro
}
970 1 hiro
971 574 hiro
static gboolean procmsg_thread_date_func(GNode *node, gpointer data)
972 574 hiro
{
973 574 hiro
        guint *tdate = (guint *)data;
974 574 hiro
        MsgInfo *msginfo = (MsgInfo *)node->data;
975 574 hiro
976 574 hiro
        if (*tdate < msginfo->date_t)
977 574 hiro
                *tdate = msginfo->date_t;
978 574 hiro
979 574 hiro
        return FALSE;
980 574 hiro
}
981 574 hiro
982 574 hiro
guint procmsg_get_thread_date(GNode *node)
983 574 hiro
{
984 574 hiro
        guint tdate = 0;
985 574 hiro
986 574 hiro
        g_return_val_if_fail(node != NULL && node->parent != NULL &&
987 574 hiro
                             node->parent->parent == NULL, 0);
988 574 hiro
989 574 hiro
        g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
990 574 hiro
                        procmsg_thread_date_func, &tdate);
991 574 hiro
992 574 hiro
        return tdate;
993 574 hiro
}
994 574 hiro
995 1 hiro
gint procmsg_move_messages(GSList *mlist)
996 1 hiro
{
997 1 hiro
        GSList *cur, *movelist = NULL;
998 1 hiro
        MsgInfo *msginfo;
999 1 hiro
        FolderItem *dest = NULL;
1000 1 hiro
        GHashTable *hash;
1001 1 hiro
        gint val = 0;
1002 1 hiro
1003 1 hiro
        if (!mlist) return 0;
1004 1 hiro
1005 1 hiro
        hash = procmsg_to_folder_hash_table_create(mlist);
1006 1 hiro
        folder_item_scan_foreach(hash);
1007 1 hiro
        g_hash_table_destroy(hash);
1008 1 hiro
1009 1 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
1010 1 hiro
                msginfo = (MsgInfo *)cur->data;
1011 1 hiro
                if (!dest) {
1012 1 hiro
                        dest = msginfo->to_folder;
1013 1 hiro
                        movelist = g_slist_append(movelist, msginfo);
1014 1 hiro
                } else if (dest == msginfo->to_folder) {
1015 1 hiro
                        movelist = g_slist_append(movelist, msginfo);
1016 1 hiro
                } else {
1017 1 hiro
                        val = folder_item_move_msgs(dest, movelist);
1018 1 hiro
                        g_slist_free(movelist);
1019 1 hiro
                        movelist = NULL;
1020 1 hiro
                        if (val == -1)
1021 1 hiro
                                return val;
1022 1 hiro
                        dest = msginfo->to_folder;
1023 1 hiro
                        movelist = g_slist_append(movelist, msginfo);
1024 1 hiro
                }
1025 1 hiro
        }
1026 1 hiro
1027 1 hiro
        if (movelist) {
1028 1 hiro
                val = folder_item_move_msgs(dest, movelist);
1029 1 hiro
                g_slist_free(movelist);
1030 1 hiro
        }
1031 1 hiro
1032 1 hiro
        return val == -1 ? -1 : 0;
1033 1 hiro
}
1034 1 hiro
1035 1 hiro
gint procmsg_copy_messages(GSList *mlist)
1036 1 hiro
{
1037 1 hiro
        GSList *cur, *copylist = NULL;
1038 1 hiro
        MsgInfo *msginfo;
1039 1 hiro
        FolderItem *dest = NULL;
1040 1 hiro
        GHashTable *hash;
1041 1 hiro
        gint val = 0;
1042 1 hiro
1043 1 hiro
        if (!mlist) return 0;
1044 1 hiro
1045 1 hiro
        hash = procmsg_to_folder_hash_table_create(mlist);
1046 1 hiro
        folder_item_scan_foreach(hash);
1047 1 hiro
        g_hash_table_destroy(hash);
1048 1 hiro
1049 1 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
1050 1 hiro
                msginfo = (MsgInfo *)cur->data;
1051 1 hiro
                if (!dest) {
1052 1 hiro
                        dest = msginfo->to_folder;
1053 1 hiro
                        copylist = g_slist_append(copylist, msginfo);
1054 1 hiro
                } else if (dest == msginfo->to_folder) {
1055 1 hiro
                        copylist = g_slist_append(copylist, msginfo);
1056 1 hiro
                } else {
1057 1 hiro
                        val = folder_item_copy_msgs(dest, copylist);
1058 1 hiro
                        g_slist_free(copylist);
1059 1 hiro
                        copylist = NULL;
1060 1 hiro
                        if (val == -1)
1061 1 hiro
                                return val;
1062 1 hiro
                        dest = msginfo->to_folder;
1063 1 hiro
                        copylist = g_slist_append(copylist, msginfo);
1064 1 hiro
                }
1065 1 hiro
        }
1066 1 hiro
1067 1 hiro
        if (copylist) {
1068 1 hiro
                val = folder_item_copy_msgs(dest, copylist);
1069 1 hiro
                g_slist_free(copylist);
1070 1 hiro
        }
1071 1 hiro
1072 1 hiro
        return val == -1 ? -1 : 0;
1073 1 hiro
}
1074 1 hiro
1075 1 hiro
gchar *procmsg_get_message_file_path(MsgInfo *msginfo)
1076 1 hiro
{
1077 1 hiro
        gchar *path, *file;
1078 1 hiro
1079 1 hiro
        g_return_val_if_fail(msginfo != NULL, NULL);
1080 1 hiro
1081 1 hiro
        if (msginfo->plaintext_file)
1082 1 hiro
                file = g_strdup(msginfo->plaintext_file);
1083 1 hiro
        else if (msginfo->file_path)
1084 1 hiro
                return g_strdup(msginfo->file_path);
1085 1 hiro
        else {
1086 1 hiro
                path = folder_item_get_path(msginfo->folder);
1087 1 hiro
                file = g_strconcat(path, G_DIR_SEPARATOR_S,
1088 1 hiro
                                   itos(msginfo->msgnum), NULL);
1089 1 hiro
                g_free(path);
1090 1 hiro
        }
1091 1 hiro
1092 1 hiro
        return file;
1093 1 hiro
}
1094 1 hiro
1095 1 hiro
gchar *procmsg_get_message_file(MsgInfo *msginfo)
1096 1 hiro
{
1097 1 hiro
        gchar *filename = NULL;
1098 1 hiro
1099 1 hiro
        g_return_val_if_fail(msginfo != NULL, NULL);
1100 1 hiro
1101 1 hiro
        if (msginfo->file_path)
1102 1 hiro
                return g_strdup(msginfo->file_path);
1103 1 hiro
1104 1 hiro
        filename = folder_item_fetch_msg(msginfo->folder, msginfo->msgnum);
1105 1 hiro
        if (!filename)
1106 1 hiro
                debug_print(_("can't fetch message %d\n"), msginfo->msgnum);
1107 1 hiro
1108 1 hiro
        return filename;
1109 1 hiro
}
1110 1 hiro
1111 1 hiro
GSList *procmsg_get_message_file_list(GSList *mlist)
1112 1 hiro
{
1113 1 hiro
        GSList *file_list = NULL;
1114 1 hiro
        MsgInfo *msginfo;
1115 1 hiro
        MsgFileInfo *fileinfo;
1116 1 hiro
        gchar *file;
1117 1 hiro
1118 1 hiro
        while (mlist != NULL) {
1119 1 hiro
                msginfo = (MsgInfo *)mlist->data;
1120 1 hiro
                file = procmsg_get_message_file(msginfo);
1121 1 hiro
                if (!file) {
1122 1 hiro
                        procmsg_message_file_list_free(file_list);
1123 1 hiro
                        return NULL;
1124 1 hiro
                }
1125 1 hiro
                fileinfo = g_new(MsgFileInfo, 1);
1126 1 hiro
                fileinfo->file = file;
1127 1 hiro
                fileinfo->flags = g_new(MsgFlags, 1);
1128 1 hiro
                *fileinfo->flags = msginfo->flags;
1129 1 hiro
                file_list = g_slist_prepend(file_list, fileinfo);
1130 1 hiro
                mlist = mlist->next;
1131 1 hiro
        }
1132 1 hiro
1133 1 hiro
        file_list = g_slist_reverse(file_list);
1134 1 hiro
1135 1 hiro
        return file_list;
1136 1 hiro
}
1137 1 hiro
1138 1 hiro
void procmsg_message_file_list_free(GSList *file_list)
1139 1 hiro
{
1140 1 hiro
        GSList *cur;
1141 1 hiro
        MsgFileInfo *fileinfo;
1142 1 hiro
1143 1 hiro
        for (cur = file_list; cur != NULL; cur = cur->next) {
1144 1 hiro
                fileinfo = (MsgFileInfo *)cur->data;
1145 1 hiro
                g_free(fileinfo->file);
1146 1 hiro
                g_free(fileinfo->flags);
1147 1 hiro
                g_free(fileinfo);
1148 1 hiro
        }
1149 1 hiro
1150 1 hiro
        g_slist_free(file_list);
1151 1 hiro
}
1152 1 hiro
1153 1 hiro
FILE *procmsg_open_message(MsgInfo *msginfo)
1154 1 hiro
{
1155 1 hiro
        FILE *fp;
1156 1 hiro
        gchar *file;
1157 1 hiro
1158 1 hiro
        g_return_val_if_fail(msginfo != NULL, NULL);
1159 1 hiro
1160 1 hiro
        file = procmsg_get_message_file_path(msginfo);
1161 1 hiro
        g_return_val_if_fail(file != NULL, NULL);
1162 1 hiro
1163 1 hiro
        if (!is_file_exist(file)) {
1164 1 hiro
                g_free(file);
1165 1 hiro
                file = procmsg_get_message_file(msginfo);
1166 1 hiro
                if (!file)
1167 1 hiro
                        return NULL;
1168 1 hiro
        }
1169 1 hiro
1170 478 hiro
        if ((fp = g_fopen(file, "rb")) == NULL) {
1171 1 hiro
                FILE_OP_ERROR(file, "fopen");
1172 1 hiro
                g_free(file);
1173 1 hiro
                return NULL;
1174 1 hiro
        }
1175 1 hiro
1176 1 hiro
        g_free(file);
1177 1 hiro
1178 1 hiro
        if (MSG_IS_QUEUED(msginfo->flags)) {
1179 1 hiro
                gchar buf[BUFFSIZE];
1180 1 hiro
1181 1 hiro
                while (fgets(buf, sizeof(buf), fp) != NULL)
1182 1 hiro
                        if (buf[0] == '\r' || buf[0] == '\n') break;
1183 1 hiro
        }
1184 1 hiro
1185 1 hiro
        return fp;
1186 1 hiro
}
1187 1 hiro
1188 548 hiro
static DecryptMessageFunc decrypt_message_func = NULL;
1189 548 hiro
1190 548 hiro
void procmsg_set_decrypt_message_func(DecryptMessageFunc func)
1191 548 hiro
{
1192 548 hiro
        decrypt_message_func = func;
1193 548 hiro
}
1194 548 hiro
1195 1 hiro
FILE *procmsg_open_message_decrypted(MsgInfo *msginfo, MimeInfo **mimeinfo)
1196 1 hiro
{
1197 1 hiro
        FILE *fp;
1198 1 hiro
1199 548 hiro
        if (decrypt_message_func)
1200 548 hiro
                return decrypt_message_func(msginfo, mimeinfo);
1201 1 hiro
1202 548 hiro
        *mimeinfo = NULL;
1203 548 hiro
        if ((fp = procmsg_open_message(msginfo)) == NULL)
1204 1 hiro
                return NULL;
1205 548 hiro
        *mimeinfo = procmime_scan_mime_header(fp);
1206 1 hiro
1207 1 hiro
        return fp;
1208 1 hiro
}
1209 1 hiro
1210 1 hiro
gboolean procmsg_msg_exist(MsgInfo *msginfo)
1211 1 hiro
{
1212 1 hiro
        gchar *path;
1213 1 hiro
        gboolean ret;
1214 1 hiro
1215 1 hiro
        if (!msginfo) return FALSE;
1216 1 hiro
1217 1 hiro
        path = folder_item_get_path(msginfo->folder);
1218 1 hiro
        change_dir(path);
1219 1 hiro
        ret = !folder_item_is_msg_changed(msginfo->folder, msginfo);
1220 1 hiro
        g_free(path);
1221 1 hiro
1222 1 hiro
        return ret;
1223 1 hiro
}
1224 1 hiro
1225 927 hiro
gboolean procmsg_trash_messages_exist(void)
1226 927 hiro
{
1227 927 hiro
        FolderItem *trash;
1228 927 hiro
        GList *cur;
1229 927 hiro
1230 927 hiro
        for (cur = folder_get_list(); cur != NULL; cur = cur->next) {
1231 927 hiro
                trash = FOLDER(cur->data)->trash;
1232 927 hiro
                if (trash && trash->total > 0)
1233 927 hiro
                        return TRUE;
1234 927 hiro
        }
1235 927 hiro
1236 927 hiro
        return FALSE;
1237 927 hiro
}
1238 927 hiro
1239 1 hiro
void procmsg_empty_trash(FolderItem *trash)
1240 1 hiro
{
1241 1 hiro
        if (trash && trash->total > 0) {
1242 1 hiro
                debug_print("Emptying messages in %s ...\n", trash->path);
1243 1 hiro
1244 1 hiro
                folder_item_remove_all_msg(trash);
1245 423 hiro
                procmsg_clear_cache(trash);
1246 423 hiro
                procmsg_clear_mark(trash);
1247 346 hiro
                trash->cache_dirty = FALSE;
1248 346 hiro
                trash->mark_dirty = FALSE;
1249 1 hiro
        }
1250 1 hiro
}
1251 1 hiro
1252 1 hiro
void procmsg_empty_all_trash(void)
1253 1 hiro
{
1254 1 hiro
        FolderItem *trash;
1255 1 hiro
        GList *cur;
1256 1 hiro
1257 1 hiro
        for (cur = folder_get_list(); cur != NULL; cur = cur->next) {
1258 1 hiro
                trash = FOLDER(cur->data)->trash;
1259 1 hiro
                procmsg_empty_trash(trash);
1260 1 hiro
        }
1261 1 hiro
}
1262 1 hiro
1263 919 hiro
static gboolean remove_all_cached_messages_func(GNode *node, gpointer data)
1264 919 hiro
{
1265 919 hiro
        FolderItem *item;
1266 919 hiro
        gchar *dir;
1267 919 hiro
1268 919 hiro
        g_return_val_if_fail(node->data != NULL, FALSE);
1269 919 hiro
1270 919 hiro
        item = FOLDER_ITEM(node->data);
1271 920 hiro
        if (!item->path || item->stype == F_VIRTUAL)
1272 919 hiro
                return FALSE;
1273 919 hiro
1274 919 hiro
        dir = folder_item_get_path(item);
1275 919 hiro
        if (is_dir_exist(dir)) {
1276 919 hiro
                debug_print("removing all cached messages in '%s' ...\n",
1277 919 hiro
                            item->path);
1278 919 hiro
                remove_all_numbered_files(dir);
1279 919 hiro
        }
1280 919 hiro
        g_free(dir);
1281 919 hiro
1282 919 hiro
        return FALSE;
1283 919 hiro
}
1284 919 hiro
1285 919 hiro
void procmsg_remove_all_cached_messages(Folder *folder)
1286 919 hiro
{
1287 919 hiro
        g_return_if_fail(folder != NULL);
1288 919 hiro
        g_return_if_fail(FOLDER_IS_REMOTE(folder));
1289 919 hiro
1290 919 hiro
        debug_print("Removing all caches in the mailbox '%s' ...\n",
1291 919 hiro
                    folder->name);
1292 919 hiro
1293 919 hiro
        g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1294 919 hiro
                        remove_all_cached_messages_func, NULL);
1295 919 hiro
}
1296 919 hiro
1297 317 hiro
gint procmsg_save_to_outbox(FolderItem *outbox, const gchar *file)
1298 1 hiro
{
1299 1 hiro
        gint num;
1300 1 hiro
        MsgFlags flag = {0, 0};
1301 1 hiro
1302 1 hiro
        debug_print("saving sent message...\n");
1303 1 hiro
1304 1 hiro
        if (!outbox)
1305 1 hiro
                outbox = folder_get_default_outbox();
1306 1 hiro
        g_return_val_if_fail(outbox != NULL, -1);
1307 1 hiro
1308 317 hiro
        folder_item_scan(outbox);
1309 317 hiro
        if ((num = folder_item_add_msg(outbox, file, &flag, FALSE)) < 0) {
1310 317 hiro
                g_warning("can't save message\n");
1311 317 hiro
                return -1;
1312 1 hiro
        }
1313 1 hiro
1314 1 hiro
        return 0;
1315 1 hiro
}
1316 1 hiro
1317 1038 hiro
void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline,
1318 1038 hiro
                           gboolean all_headers)
1319 1 hiro
{
1320 1 hiro
        static const gchar *def_cmd = "lpr %s";
1321 1 hiro
        static guint id = 0;
1322 1 hiro
        gchar *prtmp;
1323 679 hiro
        FILE *msgfp, *tmpfp, *prfp;
1324 679 hiro
        GPtrArray *headers;
1325 679 hiro
        gint i;
1326 1 hiro
        gchar buf[1024];
1327 1 hiro
1328 679 hiro
        g_return_if_fail(msginfo != NULL);
1329 1 hiro
1330 129 hiro
        if ((tmpfp = procmime_get_first_text_content
1331 129 hiro
                (msginfo, conv_get_locale_charset_str())) == NULL) {
1332 679 hiro
                g_warning("Can't get text part\n");
1333 1 hiro
                return;
1334 1 hiro
        }
1335 1 hiro
1336 680 hiro
        prtmp = g_strdup_printf("%s%cprinttmp-%08x.txt",
1337 1 hiro
                                get_mime_tmp_dir(), G_DIR_SEPARATOR, id++);
1338 1 hiro
1339 478 hiro
        if ((prfp = g_fopen(prtmp, "wb")) == NULL) {
1340 1 hiro
                FILE_OP_ERROR(prtmp, "fopen");
1341 1 hiro
                g_free(prtmp);
1342 1 hiro
                fclose(tmpfp);
1343 1 hiro
                return;
1344 1 hiro
        }
1345 1 hiro
1346 679 hiro
        if ((msgfp = procmsg_open_message(msginfo)) == NULL) {
1347 679 hiro
                fclose(prfp);
1348 679 hiro
                g_free(prtmp);
1349 679 hiro
                fclose(tmpfp);
1350 679 hiro
                return;
1351 129 hiro
        }
1352 129 hiro
1353 1038 hiro
        if (all_headers)
1354 1038 hiro
                headers = procheader_get_header_array_asis(msgfp, NULL);
1355 1038 hiro
        else
1356 1038 hiro
                headers = procheader_get_header_array_for_display(msgfp, NULL);
1357 1038 hiro
1358 679 hiro
        fclose(msgfp);
1359 679 hiro
1360 679 hiro
        for (i = 0; i < headers->len; i++) {
1361 679 hiro
                Header *hdr;
1362 679 hiro
                gchar *locale_str;
1363 679 hiro
                const gchar *body;
1364 679 hiro
1365 679 hiro
                hdr = g_ptr_array_index(headers, i);
1366 679 hiro
1367 679 hiro
                if (!g_ascii_strcasecmp(hdr->name, "Subject"))
1368 679 hiro
                        body = msginfo->subject;
1369 679 hiro
                else if (!g_ascii_strcasecmp(hdr->name, "From"))
1370 679 hiro
                        body = msginfo->from;
1371 679 hiro
                else if (!g_ascii_strcasecmp(hdr->name, "To"))
1372 679 hiro
                        body = msginfo->to;
1373 679 hiro
                else if (!g_ascii_strcasecmp(hdr->name, "Cc")) {
1374 679 hiro
                        unfold_line(hdr->body);
1375 679 hiro
                        body = hdr->body;
1376 679 hiro
                        while (g_ascii_isspace(*body))
1377 679 hiro
                                body++;
1378 679 hiro
                } else {
1379 679 hiro
                        body = hdr->body;
1380 679 hiro
                        while (g_ascii_isspace(*body))
1381 679 hiro
                                body++;
1382 679 hiro
                }
1383 679 hiro
1384 679 hiro
                locale_str = conv_codeset_strdup
1385 679 hiro
                        (body, CS_INTERNAL, conv_get_locale_charset_str());
1386 679 hiro
                fprintf(prfp, "%s: %s\n", hdr->name,
1387 679 hiro
                        locale_str ? locale_str : body);
1388 679 hiro
                g_free(locale_str);
1389 679 hiro
        }
1390 679 hiro
1391 679 hiro
        procheader_header_array_destroy(headers);
1392 679 hiro
1393 1 hiro
        fputc('\n', prfp);
1394 1 hiro
1395 1 hiro
        while (fgets(buf, sizeof(buf), tmpfp) != NULL)
1396 1 hiro
                fputs(buf, prfp);
1397 1 hiro
1398 1 hiro
        fclose(prfp);
1399 1 hiro
        fclose(tmpfp);
1400 1 hiro
1401 680 hiro
#ifdef G_OS_WIN32
1402 683 hiro
        if (canonicalize_file_replace(prtmp) < 0) {
1403 680 hiro
                g_free(prtmp);
1404 680 hiro
                return;
1405 680 hiro
        }
1406 680 hiro
#endif
1407 680 hiro
1408 1035 hiro
        if (cmdline && str_find_format_times(cmdline, 's') == 1)
1409 1 hiro
                g_snprintf(buf, sizeof(buf) - 1, cmdline, prtmp);
1410 1 hiro
        else {
1411 680 hiro
                if (cmdline) {
1412 1 hiro
                        g_warning(_("Print command line is invalid: `%s'\n"),
1413 1 hiro
                                  cmdline);
1414 680 hiro
                        g_free(prtmp);
1415 680 hiro
                        return;
1416 680 hiro
                }
1417 680 hiro
1418 680 hiro
#ifdef G_OS_WIN32
1419 680 hiro
                execute_print_file(prtmp);
1420 680 hiro
                g_free(prtmp);
1421 680 hiro
                return;
1422 680 hiro
#else
1423 1 hiro
                g_snprintf(buf, sizeof(buf) - 1, def_cmd, prtmp);
1424 680 hiro
#endif
1425 1 hiro
        }
1426 1 hiro
1427 1 hiro
        g_free(prtmp);
1428 1 hiro
1429 1 hiro
        g_strchomp(buf);
1430 1 hiro
        if (buf[strlen(buf) - 1] != '&') strcat(buf, "&");
1431 1 hiro
        system(buf);
1432 1 hiro
}
1433 1 hiro
1434 1 hiro
MsgInfo *procmsg_msginfo_copy(MsgInfo *msginfo)
1435 1 hiro
{
1436 1 hiro
        MsgInfo *newmsginfo;
1437 1 hiro
1438 1 hiro
        if (msginfo == NULL) return NULL;
1439 1 hiro
1440 1 hiro
        newmsginfo = g_new0(MsgInfo, 1);
1441 1 hiro
1442 1 hiro
#define MEMBCOPY(mmb)        newmsginfo->mmb = msginfo->mmb
1443 1 hiro
#define MEMBDUP(mmb)        newmsginfo->mmb = msginfo->mmb ? \
1444 1 hiro
                        g_strdup(msginfo->mmb) : NULL
1445 1 hiro
1446 1 hiro
        MEMBCOPY(msgnum);
1447 1 hiro
        MEMBCOPY(size);
1448 1 hiro
        MEMBCOPY(mtime);
1449 1 hiro
        MEMBCOPY(date_t);
1450 1 hiro
1451 1 hiro
        MEMBCOPY(flags);
1452 1 hiro
1453 1 hiro
        MEMBDUP(fromname);
1454 1 hiro
1455 1 hiro
        MEMBDUP(date);
1456 1 hiro
        MEMBDUP(from);
1457 1 hiro
        MEMBDUP(to);
1458 1 hiro
        MEMBDUP(cc);
1459 1 hiro
        MEMBDUP(newsgroups);
1460 1 hiro
        MEMBDUP(subject);
1461 1 hiro
        MEMBDUP(msgid);
1462 1 hiro
        MEMBDUP(inreplyto);
1463 1 hiro
1464 1 hiro
        MEMBCOPY(folder);
1465 1 hiro
        MEMBCOPY(to_folder);
1466 1 hiro
1467 1 hiro
        MEMBDUP(xface);
1468 1 hiro
1469 1 hiro
        MEMBDUP(file_path);
1470 1 hiro
1471 1 hiro
        MEMBDUP(plaintext_file);
1472 1 hiro
        MEMBCOPY(decryption_failed);
1473 1 hiro
1474 1 hiro
        return newmsginfo;
1475 1 hiro
}
1476 1 hiro
1477 1 hiro
MsgInfo *procmsg_msginfo_get_full_info(MsgInfo *msginfo)
1478 1 hiro
{
1479 1 hiro
        MsgInfo *full_msginfo;
1480 1 hiro
        gchar *file;
1481 1 hiro
1482 1 hiro
        if (msginfo == NULL) return NULL;
1483 1 hiro
1484 1 hiro
        file = procmsg_get_message_file(msginfo);
1485 1 hiro
        if (!file) {
1486 1 hiro
                g_warning("procmsg_msginfo_get_full_info(): can't get message file.\n");
1487 1 hiro
                return NULL;
1488 1 hiro
        }
1489 1 hiro
1490 1 hiro
        full_msginfo = procheader_parse_file(file, msginfo->flags, TRUE);
1491 1 hiro
        g_free(file);
1492 1 hiro
        if (!full_msginfo) return NULL;
1493 1 hiro
1494 1 hiro
        full_msginfo->msgnum = msginfo->msgnum;
1495 1 hiro
        full_msginfo->size = msginfo->size;
1496 1 hiro
        full_msginfo->mtime = msginfo->mtime;
1497 1 hiro
        full_msginfo->folder = msginfo->folder;
1498 1 hiro
        full_msginfo->to_folder = msginfo->to_folder;
1499 1 hiro
1500 1 hiro
        full_msginfo->file_path = g_strdup(msginfo->file_path);
1501 1 hiro
1502 1 hiro
        full_msginfo->plaintext_file = g_strdup(msginfo->plaintext_file);
1503 1 hiro
        full_msginfo->decryption_failed = msginfo->decryption_failed;
1504 1 hiro
1505 1 hiro
        return full_msginfo;
1506 1 hiro
}
1507 1 hiro
1508 409 hiro
gboolean procmsg_msginfo_equal(MsgInfo *msginfo_a, MsgInfo *msginfo_b)
1509 409 hiro
{
1510 409 hiro
        if (!msginfo_a || !msginfo_b)
1511 409 hiro
                return FALSE;
1512 409 hiro
1513 409 hiro
        if (msginfo_a == msginfo_b)
1514 409 hiro
                return TRUE;
1515 409 hiro
1516 409 hiro
        if (msginfo_a->folder == msginfo_b->folder &&
1517 409 hiro
            msginfo_a->msgnum == msginfo_b->msgnum &&
1518 409 hiro
            msginfo_a->size   == msginfo_b->size   &&
1519 409 hiro
            msginfo_a->mtime  == msginfo_b->mtime)
1520 409 hiro
                return TRUE;
1521 409 hiro
1522 409 hiro
        return FALSE;
1523 409 hiro
}
1524 409 hiro
1525 1 hiro
void procmsg_msginfo_free(MsgInfo *msginfo)
1526 1 hiro
{
1527 1 hiro
        if (msginfo == NULL) return;
1528 1 hiro
1529 1 hiro
        g_free(msginfo->xface);
1530 1 hiro
1531 1 hiro
        g_free(msginfo->fromname);
1532 1 hiro
1533 1 hiro
        g_free(msginfo->date);
1534 1 hiro
        g_free(msginfo->from);
1535 1 hiro
        g_free(msginfo->to);
1536 1 hiro
        g_free(msginfo->cc);
1537 1 hiro
        g_free(msginfo->newsgroups);
1538 1 hiro
        g_free(msginfo->subject);
1539 1 hiro
        g_free(msginfo->msgid);
1540 1 hiro
        g_free(msginfo->inreplyto);
1541 1 hiro
1542 190 hiro
        slist_free_strings(msginfo->references);
1543 190 hiro
        g_slist_free(msginfo->references);
1544 190 hiro
1545 1 hiro
        g_free(msginfo->file_path);
1546 1 hiro
1547 1 hiro
        g_free(msginfo->plaintext_file);
1548 1 hiro
1549 1 hiro
        g_free(msginfo);
1550 1 hiro
}
1551 1 hiro
1552 1 hiro
gint procmsg_cmp_msgnum_for_sort(gconstpointer a, gconstpointer b)
1553 1 hiro
{
1554 1 hiro
        const MsgInfo *msginfo1 = a;
1555 1 hiro
        const MsgInfo *msginfo2 = b;
1556 1 hiro
1557 496 hiro
        if (!msginfo1 || !msginfo2)
1558 496 hiro
                return 0;
1559 1 hiro
1560 1 hiro
        return msginfo1->msgnum - msginfo2->msgnum;
1561 1 hiro
}
1562 1 hiro
1563 1 hiro
#define CMP_FUNC_DEF(func_name, val)                                        \
1564 1 hiro
static gint func_name(gconstpointer a, gconstpointer b)                        \
1565 1 hiro
{                                                                        \
1566 1 hiro
        const MsgInfo *msginfo1 = a;                                        \
1567 1 hiro
        const MsgInfo *msginfo2 = b;                                        \
1568 496 hiro
        gint ret;                                                        \
1569 1 hiro
                                                                        \
1570 1 hiro
        if (!msginfo1 || !msginfo2)                                        \
1571 496 hiro
                return 0;                                                \
1572 1 hiro
                                                                        \
1573 496 hiro
        ret = (val);                                                        \
1574 496 hiro
        if (ret == 0)                                                        \
1575 496 hiro
                ret = msginfo1->date_t - msginfo2->date_t;                \
1576 496 hiro
                                                                        \
1577 496 hiro
        return ret * (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1);        \
1578 1 hiro
}
1579 1 hiro
1580 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_mark,
1581 1 hiro
             MSG_IS_MARKED(msginfo1->flags) - MSG_IS_MARKED(msginfo2->flags))
1582 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_unread,
1583 1 hiro
             MSG_IS_UNREAD(msginfo1->flags) - MSG_IS_UNREAD(msginfo2->flags))
1584 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_mime,
1585 1 hiro
             MSG_IS_MIME(msginfo1->flags) - MSG_IS_MIME(msginfo2->flags))
1586 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_label,
1587 1 hiro
             MSG_GET_COLORLABEL(msginfo1->flags) -
1588 1 hiro
             MSG_GET_COLORLABEL(msginfo2->flags))
1589 496 hiro
CMP_FUNC_DEF(procmsg_cmp_by_size, msginfo1->size - msginfo2->size)
1590 1 hiro
1591 496 hiro
#undef CMP_FUNC_DEF
1592 496 hiro
#define CMP_FUNC_DEF(func_name, val)                                        \
1593 496 hiro
static gint func_name(gconstpointer a, gconstpointer b)                        \
1594 496 hiro
{                                                                        \
1595 496 hiro
        const MsgInfo *msginfo1 = a;                                        \
1596 496 hiro
        const MsgInfo *msginfo2 = b;                                        \
1597 496 hiro
                                                                        \
1598 496 hiro
        if (!msginfo1 || !msginfo2)                                        \
1599 496 hiro
                return 0;                                                \
1600 496 hiro
                                                                        \
1601 496 hiro
        return (val) * (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1);        \
1602 496 hiro
}
1603 496 hiro
1604 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_number, msginfo1->msgnum - msginfo2->msgnum)
1605 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_date, msginfo1->date_t - msginfo2->date_t)
1606 1 hiro
1607 1 hiro
#undef CMP_FUNC_DEF
1608 1 hiro
#define CMP_FUNC_DEF(func_name, var_name)                                \
1609 1 hiro
static gint func_name(gconstpointer a, gconstpointer b)                        \
1610 1 hiro
{                                                                        \
1611 1 hiro
        const MsgInfo *msginfo1 = a;                                        \
1612 1 hiro
        const MsgInfo *msginfo2 = b;                                        \
1613 496 hiro
        gint ret;                                                        \
1614 1 hiro
                                                                        \
1615 1 hiro
        if (!msginfo1->var_name)                                        \
1616 496 hiro
                return (msginfo2->var_name != NULL) *                        \
1617 496 hiro
                        (cmp_func_sort_type == SORT_ASCENDING ? -1 : 1);\
1618 1 hiro
        if (!msginfo2->var_name)                                        \
1619 496 hiro
                return (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1);        \
1620 1 hiro
                                                                        \
1621 496 hiro
        ret = g_ascii_strcasecmp                                        \
1622 496 hiro
                (msginfo1->var_name, msginfo2->var_name);                \
1623 496 hiro
        if (ret == 0)                                                        \
1624 496 hiro
                ret = msginfo1->date_t - msginfo2->date_t;                \
1625 496 hiro
                                                                        \
1626 496 hiro
        return ret * (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1);        \
1627 1 hiro
}
1628 1 hiro
1629 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_from, fromname)
1630 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_to, to)
1631 1 hiro
1632 1 hiro
#undef CMP_FUNC_DEF
1633 1 hiro
1634 496 hiro
static gint procmsg_cmp_by_subject(gconstpointer a, gconstpointer b)
1635 496 hiro
{
1636 496 hiro
        const MsgInfo *msginfo1 = a;
1637 496 hiro
        const MsgInfo *msginfo2 = b;
1638 496 hiro
        gint ret;
1639 496 hiro
1640 496 hiro
        if (!msginfo1->subject)
1641 496 hiro
                return (msginfo2->subject != NULL) *
1642 496 hiro
                        (cmp_func_sort_type == SORT_ASCENDING ? -1 : 1);
1643 496 hiro
        if (!msginfo2->subject)
1644 496 hiro
                return (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1);
1645 496 hiro
1646 496 hiro
        ret = subject_compare_for_sort(msginfo1->subject, msginfo2->subject);
1647 496 hiro
        if (ret == 0)
1648 496 hiro
                ret = msginfo1->date_t - msginfo2->date_t;
1649 496 hiro
1650 496 hiro
        return ret * (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1);
1651 1 hiro
}