Statistics
| Revision:

root / libsylph / procmsg.c @ 2640

History | View | Annotate | Download (50.1 kB)

1 1 hiro
/*
2 578 hiro
 * LibSylph -- E-Mail client library
3 2608 hiro
 * Copyright (C) 1999-2010 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 1457 hiro
#include <errno.h>
27 1 hiro
28 1 hiro
#include "utils.h"
29 1 hiro
#include "procmsg.h"
30 1 hiro
#include "procheader.h"
31 1 hiro
#include "account.h"
32 1 hiro
#include "procmime.h"
33 317 hiro
#include "prefs_common.h"
34 1 hiro
#include "folder.h"
35 129 hiro
#include "codeconv.h"
36 1 hiro
37 2251 hiro
typedef struct _MsgFlagInfo {
38 2251 hiro
        guint msgnum;
39 2251 hiro
        MsgFlags flags;
40 2251 hiro
} MsgFlagInfo;
41 2251 hiro
42 2247 hiro
static GSList *procmsg_read_cache_queue                (FolderItem        *item,
43 2247 hiro
                                                 gboolean         scan_file);
44 2247 hiro
45 1 hiro
static void mark_sum_func                        (gpointer         key,
46 1 hiro
                                                 gpointer         value,
47 1 hiro
                                                 gpointer         data);
48 1 hiro
49 1 hiro
static GHashTable *procmsg_read_mark_file        (FolderItem        *item);
50 1 hiro
static void procmsg_write_mark_file                (FolderItem        *item,
51 1 hiro
                                                 GHashTable        *mark_table);
52 1 hiro
53 1 hiro
static FILE *procmsg_open_cache_file_with_buffer(FolderItem        *item,
54 1 hiro
                                                 DataOpenMode         mode,
55 1 hiro
                                                 gchar                *buf,
56 1 hiro
                                                 size_t                 buf_size);
57 1 hiro
58 1 hiro
static gint procmsg_cmp_by_mark                        (gconstpointer         a,
59 1 hiro
                                                 gconstpointer         b);
60 1 hiro
static gint procmsg_cmp_by_unread                (gconstpointer         a,
61 1 hiro
                                                 gconstpointer         b);
62 1 hiro
static gint procmsg_cmp_by_mime                        (gconstpointer         a,
63 1 hiro
                                                 gconstpointer         b);
64 1 hiro
static gint procmsg_cmp_by_label                (gconstpointer         a,
65 1 hiro
                                                 gconstpointer         b);
66 1 hiro
static gint procmsg_cmp_by_number                (gconstpointer         a,
67 1 hiro
                                                 gconstpointer         b);
68 1 hiro
static gint procmsg_cmp_by_size                        (gconstpointer         a,
69 1 hiro
                                                 gconstpointer         b);
70 1 hiro
static gint procmsg_cmp_by_date                        (gconstpointer         a,
71 1 hiro
                                                 gconstpointer         b);
72 1 hiro
static gint procmsg_cmp_by_from                        (gconstpointer         a,
73 1 hiro
                                                 gconstpointer         b);
74 1 hiro
static gint procmsg_cmp_by_to                        (gconstpointer         a,
75 1 hiro
                                                 gconstpointer         b);
76 1 hiro
static gint procmsg_cmp_by_subject                (gconstpointer         a,
77 1 hiro
                                                 gconstpointer         b);
78 1 hiro
79 1 hiro
80 1 hiro
GHashTable *procmsg_msg_hash_table_create(GSList *mlist)
81 1 hiro
{
82 1 hiro
        GHashTable *msg_table;
83 1 hiro
84 1 hiro
        if (mlist == NULL) return NULL;
85 1 hiro
86 1 hiro
        msg_table = g_hash_table_new(NULL, g_direct_equal);
87 1 hiro
        procmsg_msg_hash_table_append(msg_table, mlist);
88 1 hiro
89 1 hiro
        return msg_table;
90 1 hiro
}
91 1 hiro
92 1 hiro
void procmsg_msg_hash_table_append(GHashTable *msg_table, GSList *mlist)
93 1 hiro
{
94 1 hiro
        GSList *cur;
95 1 hiro
        MsgInfo *msginfo;
96 1 hiro
97 1 hiro
        if (msg_table == NULL || mlist == NULL) return;
98 1 hiro
99 1 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
100 1 hiro
                msginfo = (MsgInfo *)cur->data;
101 1 hiro
102 1 hiro
                g_hash_table_insert(msg_table,
103 1 hiro
                                    GUINT_TO_POINTER(msginfo->msgnum),
104 1 hiro
                                    msginfo);
105 1 hiro
        }
106 1 hiro
}
107 1 hiro
108 1 hiro
GHashTable *procmsg_to_folder_hash_table_create(GSList *mlist)
109 1 hiro
{
110 1 hiro
        GHashTable *msg_table;
111 1 hiro
        GSList *cur;
112 1 hiro
        MsgInfo *msginfo;
113 1 hiro
114 1 hiro
        if (mlist == NULL) return NULL;
115 1 hiro
116 1 hiro
        msg_table = g_hash_table_new(NULL, g_direct_equal);
117 1 hiro
118 1 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
119 1 hiro
                msginfo = (MsgInfo *)cur->data;
120 1 hiro
                g_hash_table_insert(msg_table, msginfo->to_folder, msginfo);
121 1 hiro
        }
122 1 hiro
123 1 hiro
        return msg_table;
124 1 hiro
}
125 1 hiro
126 869 hiro
gint procmsg_read_cache_data_str(FILE *fp, gchar **str)
127 1 hiro
{
128 1 hiro
        gchar buf[BUFFSIZE];
129 1 hiro
        gint ret = 0;
130 1 hiro
        guint32 len;
131 1 hiro
132 1 hiro
        if (fread(&len, sizeof(len), 1, fp) == 1) {
133 1 hiro
                if (len > G_MAXINT)
134 1 hiro
                        ret = -1;
135 1 hiro
                else {
136 1 hiro
                        gchar *tmp = NULL;
137 1 hiro
138 1 hiro
                        while (len > 0) {
139 1 hiro
                                size_t size = MIN(len, BUFFSIZE - 1);
140 1 hiro
141 1 hiro
                                if (fread(buf, size, 1, fp) != 1) {
142 1 hiro
                                        ret = -1;
143 1 hiro
                                        if (tmp) g_free(tmp);
144 1 hiro
                                        *str = NULL;
145 1 hiro
                                        break;
146 1 hiro
                                }
147 1 hiro
148 1 hiro
                                buf[size] = '\0';
149 1 hiro
                                if (tmp) {
150 1 hiro
                                        *str = g_strconcat(tmp, buf, NULL);
151 1 hiro
                                        g_free(tmp);
152 1 hiro
                                        tmp = *str;
153 1 hiro
                                } else
154 1 hiro
                                        tmp = *str = g_strdup(buf);
155 1 hiro
156 1 hiro
                                len -= size;
157 1 hiro
                        }
158 1 hiro
                }
159 1 hiro
        } else
160 1 hiro
                ret = -1;
161 1 hiro
162 1 hiro
        return ret;
163 1 hiro
}
164 1 hiro
165 1 hiro
#define READ_CACHE_DATA(data, fp)                                \
166 1 hiro
{                                                                \
167 1 hiro
        if (procmsg_read_cache_data_str(fp, &data) < 0) {        \
168 1155 hiro
                g_warning("Cache data is corrupted\n");                \
169 1 hiro
                procmsg_msginfo_free(msginfo);                        \
170 1 hiro
                procmsg_msg_list_free(mlist);                        \
171 1155 hiro
                fclose(fp);                                        \
172 1155 hiro
                return NULL;                                        \
173 1 hiro
        }                                                        \
174 1 hiro
}
175 1 hiro
176 1 hiro
#define READ_CACHE_DATA_INT(n, fp)                                \
177 1 hiro
{                                                                \
178 1 hiro
        guint32 idata;                                                \
179 1 hiro
                                                                \
180 1 hiro
        if (fread(&idata, sizeof(idata), 1, fp) != 1) {                \
181 1 hiro
                g_warning("Cache data is corrupted\n");                \
182 1 hiro
                procmsg_msginfo_free(msginfo);                        \
183 1 hiro
                procmsg_msg_list_free(mlist);                        \
184 1155 hiro
                fclose(fp);                                        \
185 1155 hiro
                return NULL;                                        \
186 1 hiro
        } else                                                        \
187 1 hiro
                n = idata;                                        \
188 1 hiro
}
189 1 hiro
190 1 hiro
GSList *procmsg_read_cache(FolderItem *item, gboolean scan_file)
191 1 hiro
{
192 1 hiro
        GSList *mlist = NULL;
193 1 hiro
        GSList *last = NULL;
194 1 hiro
        FILE *fp;
195 1 hiro
        MsgInfo *msginfo;
196 1 hiro
        MsgFlags default_flags;
197 1 hiro
        gchar file_buf[BUFFSIZE];
198 1 hiro
        guint32 num;
199 190 hiro
        guint refnum;
200 1 hiro
        FolderType type;
201 1 hiro
202 1 hiro
        g_return_val_if_fail(item != NULL, NULL);
203 1 hiro
        g_return_val_if_fail(item->folder != NULL, NULL);
204 1 hiro
        type = FOLDER_TYPE(item->folder);
205 1 hiro
206 1 hiro
        default_flags.perm_flags = MSG_NEW|MSG_UNREAD;
207 1 hiro
        default_flags.tmp_flags = 0;
208 1 hiro
        if (type == F_MH || type == F_IMAP) {
209 1 hiro
                if (item->stype == F_QUEUE) {
210 1 hiro
                        MSG_SET_TMP_FLAGS(default_flags, MSG_QUEUED);
211 1 hiro
                } else if (item->stype == F_DRAFT) {
212 1 hiro
                        MSG_SET_TMP_FLAGS(default_flags, MSG_DRAFT);
213 1 hiro
                }
214 1 hiro
        }
215 1 hiro
        if (type == F_IMAP) {
216 1 hiro
                MSG_SET_TMP_FLAGS(default_flags, MSG_IMAP);
217 1 hiro
        } else if (type == F_NEWS) {
218 1 hiro
                MSG_SET_TMP_FLAGS(default_flags, MSG_NEWS);
219 1 hiro
        }
220 1 hiro
221 1 hiro
        if (type == F_MH) {
222 1 hiro
                gchar *path;
223 1 hiro
224 1 hiro
                path = folder_item_get_path(item);
225 1 hiro
                if (change_dir(path) < 0) {
226 1 hiro
                        g_free(path);
227 1 hiro
                        return NULL;
228 1 hiro
                }
229 1 hiro
                g_free(path);
230 1 hiro
        }
231 1 hiro
232 1 hiro
        if ((fp = procmsg_open_cache_file_with_buffer
233 397 hiro
                (item, DATA_READ, file_buf, sizeof(file_buf))) == NULL) {
234 397 hiro
                item->cache_dirty = TRUE;
235 1 hiro
                return NULL;
236 397 hiro
        }
237 1 hiro
238 2247 hiro
        debug_print("Reading summary cache...\n");
239 1 hiro
240 1 hiro
        while (fread(&num, sizeof(num), 1, fp) == 1) {
241 1 hiro
                msginfo = g_new0(MsgInfo, 1);
242 1 hiro
                msginfo->msgnum = num;
243 1 hiro
                READ_CACHE_DATA_INT(msginfo->size, fp);
244 1 hiro
                READ_CACHE_DATA_INT(msginfo->mtime, fp);
245 1 hiro
                READ_CACHE_DATA_INT(msginfo->date_t, fp);
246 1 hiro
                READ_CACHE_DATA_INT(msginfo->flags.tmp_flags, fp);
247 1 hiro
248 1 hiro
                READ_CACHE_DATA(msginfo->fromname, fp);
249 1 hiro
250 1 hiro
                READ_CACHE_DATA(msginfo->date, fp);
251 1 hiro
                READ_CACHE_DATA(msginfo->from, fp);
252 1 hiro
                READ_CACHE_DATA(msginfo->to, fp);
253 1 hiro
                READ_CACHE_DATA(msginfo->newsgroups, fp);
254 1 hiro
                READ_CACHE_DATA(msginfo->subject, fp);
255 1 hiro
                READ_CACHE_DATA(msginfo->msgid, fp);
256 1 hiro
                READ_CACHE_DATA(msginfo->inreplyto, fp);
257 1 hiro
258 190 hiro
                READ_CACHE_DATA_INT(refnum, fp);
259 190 hiro
                for (; refnum != 0; refnum--) {
260 190 hiro
                        gchar *ref;
261 190 hiro
262 190 hiro
                        READ_CACHE_DATA(ref, fp);
263 190 hiro
                        msginfo->references =
264 190 hiro
                                g_slist_prepend(msginfo->references, ref);
265 190 hiro
                }
266 190 hiro
                if (msginfo->references)
267 190 hiro
                        msginfo->references =
268 190 hiro
                                g_slist_reverse(msginfo->references);
269 190 hiro
270 1 hiro
                MSG_SET_PERM_FLAGS(msginfo->flags, default_flags.perm_flags);
271 1 hiro
                MSG_SET_TMP_FLAGS(msginfo->flags, default_flags.tmp_flags);
272 1 hiro
273 1 hiro
                /* if the message file doesn't exist or is changed,
274 1 hiro
                   don't add the data */
275 20 hiro
                if ((type == F_MH && scan_file &&
276 285 hiro
                     folder_item_is_msg_changed(item, msginfo)) || num == 0) {
277 1 hiro
                        procmsg_msginfo_free(msginfo);
278 285 hiro
                        item->cache_dirty = TRUE;
279 285 hiro
                } else {
280 1 hiro
                        msginfo->folder = item;
281 1 hiro
282 1 hiro
                        if (!mlist)
283 1 hiro
                                last = mlist = g_slist_append(NULL, msginfo);
284 1 hiro
                        else {
285 1 hiro
                                last = g_slist_append(last, msginfo);
286 1 hiro
                                last = last->next;
287 1 hiro
                        }
288 1 hiro
                }
289 1 hiro
        }
290 1 hiro
291 1 hiro
        fclose(fp);
292 1 hiro
293 2247 hiro
        if (item->cache_queue) {
294 2247 hiro
                GSList *qlist;
295 2247 hiro
                qlist = procmsg_read_cache_queue(item, scan_file);
296 2247 hiro
                mlist = g_slist_concat(mlist, qlist);
297 2247 hiro
        }
298 2247 hiro
299 1 hiro
        debug_print("done.\n");
300 1 hiro
301 1 hiro
        return mlist;
302 1 hiro
}
303 1 hiro
304 1 hiro
#undef READ_CACHE_DATA
305 1 hiro
#undef READ_CACHE_DATA_INT
306 1 hiro
307 2247 hiro
static GSList *procmsg_read_cache_queue(FolderItem *item, gboolean scan_file)
308 2247 hiro
{
309 2247 hiro
        FolderType type;
310 2247 hiro
        MsgInfo *msginfo;
311 2247 hiro
        MsgFlags default_flags;
312 2247 hiro
        GSList *cur;
313 2247 hiro
        GSList *qlist = NULL;
314 2247 hiro
315 2247 hiro
        g_return_val_if_fail(item != NULL, NULL);
316 2247 hiro
        g_return_val_if_fail(item->folder != NULL, NULL);
317 2247 hiro
318 2247 hiro
        if (!item->cache_queue)
319 2247 hiro
                return NULL;
320 2247 hiro
321 2247 hiro
        debug_print("Reading cache queue...\n");
322 2247 hiro
323 2247 hiro
        type = FOLDER_TYPE(item->folder);
324 2247 hiro
        default_flags.perm_flags = MSG_NEW|MSG_UNREAD;
325 2247 hiro
        default_flags.tmp_flags = 0;
326 2247 hiro
327 2247 hiro
        for (cur = item->cache_queue; cur != NULL; cur = cur->next) {
328 2247 hiro
                msginfo = (MsgInfo *)cur->data;
329 2247 hiro
330 2247 hiro
                debug_print("read cache queue: %s/%d\n",
331 2247 hiro
                            item->path, msginfo->msgnum);
332 2247 hiro
333 2247 hiro
                MSG_SET_PERM_FLAGS(msginfo->flags, default_flags.perm_flags);
334 2247 hiro
                MSG_SET_TMP_FLAGS(msginfo->flags, default_flags.tmp_flags);
335 2247 hiro
336 2247 hiro
                if ((type == F_MH && scan_file &&
337 2247 hiro
                     folder_item_is_msg_changed(item, msginfo))) {
338 2247 hiro
                        procmsg_msginfo_free(msginfo);
339 2247 hiro
                        item->cache_dirty = TRUE;
340 2247 hiro
                } else {
341 2247 hiro
                        msginfo->folder = item;
342 2252 hiro
                        qlist = g_slist_prepend(qlist, msginfo);
343 2247 hiro
                }
344 2247 hiro
        }
345 2247 hiro
346 2247 hiro
        g_slist_free(item->cache_queue);
347 2247 hiro
        item->cache_queue = NULL;
348 2247 hiro
        item->cache_dirty = TRUE;
349 2247 hiro
350 2247 hiro
        return qlist;
351 2247 hiro
}
352 2247 hiro
353 1 hiro
static void mark_unset_new_func(gpointer key, gpointer value, gpointer data)
354 1 hiro
{
355 1 hiro
        MSG_UNSET_PERM_FLAGS(*((MsgFlags *)value), MSG_NEW);
356 1 hiro
}
357 1 hiro
358 1 hiro
void procmsg_set_flags(GSList *mlist, FolderItem *item)
359 1 hiro
{
360 1 hiro
        GSList *cur;
361 1 hiro
        gint new = 0, unread = 0, total = 0;
362 1 hiro
        gint lastnum = 0;
363 1 hiro
        gint unflagged = 0;
364 1 hiro
        gboolean mark_queue_exist;
365 1 hiro
        MsgInfo *msginfo;
366 1 hiro
        GHashTable *mark_table;
367 1 hiro
        MsgFlags *flags;
368 1 hiro
369 1 hiro
        g_return_if_fail(item != NULL);
370 1 hiro
        g_return_if_fail(item->folder != NULL);
371 1 hiro
372 1 hiro
        debug_print("Marking the messages...\n");
373 1 hiro
374 1 hiro
        mark_queue_exist = (item->mark_queue != NULL);
375 1 hiro
        mark_table = procmsg_read_mark_file(item);
376 1 hiro
        if (!mark_table) {
377 1 hiro
                item->new = item->unread = item->total = g_slist_length(mlist);
378 1 hiro
                item->updated = TRUE;
379 293 hiro
                item->mark_dirty = TRUE;
380 1 hiro
                return;
381 1 hiro
        }
382 1 hiro
383 1 hiro
        /* unset new flags if new (unflagged) messages exist */
384 1 hiro
        if (!mark_queue_exist) {
385 1 hiro
                for (cur = mlist; cur != NULL; cur = cur->next) {
386 1 hiro
                        msginfo = (MsgInfo *)cur->data;
387 1 hiro
                        flags = g_hash_table_lookup
388 1 hiro
                                (mark_table, GUINT_TO_POINTER(msginfo->msgnum));
389 1 hiro
                        if (!flags) {
390 1 hiro
                                g_hash_table_foreach(mark_table,
391 1 hiro
                                                     mark_unset_new_func, NULL);
392 293 hiro
                                item->mark_dirty = TRUE;
393 1 hiro
                                break;
394 1 hiro
                        }
395 1 hiro
                }
396 1 hiro
        }
397 1 hiro
398 1 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
399 1 hiro
                msginfo = (MsgInfo *)cur->data;
400 1 hiro
401 1 hiro
                if (lastnum < msginfo->msgnum)
402 1 hiro
                        lastnum = msginfo->msgnum;
403 1 hiro
404 1 hiro
                flags = g_hash_table_lookup
405 1 hiro
                        (mark_table, GUINT_TO_POINTER(msginfo->msgnum));
406 1 hiro
407 1 hiro
                if (flags != NULL) {
408 1 hiro
                        /* add the permanent flags only */
409 1 hiro
                        msginfo->flags.perm_flags = flags->perm_flags;
410 1 hiro
                        if (MSG_IS_NEW(*flags))
411 1 hiro
                                ++new;
412 1 hiro
                        if (MSG_IS_UNREAD(*flags))
413 1 hiro
                                ++unread;
414 1 hiro
                        if (FOLDER_TYPE(item->folder) == F_IMAP) {
415 1 hiro
                                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_IMAP);
416 1 hiro
                        } else if (FOLDER_TYPE(item->folder) == F_NEWS) {
417 1 hiro
                                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_NEWS);
418 1 hiro
                        }
419 1 hiro
                } else {
420 1 hiro
                        ++unflagged;
421 1 hiro
                        ++new;
422 1 hiro
                        ++unread;
423 1 hiro
                }
424 1 hiro
425 1 hiro
                ++total;
426 1 hiro
        }
427 1 hiro
428 1 hiro
        item->new = new;
429 1 hiro
        item->unread = unread;
430 1 hiro
        item->total = total;
431 1 hiro
        item->unmarked_num = unflagged;
432 1 hiro
        item->last_num = lastnum;
433 1 hiro
        item->updated = TRUE;
434 1 hiro
435 293 hiro
        if (unflagged > 0)
436 293 hiro
                item->mark_dirty = TRUE;
437 293 hiro
438 1 hiro
        debug_print("new: %d unread: %d unflagged: %d total: %d\n",
439 1 hiro
                    new, unread, unflagged, total);
440 1 hiro
441 1 hiro
        hash_free_value_mem(mark_table);
442 1 hiro
        g_hash_table_destroy(mark_table);
443 1 hiro
}
444 1 hiro
445 1082 hiro
static void mark_all_read_func(gpointer key, gpointer value, gpointer data)
446 1082 hiro
{
447 1082 hiro
        MSG_UNSET_PERM_FLAGS(*((MsgFlags *)value), MSG_NEW|MSG_UNREAD);
448 1082 hiro
}
449 1082 hiro
450 1082 hiro
void procmsg_mark_all_read(FolderItem *item)
451 1082 hiro
{
452 1082 hiro
        GHashTable *mark_table;
453 1082 hiro
454 1082 hiro
        debug_print("Marking all messages as read\n");
455 1082 hiro
456 1082 hiro
        mark_table = procmsg_read_mark_file(item);
457 1082 hiro
        if (mark_table) {
458 1082 hiro
                g_hash_table_foreach(mark_table, mark_all_read_func, NULL);
459 1082 hiro
                procmsg_write_mark_file(item, mark_table);
460 1082 hiro
                hash_free_value_mem(mark_table);
461 1082 hiro
                g_hash_table_destroy(mark_table);
462 1082 hiro
        }
463 1082 hiro
464 1082 hiro
        if (item->mark_queue) {
465 1082 hiro
                GSList *cur;
466 2251 hiro
                MsgFlagInfo *flaginfo;
467 1082 hiro
468 1082 hiro
                for (cur = item->mark_queue; cur != NULL; cur = cur->next) {
469 2251 hiro
                        flaginfo = (MsgFlagInfo *)cur->data;
470 1082 hiro
                        MSG_UNSET_PERM_FLAGS
471 2251 hiro
                                (flaginfo->flags, MSG_NEW|MSG_UNREAD);
472 1082 hiro
                }
473 1082 hiro
                item->mark_dirty = TRUE;
474 1082 hiro
        }
475 1082 hiro
476 1082 hiro
        item->new = item->unread = 0;
477 1082 hiro
}
478 1082 hiro
479 1 hiro
static FolderSortType cmp_func_sort_type;
480 1 hiro
481 1 hiro
GSList *procmsg_sort_msg_list(GSList *mlist, FolderSortKey sort_key,
482 1 hiro
                              FolderSortType sort_type)
483 1 hiro
{
484 1 hiro
        GCompareFunc cmp_func;
485 1 hiro
486 1 hiro
        switch (sort_key) {
487 1 hiro
        case SORT_BY_MARK:
488 1 hiro
                cmp_func = procmsg_cmp_by_mark; break;
489 1 hiro
        case SORT_BY_UNREAD:
490 1 hiro
                cmp_func = procmsg_cmp_by_unread; break;
491 1 hiro
        case SORT_BY_MIME:
492 1 hiro
                cmp_func = procmsg_cmp_by_mime; break;
493 1 hiro
        case SORT_BY_LABEL:
494 1 hiro
                cmp_func = procmsg_cmp_by_label; break;
495 1 hiro
        case SORT_BY_NUMBER:
496 1 hiro
                cmp_func = procmsg_cmp_by_number; break;
497 1 hiro
        case SORT_BY_SIZE:
498 1 hiro
                cmp_func = procmsg_cmp_by_size; break;
499 1 hiro
        case SORT_BY_DATE:
500 1 hiro
                cmp_func = procmsg_cmp_by_date; break;
501 1 hiro
        case SORT_BY_FROM:
502 1 hiro
                cmp_func = procmsg_cmp_by_from; break;
503 1 hiro
        case SORT_BY_SUBJECT:
504 1 hiro
                cmp_func = procmsg_cmp_by_subject; break;
505 1 hiro
        case SORT_BY_TO:
506 1 hiro
                cmp_func = procmsg_cmp_by_to; break;
507 1 hiro
        default:
508 1 hiro
                return mlist;
509 1 hiro
        }
510 1 hiro
511 1 hiro
        cmp_func_sort_type = sort_type;
512 1 hiro
513 1 hiro
        mlist = g_slist_sort(mlist, cmp_func);
514 1 hiro
515 1 hiro
        return mlist;
516 1 hiro
}
517 1 hiro
518 1 hiro
gint procmsg_get_last_num_in_msg_list(GSList *mlist)
519 1 hiro
{
520 1 hiro
        GSList *cur;
521 1 hiro
        MsgInfo *msginfo;
522 1 hiro
        gint last = 0;
523 1 hiro
524 1 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
525 1 hiro
                msginfo = (MsgInfo *)cur->data;
526 1 hiro
                if (msginfo && msginfo->msgnum > last)
527 1 hiro
                        last = msginfo->msgnum;
528 1 hiro
        }
529 1 hiro
530 1 hiro
        return last;
531 1 hiro
}
532 1 hiro
533 1 hiro
void procmsg_msg_list_free(GSList *mlist)
534 1 hiro
{
535 1 hiro
        GSList *cur;
536 1 hiro
        MsgInfo *msginfo;
537 1 hiro
538 1 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
539 1 hiro
                msginfo = (MsgInfo *)cur->data;
540 1 hiro
                procmsg_msginfo_free(msginfo);
541 1 hiro
        }
542 1 hiro
        g_slist_free(mlist);
543 1 hiro
}
544 1 hiro
545 1 hiro
void procmsg_write_cache(MsgInfo *msginfo, FILE *fp)
546 1 hiro
{
547 1 hiro
        MsgTmpFlags flags = msginfo->flags.tmp_flags & MSG_CACHED_FLAG_MASK;
548 190 hiro
        GSList *cur;
549 1 hiro
550 1 hiro
        WRITE_CACHE_DATA_INT(msginfo->msgnum, fp);
551 1 hiro
        WRITE_CACHE_DATA_INT(msginfo->size, fp);
552 1 hiro
        WRITE_CACHE_DATA_INT(msginfo->mtime, fp);
553 1 hiro
        WRITE_CACHE_DATA_INT(msginfo->date_t, fp);
554 1 hiro
        WRITE_CACHE_DATA_INT(flags, fp);
555 1 hiro
556 1 hiro
        WRITE_CACHE_DATA(msginfo->fromname, fp);
557 1 hiro
558 1 hiro
        WRITE_CACHE_DATA(msginfo->date, fp);
559 1 hiro
        WRITE_CACHE_DATA(msginfo->from, fp);
560 1 hiro
        WRITE_CACHE_DATA(msginfo->to, fp);
561 1 hiro
        WRITE_CACHE_DATA(msginfo->newsgroups, fp);
562 1 hiro
        WRITE_CACHE_DATA(msginfo->subject, fp);
563 1 hiro
        WRITE_CACHE_DATA(msginfo->msgid, fp);
564 1 hiro
        WRITE_CACHE_DATA(msginfo->inreplyto, fp);
565 190 hiro
566 190 hiro
        WRITE_CACHE_DATA_INT(g_slist_length(msginfo->references), fp);
567 190 hiro
        for (cur = msginfo->references; cur != NULL; cur = cur->next) {
568 190 hiro
                WRITE_CACHE_DATA((gchar *)cur->data, fp);
569 190 hiro
        }
570 1 hiro
}
571 1 hiro
572 1 hiro
void procmsg_write_flags(MsgInfo *msginfo, FILE *fp)
573 1 hiro
{
574 1 hiro
        MsgPermFlags flags = msginfo->flags.perm_flags;
575 1 hiro
576 1 hiro
        WRITE_CACHE_DATA_INT(msginfo->msgnum, fp);
577 1 hiro
        WRITE_CACHE_DATA_INT(flags, fp);
578 1 hiro
}
579 1 hiro
580 806 hiro
void procmsg_write_cache_list(FolderItem *item, GSList *mlist)
581 806 hiro
{
582 806 hiro
        FILE *fp;
583 806 hiro
        GSList *cur;
584 806 hiro
585 806 hiro
        g_return_if_fail(item != NULL);
586 806 hiro
587 806 hiro
        debug_print("Writing summary cache (%s)\n", item->path);
588 806 hiro
589 806 hiro
        fp = procmsg_open_cache_file(item, DATA_WRITE);
590 806 hiro
        if (fp == NULL)
591 806 hiro
                return;
592 806 hiro
593 806 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
594 806 hiro
                MsgInfo *msginfo = (MsgInfo *)cur->data;
595 806 hiro
                procmsg_write_cache(msginfo, fp);
596 806 hiro
        }
597 806 hiro
598 2247 hiro
        if (item->cache_queue)
599 2247 hiro
                procmsg_flush_cache_queue(item, fp);
600 2247 hiro
601 806 hiro
        fclose(fp);
602 806 hiro
        item->cache_dirty = FALSE;
603 806 hiro
}
604 806 hiro
605 806 hiro
void procmsg_write_flags_list(FolderItem *item, GSList *mlist)
606 806 hiro
{
607 806 hiro
        FILE *fp;
608 806 hiro
        GSList *cur;
609 806 hiro
610 806 hiro
        g_return_if_fail(item != NULL);
611 806 hiro
612 806 hiro
        debug_print("Writing summary flags (%s)\n", item->path);
613 806 hiro
614 806 hiro
        fp = procmsg_open_mark_file(item, DATA_WRITE);
615 806 hiro
        if (fp == NULL)
616 806 hiro
                return;
617 806 hiro
618 806 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
619 806 hiro
                MsgInfo *msginfo = (MsgInfo *)cur->data;
620 806 hiro
                procmsg_write_flags(msginfo, fp);
621 806 hiro
        }
622 806 hiro
623 806 hiro
        if (item->mark_queue)
624 806 hiro
                procmsg_flush_mark_queue(item, fp);
625 806 hiro
626 806 hiro
        fclose(fp);
627 806 hiro
        item->mark_dirty = FALSE;
628 806 hiro
}
629 806 hiro
630 850 hiro
static gint cmp_by_item(gconstpointer a, gconstpointer b)
631 850 hiro
{
632 850 hiro
        const MsgInfo *msginfo1 = a;
633 850 hiro
        const MsgInfo *msginfo2 = b;
634 850 hiro
635 850 hiro
        if (msginfo1->folder == msginfo2->folder)
636 850 hiro
                return msginfo1->msgnum - msginfo2->msgnum;
637 850 hiro
638 850 hiro
        return msginfo1->folder - msginfo2->folder;
639 850 hiro
}
640 850 hiro
641 850 hiro
void procmsg_write_flags_for_multiple_folders(GSList *mlist)
642 850 hiro
{
643 850 hiro
        GSList *tmp_list, *cur;
644 850 hiro
        FolderItem *prev_item = NULL;
645 850 hiro
        FILE *fp = NULL;
646 850 hiro
647 850 hiro
        if (!mlist)
648 850 hiro
                return;
649 850 hiro
650 850 hiro
        tmp_list = g_slist_copy(mlist);
651 850 hiro
        tmp_list = g_slist_sort(tmp_list, cmp_by_item);
652 850 hiro
653 850 hiro
        for (cur = tmp_list; cur != NULL; cur = cur->next) {
654 850 hiro
                MsgInfo *msginfo = (MsgInfo *)cur->data;
655 850 hiro
                FolderItem *item = msginfo->folder;
656 850 hiro
657 850 hiro
                if (prev_item != item) {
658 850 hiro
                        if (fp)
659 850 hiro
                                fclose(fp);
660 850 hiro
                        fp = procmsg_open_mark_file(item, DATA_APPEND);
661 850 hiro
                        if (!fp) {
662 850 hiro
                                g_warning("can't open mark file\n");
663 850 hiro
                                break;
664 850 hiro
                        }
665 850 hiro
                        item->updated = TRUE;
666 850 hiro
                }
667 850 hiro
                procmsg_write_flags(msginfo, fp);
668 850 hiro
                prev_item = item;
669 850 hiro
        }
670 850 hiro
671 850 hiro
        if (fp)
672 850 hiro
                fclose(fp);
673 850 hiro
        g_slist_free(tmp_list);
674 850 hiro
}
675 850 hiro
676 1 hiro
void procmsg_flush_mark_queue(FolderItem *item, FILE *fp)
677 1 hiro
{
678 2251 hiro
        MsgFlagInfo *flaginfo;
679 2251 hiro
        MsgInfo msginfo = {0};
680 2247 hiro
        gboolean append = FALSE;
681 2252 hiro
        GSList *qlist, *cur;
682 1 hiro
683 1 hiro
        g_return_if_fail(item != NULL);
684 1 hiro
685 2247 hiro
        if (!item->mark_queue)
686 2247 hiro
                return;
687 1 hiro
688 2252 hiro
        debug_print("flushing mark_queue: %s ...\n", item->path);
689 2247 hiro
690 2247 hiro
        if (!fp) {
691 2247 hiro
                append =  TRUE;
692 2247 hiro
                fp = procmsg_open_mark_file(item, DATA_APPEND);
693 2247 hiro
                g_return_if_fail(fp != NULL);
694 2247 hiro
        }
695 2247 hiro
696 2252 hiro
        qlist = g_slist_reverse(item->mark_queue);
697 2252 hiro
        item->mark_queue = NULL;
698 2252 hiro
699 2252 hiro
        for (cur = qlist; cur != NULL; cur = cur->next) {
700 2252 hiro
                flaginfo = (MsgFlagInfo *)cur->data;
701 2252 hiro
702 2251 hiro
                msginfo.msgnum = flaginfo->msgnum;
703 2251 hiro
                msginfo.flags = flaginfo->flags;
704 2251 hiro
                procmsg_write_flags(&msginfo, fp);
705 2251 hiro
                g_free(flaginfo);
706 1 hiro
        }
707 2247 hiro
708 2252 hiro
        g_slist_free(qlist);
709 2252 hiro
710 2247 hiro
        if (append)
711 2247 hiro
                fclose(fp);
712 1 hiro
}
713 1 hiro
714 1 hiro
void procmsg_add_mark_queue(FolderItem *item, gint num, MsgFlags flags)
715 1 hiro
{
716 2251 hiro
        MsgFlagInfo *flaginfo;
717 1 hiro
718 2251 hiro
        flaginfo = g_new(MsgFlagInfo, 1);
719 2251 hiro
        flaginfo->msgnum = num;
720 2251 hiro
        flaginfo->flags = flags;
721 2252 hiro
        item->mark_queue = g_slist_prepend(item->mark_queue, flaginfo);
722 1 hiro
}
723 1 hiro
724 2591 hiro
void procmsg_flaginfo_list_free(GSList *flaglist)
725 2251 hiro
{
726 2251 hiro
        GSList *cur;
727 2251 hiro
        MsgFlagInfo *flaginfo;
728 2251 hiro
729 2251 hiro
        for (cur = flaglist; cur != NULL; cur = cur->next) {
730 2251 hiro
                flaginfo = (MsgFlagInfo *)cur->data;
731 2251 hiro
                g_free(flaginfo);
732 2251 hiro
        }
733 2251 hiro
        g_slist_free(flaglist);
734 2251 hiro
}
735 2251 hiro
736 2247 hiro
void procmsg_flush_cache_queue(FolderItem *item, FILE *fp)
737 2247 hiro
{
738 2247 hiro
        MsgInfo *msginfo;
739 2247 hiro
        gboolean append = FALSE;
740 2252 hiro
        GSList *qlist, *cur;
741 2247 hiro
742 2247 hiro
        g_return_if_fail(item != NULL);
743 2247 hiro
744 2247 hiro
        if (!item->cache_queue)
745 2247 hiro
                return;
746 2247 hiro
747 2247 hiro
        debug_print("flushing cache_queue: %s ...\n", item->path);
748 2247 hiro
749 2247 hiro
        if (!fp) {
750 2247 hiro
                append =  TRUE;
751 2247 hiro
                fp = procmsg_open_cache_file(item, DATA_APPEND);
752 2247 hiro
                g_return_if_fail(fp != NULL);
753 2247 hiro
        }
754 2247 hiro
755 2252 hiro
        qlist = g_slist_reverse(item->cache_queue);
756 2252 hiro
        item->cache_queue = NULL;
757 2252 hiro
758 2252 hiro
        for (cur = qlist; cur != NULL; cur = cur->next) {
759 2252 hiro
                msginfo = (MsgInfo *)cur->data;
760 2252 hiro
761 2252 hiro
                debug_print("flush cache queue: %s/%d\n",
762 2252 hiro
                            item->path, msginfo->msgnum);
763 2247 hiro
                procmsg_write_cache(msginfo, fp);
764 2247 hiro
                procmsg_msginfo_free(msginfo);
765 2247 hiro
        }
766 2247 hiro
767 2252 hiro
        g_slist_free(qlist);
768 2252 hiro
769 2247 hiro
        if (append)
770 2247 hiro
                fclose(fp);
771 2247 hiro
}
772 2247 hiro
773 2247 hiro
void procmsg_add_cache_queue(FolderItem *item, gint num, MsgInfo *msginfo)
774 2247 hiro
{
775 2247 hiro
        MsgInfo *queue_msginfo;
776 2247 hiro
777 2247 hiro
        g_return_if_fail(msginfo != NULL);
778 2247 hiro
779 2247 hiro
        queue_msginfo = procmsg_msginfo_copy(msginfo);
780 2247 hiro
        queue_msginfo->msgnum = num;
781 2591 hiro
        queue_msginfo->folder = item;
782 2247 hiro
        if (queue_msginfo->file_path) {
783 2247 hiro
                g_free(queue_msginfo->file_path);
784 2247 hiro
                queue_msginfo->file_path = NULL;
785 2247 hiro
        }
786 2247 hiro
787 2247 hiro
        debug_print("procmsg_add_cache_queue: add msg cache: %s/%d\n",
788 2247 hiro
                    item->path, num);
789 2252 hiro
        item->cache_queue = g_slist_prepend(item->cache_queue, queue_msginfo);
790 2247 hiro
}
791 2247 hiro
792 2247 hiro
gboolean procmsg_flush_folder(FolderItem *item)
793 2247 hiro
{
794 2247 hiro
        gboolean flushed = FALSE;
795 2247 hiro
        gint n_new, n_unread, n_total, n_min, n_max;
796 2247 hiro
797 2247 hiro
        g_return_val_if_fail(item != NULL, FALSE);
798 2247 hiro
        g_return_val_if_fail(item->folder != NULL, FALSE);
799 2247 hiro
800 2247 hiro
        if (FOLDER_TYPE(item->folder) != F_MH || item->last_num < 0) {
801 2247 hiro
                folder_item_scan(item);
802 2247 hiro
                return TRUE;
803 2247 hiro
        }
804 2247 hiro
805 2247 hiro
        if (item->mark_queue && !item->opened)
806 2247 hiro
                flushed = TRUE;
807 2247 hiro
        procmsg_get_mark_sum(item, &n_new, &n_unread, &n_total, &n_min, &n_max,
808 2247 hiro
                             0);
809 2247 hiro
        item->unmarked_num = 0;
810 2247 hiro
        item->new = n_new;
811 2247 hiro
        item->unread = n_unread;
812 2247 hiro
        item->total = n_total;
813 2247 hiro
814 2247 hiro
        if (item->cache_queue && !item->opened) {
815 2247 hiro
                procmsg_flush_cache_queue(item, NULL);
816 2247 hiro
                flushed = TRUE;
817 2247 hiro
        }
818 2247 hiro
819 2247 hiro
        if (flushed)
820 2247 hiro
                debug_print("procmsg_flush_folder: flushed %s\n", item->path);
821 2247 hiro
822 2247 hiro
        return flushed;
823 2247 hiro
}
824 2247 hiro
825 2247 hiro
static void procmsg_flush_folder_foreach_func(gpointer key, gpointer val,
826 2247 hiro
                                              gpointer data)
827 2247 hiro
{
828 2247 hiro
        procmsg_flush_folder(FOLDER_ITEM(key));
829 2247 hiro
}
830 2247 hiro
831 2247 hiro
void procmsg_flush_folder_foreach(GHashTable *folder_table)
832 2247 hiro
{
833 2247 hiro
        g_hash_table_foreach(folder_table, procmsg_flush_folder_foreach_func,
834 2247 hiro
                             NULL);
835 2247 hiro
}
836 2247 hiro
837 1 hiro
void procmsg_add_flags(FolderItem *item, gint num, MsgFlags flags)
838 1 hiro
{
839 1 hiro
        FILE *fp;
840 1 hiro
        MsgInfo msginfo;
841 1 hiro
842 1 hiro
        g_return_if_fail(item != NULL);
843 1 hiro
844 1 hiro
        if (item->opened) {
845 1 hiro
                procmsg_add_mark_queue(item, num, flags);
846 1 hiro
                return;
847 1 hiro
        }
848 1 hiro
849 1 hiro
        if ((fp = procmsg_open_mark_file(item, DATA_APPEND)) == NULL) {
850 1 hiro
                g_warning(_("can't open mark file\n"));
851 1 hiro
                return;
852 1 hiro
        }
853 1 hiro
854 1 hiro
        msginfo.msgnum = num;
855 1 hiro
        msginfo.flags = flags;
856 1 hiro
857 1 hiro
        procmsg_write_flags(&msginfo, fp);
858 1 hiro
        fclose(fp);
859 1 hiro
}
860 1 hiro
861 1 hiro
struct MarkSum {
862 1 hiro
        gint *new;
863 1 hiro
        gint *unread;
864 1 hiro
        gint *total;
865 1 hiro
        gint *min;
866 1 hiro
        gint *max;
867 1 hiro
        gint first;
868 1 hiro
};
869 1 hiro
870 1 hiro
static void mark_sum_func(gpointer key, gpointer value, gpointer data)
871 1 hiro
{
872 1 hiro
        MsgFlags *flags = value;
873 1 hiro
        gint num = GPOINTER_TO_INT(key);
874 1 hiro
        struct MarkSum *marksum = data;
875 1 hiro
876 1 hiro
        if (marksum->first <= num) {
877 1 hiro
                if (MSG_IS_NEW(*flags)) (*marksum->new)++;
878 1 hiro
                if (MSG_IS_UNREAD(*flags)) (*marksum->unread)++;
879 1 hiro
                if (num > *marksum->max) *marksum->max = num;
880 1 hiro
                if (num < *marksum->min || *marksum->min == 0) *marksum->min = num;
881 1 hiro
                (*marksum->total)++;
882 1 hiro
        }
883 1 hiro
884 1 hiro
        g_free(flags);
885 1 hiro
}
886 1 hiro
887 1 hiro
void procmsg_get_mark_sum(FolderItem *item,
888 1 hiro
                          gint *new, gint *unread, gint *total,
889 1 hiro
                          gint *min, gint *max,
890 1 hiro
                          gint first)
891 1 hiro
{
892 1 hiro
        GHashTable *mark_table;
893 1 hiro
        struct MarkSum marksum;
894 1 hiro
895 1 hiro
        *new = *unread = *total = *min = *max = 0;
896 1 hiro
        marksum.new    = new;
897 1 hiro
        marksum.unread = unread;
898 1 hiro
        marksum.total  = total;
899 1 hiro
        marksum.min    = min;
900 1 hiro
        marksum.max    = max;
901 1 hiro
        marksum.first  = first;
902 1 hiro
903 1 hiro
        mark_table = procmsg_read_mark_file(item);
904 1 hiro
905 1 hiro
        if (mark_table) {
906 1 hiro
                g_hash_table_foreach(mark_table, mark_sum_func, &marksum);
907 1 hiro
                g_hash_table_destroy(mark_table);
908 1 hiro
        }
909 1 hiro
}
910 1 hiro
911 1 hiro
static GHashTable *procmsg_read_mark_file(FolderItem *item)
912 1 hiro
{
913 1 hiro
        FILE *fp;
914 1 hiro
        GHashTable *mark_table = NULL;
915 1 hiro
        guint32 idata;
916 1 hiro
        guint num;
917 1 hiro
        MsgFlags *flags;
918 1 hiro
        MsgPermFlags perm_flags;
919 1 hiro
        GSList *cur;
920 1 hiro
921 1 hiro
        if ((fp = procmsg_open_mark_file(item, DATA_READ)) == NULL)
922 1 hiro
                return NULL;
923 1 hiro
924 1 hiro
        mark_table = g_hash_table_new(NULL, g_direct_equal);
925 1 hiro
926 1 hiro
        while (fread(&idata, sizeof(idata), 1, fp) == 1) {
927 1 hiro
                num = idata;
928 1 hiro
                if (fread(&idata, sizeof(idata), 1, fp) != 1) break;
929 1 hiro
                perm_flags = idata;
930 1 hiro
931 1 hiro
                flags = g_hash_table_lookup(mark_table, GUINT_TO_POINTER(num));
932 1 hiro
                if (flags != NULL)
933 1 hiro
                        g_free(flags);
934 1 hiro
935 1 hiro
                flags = g_new0(MsgFlags, 1);
936 1 hiro
                flags->perm_flags = perm_flags;
937 1 hiro
938 1 hiro
                g_hash_table_insert(mark_table, GUINT_TO_POINTER(num), flags);
939 1 hiro
        }
940 1 hiro
941 1 hiro
        fclose(fp);
942 1 hiro
943 1 hiro
        if (item->mark_queue) {
944 1 hiro
                g_hash_table_foreach(mark_table, mark_unset_new_func, NULL);
945 293 hiro
                item->mark_dirty = TRUE;
946 1 hiro
        }
947 1 hiro
948 1 hiro
        for (cur = item->mark_queue; cur != NULL; cur = cur->next) {
949 2251 hiro
                MsgFlagInfo *flaginfo = (MsgFlagInfo *)cur->data;
950 1 hiro
951 1 hiro
                flags = g_hash_table_lookup(mark_table,
952 2251 hiro
                                            GUINT_TO_POINTER(flaginfo->msgnum));
953 1 hiro
                if (flags != NULL)
954 1 hiro
                        g_free(flags);
955 1 hiro
956 1 hiro
                flags = g_new0(MsgFlags, 1);
957 2251 hiro
                flags->perm_flags = flaginfo->flags.perm_flags;
958 1 hiro
959 1 hiro
                g_hash_table_insert(mark_table,
960 2251 hiro
                                    GUINT_TO_POINTER(flaginfo->msgnum), flags);
961 1 hiro
962 1 hiro
        }
963 1 hiro
964 1 hiro
        if (item->mark_queue && !item->opened) {
965 1 hiro
                procmsg_write_mark_file(item, mark_table);
966 2251 hiro
                procmsg_flaginfo_list_free(item->mark_queue);
967 1 hiro
                item->mark_queue = NULL;
968 293 hiro
                item->mark_dirty = FALSE;
969 1 hiro
        }
970 1 hiro
971 1 hiro
        return mark_table;
972 1 hiro
}
973 1 hiro
974 1 hiro
static void write_mark_func(gpointer key, gpointer value, gpointer data)
975 1 hiro
{
976 1 hiro
        MsgInfo msginfo;
977 1 hiro
978 1 hiro
        msginfo.msgnum = GPOINTER_TO_UINT(key);
979 1 hiro
        msginfo.flags.perm_flags = ((MsgFlags *)value)->perm_flags;
980 1 hiro
        procmsg_write_flags(&msginfo, (FILE *)data);
981 1 hiro
}
982 1 hiro
983 1 hiro
static void procmsg_write_mark_file(FolderItem *item, GHashTable *mark_table)
984 1 hiro
{
985 1 hiro
        FILE *fp;
986 1 hiro
987 2164 hiro
        if ((fp = procmsg_open_mark_file(item, DATA_WRITE)) == NULL) {
988 2164 hiro
                g_warning("procmsg_write_mark_file: cannot open mark file.");
989 1457 hiro
                return;
990 2164 hiro
        }
991 1 hiro
        g_hash_table_foreach(mark_table, write_mark_func, fp);
992 1 hiro
        fclose(fp);
993 1 hiro
}
994 1 hiro
995 869 hiro
FILE *procmsg_open_data_file(const gchar *file, guint version,
996 869 hiro
                             DataOpenMode mode, gchar *buf, size_t buf_size)
997 1 hiro
{
998 1 hiro
        FILE *fp;
999 1158 hiro
        guint32 data_ver = 0;
1000 1 hiro
1001 1 hiro
        g_return_val_if_fail(file != NULL, NULL);
1002 1 hiro
1003 1 hiro
        if (mode == DATA_WRITE) {
1004 478 hiro
                if ((fp = g_fopen(file, "wb")) == NULL) {
1005 1457 hiro
                        if (errno == EACCES) {
1006 1457 hiro
                                change_file_mode_rw(NULL, file);
1007 1457 hiro
                                if ((fp = g_fopen(file, "wb")) == NULL) {
1008 2164 hiro
                                        FILE_OP_ERROR(file, "procmsg_open_data_file: fopen");
1009 1457 hiro
                                        return NULL;
1010 1457 hiro
                                }
1011 1457 hiro
                        } else {
1012 2164 hiro
                                FILE_OP_ERROR(file, "procmsg_open_data_file: fopen");
1013 1457 hiro
                                return NULL;
1014 1457 hiro
                        }
1015 1 hiro
                }
1016 1 hiro
                if (change_file_mode_rw(fp, file) < 0)
1017 1 hiro
                        FILE_OP_ERROR(file, "chmod");
1018 1 hiro
1019 1 hiro
                WRITE_CACHE_DATA_INT(version, fp);
1020 1 hiro
                return fp;
1021 1 hiro
        }
1022 1 hiro
1023 1 hiro
        /* check version */
1024 1457 hiro
        if ((fp = g_fopen(file, "rb")) == NULL) {
1025 1457 hiro
                if (errno == EACCES) {
1026 1457 hiro
                        change_file_mode_rw(NULL, file);
1027 1457 hiro
                        if ((fp = g_fopen(file, "rb")) == NULL) {
1028 2164 hiro
                                FILE_OP_ERROR(file, "procmsg_open_data_file: fopen");
1029 1457 hiro
                        }
1030 1457 hiro
                } else {
1031 1457 hiro
                        debug_print("Mark/Cache file '%s' not found\n", file);
1032 1457 hiro
                }
1033 1486 hiro
        }
1034 1486 hiro
1035 1486 hiro
        if (fp) {
1036 1 hiro
                if (buf && buf_size > 0)
1037 1 hiro
                        setvbuf(fp, buf, _IOFBF, buf_size);
1038 2164 hiro
                if (fread(&data_ver, sizeof(data_ver), 1, fp) != 1) {
1039 2164 hiro
                        g_warning("%s: cannot read mark/cache file (truncated?)\n", file);
1040 2164 hiro
                        fclose(fp);
1041 2164 hiro
                        fp = NULL;
1042 2164 hiro
                } else if (version != data_ver) {
1043 191 hiro
                        g_message("%s: Mark/Cache version is different (%u != %u). Discarding it.\n",
1044 191 hiro
                                  file, data_ver, version);
1045 1 hiro
                        fclose(fp);
1046 1 hiro
                        fp = NULL;
1047 1 hiro
                }
1048 1 hiro
        }
1049 1 hiro
1050 1 hiro
        if (mode == DATA_READ)
1051 1 hiro
                return fp;
1052 1 hiro
1053 1 hiro
        if (fp) {
1054 1 hiro
                /* reopen with append mode */
1055 1 hiro
                fclose(fp);
1056 1457 hiro
                if ((fp = g_fopen(file, "ab")) == NULL) {
1057 1457 hiro
                        if (errno == EACCES) {
1058 1457 hiro
                                change_file_mode_rw(NULL, file);
1059 1457 hiro
                                if ((fp = g_fopen(file, "ab")) == NULL) {
1060 2164 hiro
                                        FILE_OP_ERROR(file, "procmsg_open_data_file: fopen");
1061 1457 hiro
                                }
1062 1457 hiro
                        } else {
1063 2164 hiro
                                FILE_OP_ERROR(file, "procmsg_open_data_file: fopen");
1064 1457 hiro
                        }
1065 1457 hiro
                }
1066 1 hiro
        } else {
1067 1 hiro
                /* open with overwrite mode if mark file doesn't exist or
1068 1 hiro
                   version is different */
1069 1 hiro
                fp = procmsg_open_data_file(file, version, DATA_WRITE, buf,
1070 1 hiro
                                            buf_size);
1071 1 hiro
        }
1072 1 hiro
1073 1 hiro
        return fp;
1074 1 hiro
}
1075 1 hiro
1076 1 hiro
static FILE *procmsg_open_cache_file_with_buffer(FolderItem *item,
1077 1 hiro
                                                 DataOpenMode mode,
1078 1 hiro
                                                 gchar *buf, size_t buf_size)
1079 1 hiro
{
1080 1 hiro
        gchar *cachefile;
1081 1 hiro
        FILE *fp;
1082 1 hiro
1083 1 hiro
        cachefile = folder_item_get_cache_file(item);
1084 1 hiro
        fp = procmsg_open_data_file(cachefile, CACHE_VERSION, mode, buf,
1085 1 hiro
                                    buf_size);
1086 1 hiro
        g_free(cachefile);
1087 1 hiro
1088 1 hiro
        return fp;
1089 1 hiro
}
1090 1 hiro
1091 1 hiro
FILE *procmsg_open_cache_file(FolderItem *item, DataOpenMode mode)
1092 1 hiro
{
1093 1 hiro
        gchar *cachefile;
1094 1 hiro
        FILE *fp;
1095 1 hiro
1096 1 hiro
        cachefile = folder_item_get_cache_file(item);
1097 1 hiro
        fp = procmsg_open_data_file(cachefile, CACHE_VERSION, mode, NULL, 0);
1098 1 hiro
        g_free(cachefile);
1099 1 hiro
1100 1 hiro
        return fp;
1101 1 hiro
}
1102 1 hiro
1103 1 hiro
FILE *procmsg_open_mark_file(FolderItem *item, DataOpenMode mode)
1104 1 hiro
{
1105 1 hiro
        gchar *markfile;
1106 1 hiro
        FILE *fp;
1107 1 hiro
1108 1 hiro
        markfile = folder_item_get_mark_file(item);
1109 1 hiro
        fp = procmsg_open_data_file(markfile, MARK_VERSION, mode, NULL, 0);
1110 1 hiro
        g_free(markfile);
1111 1 hiro
1112 1 hiro
        return fp;
1113 1 hiro
}
1114 1 hiro
1115 423 hiro
void procmsg_clear_cache(FolderItem *item)
1116 423 hiro
{
1117 423 hiro
        FILE *fp;
1118 423 hiro
1119 423 hiro
        fp = procmsg_open_cache_file(item, DATA_WRITE);
1120 423 hiro
        if (fp)
1121 423 hiro
                fclose(fp);
1122 423 hiro
}
1123 423 hiro
1124 423 hiro
void procmsg_clear_mark(FolderItem *item)
1125 423 hiro
{
1126 423 hiro
        FILE *fp;
1127 423 hiro
1128 423 hiro
        fp = procmsg_open_mark_file(item, DATA_WRITE);
1129 423 hiro
        if (fp)
1130 423 hiro
                fclose(fp);
1131 423 hiro
}
1132 423 hiro
1133 1 hiro
/* return the reversed thread tree */
1134 1 hiro
GNode *procmsg_get_thread_tree(GSList *mlist)
1135 1 hiro
{
1136 1 hiro
        GNode *root, *parent, *node, *next;
1137 1 hiro
        GHashTable *table;
1138 1 hiro
        MsgInfo *msginfo;
1139 1 hiro
        const gchar *msgid;
1140 190 hiro
        GSList *reflist;
1141 1 hiro
1142 1 hiro
        root = g_node_new(NULL);
1143 1 hiro
        table = g_hash_table_new(g_str_hash, g_str_equal);
1144 1 hiro
1145 1 hiro
        for (; mlist != NULL; mlist = mlist->next) {
1146 1 hiro
                msginfo = (MsgInfo *)mlist->data;
1147 191 hiro
                parent = root;
1148 1 hiro
1149 191 hiro
                /* only look for the real parent first */
1150 191 hiro
                if (msginfo->inreplyto) {
1151 1 hiro
                        parent = g_hash_table_lookup(table, msginfo->inreplyto);
1152 191 hiro
                        if (parent == NULL)
1153 191 hiro
                                parent = root;
1154 1 hiro
                }
1155 190 hiro
1156 1 hiro
                node = g_node_insert_data_before
1157 1 hiro
                        (parent, parent == root ? parent->children : NULL,
1158 1 hiro
                         msginfo);
1159 1 hiro
                if ((msgid = msginfo->msgid) &&
1160 1 hiro
                    g_hash_table_lookup(table, msgid) == NULL)
1161 1 hiro
                        g_hash_table_insert(table, (gchar *)msgid, node);
1162 1 hiro
        }
1163 1 hiro
1164 1 hiro
        /* complete the unfinished threads */
1165 1 hiro
        for (node = root->children; node != NULL; ) {
1166 1 hiro
                next = node->next;
1167 1 hiro
                msginfo = (MsgInfo *)node->data;
1168 190 hiro
                parent = NULL;
1169 190 hiro
1170 190 hiro
                if (msginfo->inreplyto)
1171 1 hiro
                        parent = g_hash_table_lookup(table, msginfo->inreplyto);
1172 190 hiro
1173 191 hiro
                /* try looking for the indirect parent */
1174 190 hiro
                if (!parent && msginfo->references) {
1175 190 hiro
                        for (reflist = msginfo->references;
1176 190 hiro
                             reflist != NULL; reflist = reflist->next)
1177 190 hiro
                                if ((parent = g_hash_table_lookup
1178 190 hiro
                                        (table, reflist->data)) != NULL)
1179 190 hiro
                                        break;
1180 1 hiro
                }
1181 190 hiro
1182 190 hiro
                /* node should not be the parent, and node should not
1183 190 hiro
                   be an ancestor of parent (circular reference) */
1184 190 hiro
                if (parent && parent != node &&
1185 190 hiro
                    !g_node_is_ancestor(node, parent)) {
1186 190 hiro
                        g_node_unlink(node);
1187 190 hiro
                        g_node_insert_before
1188 190 hiro
                                (parent, parent->children, node);
1189 190 hiro
                }
1190 1 hiro
                node = next;
1191 1 hiro
        }
1192 1 hiro
1193 1 hiro
        g_hash_table_destroy(table);
1194 1 hiro
1195 1 hiro
        return root;
1196 1 hiro
}
1197 1 hiro
1198 574 hiro
static gboolean procmsg_thread_date_func(GNode *node, gpointer data)
1199 574 hiro
{
1200 574 hiro
        guint *tdate = (guint *)data;
1201 574 hiro
        MsgInfo *msginfo = (MsgInfo *)node->data;
1202 574 hiro
1203 574 hiro
        if (*tdate < msginfo->date_t)
1204 574 hiro
                *tdate = msginfo->date_t;
1205 574 hiro
1206 574 hiro
        return FALSE;
1207 574 hiro
}
1208 574 hiro
1209 574 hiro
guint procmsg_get_thread_date(GNode *node)
1210 574 hiro
{
1211 574 hiro
        guint tdate = 0;
1212 574 hiro
1213 574 hiro
        g_return_val_if_fail(node != NULL && node->parent != NULL &&
1214 574 hiro
                             node->parent->parent == NULL, 0);
1215 574 hiro
1216 574 hiro
        g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1217 574 hiro
                        procmsg_thread_date_func, &tdate);
1218 574 hiro
1219 574 hiro
        return tdate;
1220 574 hiro
}
1221 574 hiro
1222 1 hiro
gint procmsg_move_messages(GSList *mlist)
1223 1 hiro
{
1224 1 hiro
        GSList *cur, *movelist = NULL;
1225 1 hiro
        MsgInfo *msginfo;
1226 1 hiro
        FolderItem *dest = NULL;
1227 1 hiro
        GHashTable *hash;
1228 1 hiro
        gint val = 0;
1229 1 hiro
1230 1 hiro
        if (!mlist) return 0;
1231 1 hiro
1232 1 hiro
        hash = procmsg_to_folder_hash_table_create(mlist);
1233 1 hiro
        folder_item_scan_foreach(hash);
1234 1 hiro
        g_hash_table_destroy(hash);
1235 1 hiro
1236 1 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
1237 1 hiro
                msginfo = (MsgInfo *)cur->data;
1238 1 hiro
                if (!dest) {
1239 1 hiro
                        dest = msginfo->to_folder;
1240 1 hiro
                        movelist = g_slist_append(movelist, msginfo);
1241 1 hiro
                } else if (dest == msginfo->to_folder) {
1242 1 hiro
                        movelist = g_slist_append(movelist, msginfo);
1243 1 hiro
                } else {
1244 1 hiro
                        val = folder_item_move_msgs(dest, movelist);
1245 1 hiro
                        g_slist_free(movelist);
1246 1 hiro
                        movelist = NULL;
1247 1 hiro
                        if (val == -1)
1248 1 hiro
                                return val;
1249 1 hiro
                        dest = msginfo->to_folder;
1250 1 hiro
                        movelist = g_slist_append(movelist, msginfo);
1251 1 hiro
                }
1252 1 hiro
        }
1253 1 hiro
1254 1 hiro
        if (movelist) {
1255 1 hiro
                val = folder_item_move_msgs(dest, movelist);
1256 1 hiro
                g_slist_free(movelist);
1257 1 hiro
        }
1258 1 hiro
1259 1 hiro
        return val == -1 ? -1 : 0;
1260 1 hiro
}
1261 1 hiro
1262 1 hiro
gint procmsg_copy_messages(GSList *mlist)
1263 1 hiro
{
1264 1 hiro
        GSList *cur, *copylist = NULL;
1265 1 hiro
        MsgInfo *msginfo;
1266 1 hiro
        FolderItem *dest = NULL;
1267 1 hiro
        GHashTable *hash;
1268 1 hiro
        gint val = 0;
1269 1 hiro
1270 1 hiro
        if (!mlist) return 0;
1271 1 hiro
1272 1 hiro
        hash = procmsg_to_folder_hash_table_create(mlist);
1273 1 hiro
        folder_item_scan_foreach(hash);
1274 1 hiro
        g_hash_table_destroy(hash);
1275 1 hiro
1276 1 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
1277 1 hiro
                msginfo = (MsgInfo *)cur->data;
1278 1 hiro
                if (!dest) {
1279 1 hiro
                        dest = msginfo->to_folder;
1280 1 hiro
                        copylist = g_slist_append(copylist, msginfo);
1281 1 hiro
                } else if (dest == msginfo->to_folder) {
1282 1 hiro
                        copylist = g_slist_append(copylist, msginfo);
1283 1 hiro
                } else {
1284 1 hiro
                        val = folder_item_copy_msgs(dest, copylist);
1285 1 hiro
                        g_slist_free(copylist);
1286 1 hiro
                        copylist = NULL;
1287 1 hiro
                        if (val == -1)
1288 1 hiro
                                return val;
1289 1 hiro
                        dest = msginfo->to_folder;
1290 1 hiro
                        copylist = g_slist_append(copylist, msginfo);
1291 1 hiro
                }
1292 1 hiro
        }
1293 1 hiro
1294 1 hiro
        if (copylist) {
1295 1 hiro
                val = folder_item_copy_msgs(dest, copylist);
1296 1 hiro
                g_slist_free(copylist);
1297 1 hiro
        }
1298 1 hiro
1299 1 hiro
        return val == -1 ? -1 : 0;
1300 1 hiro
}
1301 1 hiro
1302 1 hiro
gchar *procmsg_get_message_file_path(MsgInfo *msginfo)
1303 1 hiro
{
1304 1 hiro
        gchar *path, *file;
1305 1 hiro
1306 1 hiro
        g_return_val_if_fail(msginfo != NULL, NULL);
1307 1 hiro
1308 1128 hiro
        if (msginfo->encinfo && msginfo->encinfo->plaintext_file)
1309 1128 hiro
                file = g_strdup(msginfo->encinfo->plaintext_file);
1310 1 hiro
        else if (msginfo->file_path)
1311 1 hiro
                return g_strdup(msginfo->file_path);
1312 1 hiro
        else {
1313 2286 hiro
                gchar nstr[16];
1314 1 hiro
                path = folder_item_get_path(msginfo->folder);
1315 1 hiro
                file = g_strconcat(path, G_DIR_SEPARATOR_S,
1316 2327 hiro
                                   utos_buf(nstr, msginfo->msgnum), NULL);
1317 1 hiro
                g_free(path);
1318 1 hiro
        }
1319 1 hiro
1320 1 hiro
        return file;
1321 1 hiro
}
1322 1 hiro
1323 1 hiro
gchar *procmsg_get_message_file(MsgInfo *msginfo)
1324 1 hiro
{
1325 1 hiro
        gchar *filename = NULL;
1326 1 hiro
1327 1 hiro
        g_return_val_if_fail(msginfo != NULL, NULL);
1328 1 hiro
1329 1 hiro
        if (msginfo->file_path)
1330 1 hiro
                return g_strdup(msginfo->file_path);
1331 1 hiro
1332 1 hiro
        filename = folder_item_fetch_msg(msginfo->folder, msginfo->msgnum);
1333 1 hiro
        if (!filename)
1334 1 hiro
                debug_print(_("can't fetch message %d\n"), msginfo->msgnum);
1335 1 hiro
1336 1 hiro
        return filename;
1337 1 hiro
}
1338 1 hiro
1339 1 hiro
GSList *procmsg_get_message_file_list(GSList *mlist)
1340 1 hiro
{
1341 1 hiro
        GSList *file_list = NULL;
1342 1 hiro
        MsgInfo *msginfo;
1343 1 hiro
        MsgFileInfo *fileinfo;
1344 1 hiro
        gchar *file;
1345 1 hiro
1346 1 hiro
        while (mlist != NULL) {
1347 1 hiro
                msginfo = (MsgInfo *)mlist->data;
1348 1 hiro
                file = procmsg_get_message_file(msginfo);
1349 1 hiro
                if (!file) {
1350 1 hiro
                        procmsg_message_file_list_free(file_list);
1351 1 hiro
                        return NULL;
1352 1 hiro
                }
1353 1 hiro
                fileinfo = g_new(MsgFileInfo, 1);
1354 1 hiro
                fileinfo->file = file;
1355 1 hiro
                fileinfo->flags = g_new(MsgFlags, 1);
1356 1 hiro
                *fileinfo->flags = msginfo->flags;
1357 1 hiro
                file_list = g_slist_prepend(file_list, fileinfo);
1358 1 hiro
                mlist = mlist->next;
1359 1 hiro
        }
1360 1 hiro
1361 1 hiro
        file_list = g_slist_reverse(file_list);
1362 1 hiro
1363 1 hiro
        return file_list;
1364 1 hiro
}
1365 1 hiro
1366 1 hiro
void procmsg_message_file_list_free(GSList *file_list)
1367 1 hiro
{
1368 1 hiro
        GSList *cur;
1369 1 hiro
        MsgFileInfo *fileinfo;
1370 1 hiro
1371 1 hiro
        for (cur = file_list; cur != NULL; cur = cur->next) {
1372 1 hiro
                fileinfo = (MsgFileInfo *)cur->data;
1373 1 hiro
                g_free(fileinfo->file);
1374 1 hiro
                g_free(fileinfo->flags);
1375 1 hiro
                g_free(fileinfo);
1376 1 hiro
        }
1377 1 hiro
1378 1 hiro
        g_slist_free(file_list);
1379 1 hiro
}
1380 1 hiro
1381 1 hiro
FILE *procmsg_open_message(MsgInfo *msginfo)
1382 1 hiro
{
1383 1 hiro
        FILE *fp;
1384 1 hiro
        gchar *file;
1385 1 hiro
1386 1 hiro
        g_return_val_if_fail(msginfo != NULL, NULL);
1387 1 hiro
1388 1 hiro
        file = procmsg_get_message_file_path(msginfo);
1389 1 hiro
        g_return_val_if_fail(file != NULL, NULL);
1390 1 hiro
1391 1 hiro
        if (!is_file_exist(file)) {
1392 1 hiro
                g_free(file);
1393 1 hiro
                file = procmsg_get_message_file(msginfo);
1394 1 hiro
                if (!file)
1395 1 hiro
                        return NULL;
1396 1 hiro
        }
1397 1 hiro
1398 478 hiro
        if ((fp = g_fopen(file, "rb")) == NULL) {
1399 2164 hiro
                FILE_OP_ERROR(file, "procmsg_open_message: fopen");
1400 1 hiro
                g_free(file);
1401 1 hiro
                return NULL;
1402 1 hiro
        }
1403 1 hiro
1404 1 hiro
        g_free(file);
1405 1 hiro
1406 1 hiro
        if (MSG_IS_QUEUED(msginfo->flags)) {
1407 1 hiro
                gchar buf[BUFFSIZE];
1408 1 hiro
1409 1 hiro
                while (fgets(buf, sizeof(buf), fp) != NULL)
1410 1 hiro
                        if (buf[0] == '\r' || buf[0] == '\n') break;
1411 1 hiro
        }
1412 1 hiro
1413 1 hiro
        return fp;
1414 1 hiro
}
1415 1 hiro
1416 548 hiro
static DecryptMessageFunc decrypt_message_func = NULL;
1417 1896 hiro
static gboolean auto_decrypt = TRUE;
1418 548 hiro
1419 548 hiro
void procmsg_set_decrypt_message_func(DecryptMessageFunc func)
1420 548 hiro
{
1421 548 hiro
        decrypt_message_func = func;
1422 548 hiro
}
1423 548 hiro
1424 1896 hiro
void procmsg_set_auto_decrypt_message(gboolean enabled)
1425 1896 hiro
{
1426 1896 hiro
        auto_decrypt = enabled;
1427 1896 hiro
}
1428 1896 hiro
1429 1 hiro
FILE *procmsg_open_message_decrypted(MsgInfo *msginfo, MimeInfo **mimeinfo)
1430 1 hiro
{
1431 1 hiro
        FILE *fp;
1432 1 hiro
1433 1896 hiro
        if (decrypt_message_func && auto_decrypt)
1434 548 hiro
                return decrypt_message_func(msginfo, mimeinfo);
1435 1 hiro
1436 548 hiro
        *mimeinfo = NULL;
1437 548 hiro
        if ((fp = procmsg_open_message(msginfo)) == NULL)
1438 1 hiro
                return NULL;
1439 548 hiro
        *mimeinfo = procmime_scan_mime_header(fp);
1440 1 hiro
1441 1 hiro
        return fp;
1442 1 hiro
}
1443 1 hiro
1444 1 hiro
gboolean procmsg_msg_exist(MsgInfo *msginfo)
1445 1 hiro
{
1446 1 hiro
        gchar *path;
1447 1 hiro
        gboolean ret;
1448 1 hiro
1449 1 hiro
        if (!msginfo) return FALSE;
1450 1 hiro
1451 1 hiro
        path = folder_item_get_path(msginfo->folder);
1452 1 hiro
        change_dir(path);
1453 1 hiro
        ret = !folder_item_is_msg_changed(msginfo->folder, msginfo);
1454 1 hiro
        g_free(path);
1455 1 hiro
1456 1 hiro
        return ret;
1457 1 hiro
}
1458 1 hiro
1459 927 hiro
gboolean procmsg_trash_messages_exist(void)
1460 927 hiro
{
1461 927 hiro
        FolderItem *trash;
1462 927 hiro
        GList *cur;
1463 927 hiro
1464 927 hiro
        for (cur = folder_get_list(); cur != NULL; cur = cur->next) {
1465 927 hiro
                trash = FOLDER(cur->data)->trash;
1466 927 hiro
                if (trash && trash->total > 0)
1467 927 hiro
                        return TRUE;
1468 927 hiro
        }
1469 927 hiro
1470 927 hiro
        return FALSE;
1471 927 hiro
}
1472 927 hiro
1473 1 hiro
void procmsg_empty_trash(FolderItem *trash)
1474 1 hiro
{
1475 1106 hiro
        if (!trash)
1476 1106 hiro
                return;
1477 1106 hiro
1478 2640 hiro
        g_return_if_fail(trash->stype == F_TRASH || trash->stype == F_JUNK);
1479 1106 hiro
1480 1106 hiro
        if (trash->total > 0) {
1481 1 hiro
                debug_print("Emptying messages in %s ...\n", trash->path);
1482 1 hiro
1483 1 hiro
                folder_item_remove_all_msg(trash);
1484 423 hiro
                procmsg_clear_cache(trash);
1485 423 hiro
                procmsg_clear_mark(trash);
1486 346 hiro
                trash->cache_dirty = FALSE;
1487 346 hiro
                trash->mark_dirty = FALSE;
1488 1 hiro
        }
1489 1 hiro
}
1490 1 hiro
1491 1 hiro
void procmsg_empty_all_trash(void)
1492 1 hiro
{
1493 1 hiro
        FolderItem *trash;
1494 1 hiro
        GList *cur;
1495 1 hiro
1496 1 hiro
        for (cur = folder_get_list(); cur != NULL; cur = cur->next) {
1497 1 hiro
                trash = FOLDER(cur->data)->trash;
1498 1 hiro
                procmsg_empty_trash(trash);
1499 1 hiro
        }
1500 1 hiro
}
1501 1 hiro
1502 919 hiro
static gboolean remove_all_cached_messages_func(GNode *node, gpointer data)
1503 919 hiro
{
1504 919 hiro
        FolderItem *item;
1505 919 hiro
        gchar *dir;
1506 919 hiro
1507 919 hiro
        g_return_val_if_fail(node->data != NULL, FALSE);
1508 919 hiro
1509 919 hiro
        item = FOLDER_ITEM(node->data);
1510 920 hiro
        if (!item->path || item->stype == F_VIRTUAL)
1511 919 hiro
                return FALSE;
1512 919 hiro
1513 919 hiro
        dir = folder_item_get_path(item);
1514 919 hiro
        if (is_dir_exist(dir)) {
1515 919 hiro
                debug_print("removing all cached messages in '%s' ...\n",
1516 919 hiro
                            item->path);
1517 919 hiro
                remove_all_numbered_files(dir);
1518 919 hiro
        }
1519 919 hiro
        g_free(dir);
1520 919 hiro
1521 919 hiro
        return FALSE;
1522 919 hiro
}
1523 919 hiro
1524 919 hiro
void procmsg_remove_all_cached_messages(Folder *folder)
1525 919 hiro
{
1526 919 hiro
        g_return_if_fail(folder != NULL);
1527 919 hiro
        g_return_if_fail(FOLDER_IS_REMOTE(folder));
1528 919 hiro
1529 919 hiro
        debug_print("Removing all caches in the mailbox '%s' ...\n",
1530 919 hiro
                    folder->name);
1531 919 hiro
1532 919 hiro
        g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1533 919 hiro
                        remove_all_cached_messages_func, NULL);
1534 919 hiro
}
1535 919 hiro
1536 317 hiro
gint procmsg_save_to_outbox(FolderItem *outbox, const gchar *file)
1537 1 hiro
{
1538 1 hiro
        gint num;
1539 1 hiro
        MsgFlags flag = {0, 0};
1540 1 hiro
1541 1 hiro
        debug_print("saving sent message...\n");
1542 1 hiro
1543 1 hiro
        if (!outbox)
1544 1 hiro
                outbox = folder_get_default_outbox();
1545 1 hiro
        g_return_val_if_fail(outbox != NULL, -1);
1546 1 hiro
1547 317 hiro
        folder_item_scan(outbox);
1548 317 hiro
        if ((num = folder_item_add_msg(outbox, file, &flag, FALSE)) < 0) {
1549 317 hiro
                g_warning("can't save message\n");
1550 317 hiro
                return -1;
1551 1 hiro
        }
1552 2253 hiro
        procmsg_flush_folder(outbox);
1553 1 hiro
1554 1 hiro
        return 0;
1555 1 hiro
}
1556 1 hiro
1557 1386 hiro
static guint print_id = 0;
1558 1386 hiro
1559 1386 hiro
static gint print_command_exec(const gchar *file, const gchar *cmdline)
1560 1386 hiro
{
1561 1386 hiro
        static const gchar *def_cmd = "lpr %s";
1562 1386 hiro
        gchar buf[1024];
1563 1386 hiro
1564 1386 hiro
#ifdef G_OS_WIN32
1565 1386 hiro
        if (canonicalize_file_replace(file) < 0)
1566 1386 hiro
                return -1;
1567 1386 hiro
#endif
1568 1386 hiro
1569 1386 hiro
        if (cmdline && str_find_format_times(cmdline, 's') == 1)
1570 1386 hiro
                g_snprintf(buf, sizeof(buf) - 1, cmdline, file);
1571 1386 hiro
        else {
1572 1386 hiro
                if (cmdline) {
1573 1386 hiro
                        g_warning(_("Print command line is invalid: `%s'\n"),
1574 1386 hiro
                                  cmdline);
1575 1386 hiro
                        return -1;
1576 1386 hiro
                }
1577 1386 hiro
1578 1386 hiro
#ifdef G_OS_WIN32
1579 1386 hiro
                execute_print_file(file);
1580 1386 hiro
                return 0;
1581 1386 hiro
#else
1582 1386 hiro
                g_snprintf(buf, sizeof(buf) - 1, def_cmd, file);
1583 1386 hiro
#endif
1584 1386 hiro
        }
1585 1386 hiro
1586 1386 hiro
        g_strchomp(buf);
1587 1386 hiro
        if (buf[strlen(buf) - 1] != '&')
1588 1386 hiro
                strcat(buf, "&");
1589 1386 hiro
1590 1386 hiro
        system(buf);
1591 1386 hiro
1592 1386 hiro
        return 0;
1593 1386 hiro
}
1594 1386 hiro
1595 1038 hiro
void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline,
1596 1038 hiro
                           gboolean all_headers)
1597 1 hiro
{
1598 1 hiro
        gchar *prtmp;
1599 679 hiro
        FILE *msgfp, *tmpfp, *prfp;
1600 679 hiro
        GPtrArray *headers;
1601 679 hiro
        gint i;
1602 1386 hiro
        gchar buf[BUFFSIZE];
1603 1 hiro
1604 679 hiro
        g_return_if_fail(msginfo != NULL);
1605 1 hiro
1606 129 hiro
        if ((tmpfp = procmime_get_first_text_content
1607 129 hiro
                (msginfo, conv_get_locale_charset_str())) == NULL) {
1608 679 hiro
                g_warning("Can't get text part\n");
1609 1 hiro
                return;
1610 1 hiro
        }
1611 1 hiro
1612 680 hiro
        prtmp = g_strdup_printf("%s%cprinttmp-%08x.txt",
1613 1386 hiro
                                get_mime_tmp_dir(), G_DIR_SEPARATOR,
1614 1386 hiro
                                print_id++);
1615 1 hiro
1616 478 hiro
        if ((prfp = g_fopen(prtmp, "wb")) == NULL) {
1617 2164 hiro
                FILE_OP_ERROR(prtmp, "procmsg_print_message: fopen");
1618 1 hiro
                g_free(prtmp);
1619 1 hiro
                fclose(tmpfp);
1620 1 hiro
                return;
1621 1 hiro
        }
1622 1 hiro
1623 679 hiro
        if ((msgfp = procmsg_open_message(msginfo)) == NULL) {
1624 679 hiro
                fclose(prfp);
1625 679 hiro
                g_free(prtmp);
1626 679 hiro
                fclose(tmpfp);
1627 679 hiro
                return;
1628 129 hiro
        }
1629 129 hiro
1630 1038 hiro
        if (all_headers)
1631 1038 hiro
                headers = procheader_get_header_array_asis(msgfp, NULL);
1632 1038 hiro
        else
1633 1038 hiro
                headers = procheader_get_header_array_for_display(msgfp, NULL);
1634 1038 hiro
1635 679 hiro
        fclose(msgfp);
1636 679 hiro
1637 679 hiro
        for (i = 0; i < headers->len; i++) {
1638 679 hiro
                Header *hdr;
1639 679 hiro
                gchar *locale_str;
1640 679 hiro
                const gchar *body;
1641 679 hiro
1642 679 hiro
                hdr = g_ptr_array_index(headers, i);
1643 679 hiro
1644 679 hiro
                if (!g_ascii_strcasecmp(hdr->name, "Subject"))
1645 679 hiro
                        body = msginfo->subject;
1646 679 hiro
                else if (!g_ascii_strcasecmp(hdr->name, "From"))
1647 679 hiro
                        body = msginfo->from;
1648 679 hiro
                else if (!g_ascii_strcasecmp(hdr->name, "To"))
1649 679 hiro
                        body = msginfo->to;
1650 679 hiro
                else if (!g_ascii_strcasecmp(hdr->name, "Cc")) {
1651 679 hiro
                        unfold_line(hdr->body);
1652 679 hiro
                        body = hdr->body;
1653 679 hiro
                        while (g_ascii_isspace(*body))
1654 679 hiro
                                body++;
1655 679 hiro
                } else {
1656 679 hiro
                        body = hdr->body;
1657 679 hiro
                        while (g_ascii_isspace(*body))
1658 679 hiro
                                body++;
1659 679 hiro
                }
1660 679 hiro
1661 1266 hiro
                if (body && *body != '\0') {
1662 1266 hiro
                        locale_str = conv_codeset_strdup
1663 1266 hiro
                                (body, CS_INTERNAL,
1664 1266 hiro
                                 conv_get_locale_charset_str());
1665 1266 hiro
                        fprintf(prfp, "%s: %s\n", hdr->name,
1666 1266 hiro
                                locale_str ? locale_str : body);
1667 1266 hiro
                        g_free(locale_str);
1668 1266 hiro
                } else {
1669 1266 hiro
                        fprintf(prfp, "%s: (none)\n", hdr->name);
1670 1266 hiro
                }
1671 679 hiro
        }
1672 679 hiro
1673 679 hiro
        procheader_header_array_destroy(headers);
1674 679 hiro
1675 1 hiro
        fputc('\n', prfp);
1676 1 hiro
1677 1 hiro
        while (fgets(buf, sizeof(buf), tmpfp) != NULL)
1678 1 hiro
                fputs(buf, prfp);
1679 1 hiro
1680 1 hiro
        fclose(prfp);
1681 1 hiro
        fclose(tmpfp);
1682 1 hiro
1683 1386 hiro
        print_command_exec(prtmp, cmdline);
1684 1386 hiro
1685 1386 hiro
        g_free(prtmp);
1686 1386 hiro
}
1687 1386 hiro
1688 1386 hiro
void procmsg_print_message_part(MsgInfo *msginfo, MimeInfo *partinfo,
1689 1386 hiro
                                const gchar *cmdline, gboolean all_headers)
1690 1386 hiro
{
1691 1386 hiro
        FILE *msgfp, *tmpfp, *prfp;
1692 1386 hiro
        gchar *prtmp;
1693 1386 hiro
        gchar buf[BUFFSIZE];
1694 1386 hiro
1695 1386 hiro
        if ((msgfp = procmsg_open_message(msginfo)) == NULL) {
1696 680 hiro
                return;
1697 680 hiro
        }
1698 680 hiro
1699 1386 hiro
        if ((tmpfp = procmime_get_text_content
1700 1386 hiro
                (partinfo, msgfp, conv_get_locale_charset_str())) == NULL) {
1701 1386 hiro
                fclose(msgfp);
1702 1386 hiro
                return;
1703 1386 hiro
        }
1704 1386 hiro
        fclose(msgfp);
1705 680 hiro
1706 1386 hiro
        prtmp = g_strdup_printf("%s%cprinttmp-%08x.txt",
1707 1386 hiro
                                get_mime_tmp_dir(), G_DIR_SEPARATOR,
1708 1386 hiro
                                print_id++);
1709 1386 hiro
        if ((prfp = g_fopen(prtmp, "wb")) == NULL) {
1710 2164 hiro
                FILE_OP_ERROR(prtmp, "procmsg_print_message_part: fopen");
1711 680 hiro
                g_free(prtmp);
1712 1386 hiro
                fclose(tmpfp);
1713 680 hiro
                return;
1714 1 hiro
        }
1715 1 hiro
1716 1386 hiro
        while (fgets(buf, sizeof(buf), tmpfp) != NULL)
1717 1386 hiro
                fputs(buf, prfp);
1718 1386 hiro
1719 1386 hiro
        fclose(prfp);
1720 1386 hiro
        fclose(tmpfp);
1721 1386 hiro
1722 1386 hiro
        print_command_exec(prtmp, cmdline);
1723 1386 hiro
1724 1 hiro
        g_free(prtmp);
1725 1 hiro
}
1726 1 hiro
1727 2608 hiro
/**
1728 2608 hiro
 * procmsg_concat_partial_messages:
1729 2608 hiro
 * @mlist: list of MsgInfo* including message/partial messages.
1730 2608 hiro
 * @file: output file name of concatenated message.
1731 2608 hiro
 *
1732 2608 hiro
 * Concatenate @mlist which consists of message/partial messages and
1733 2608 hiro
 * output to @file. If @mlist has different partial id, the first one
1734 2608 hiro
 * is used.
1735 2608 hiro
 *
1736 2608 hiro
 * Return value: 0 on success, or -1 if failed.
1737 2608 hiro
 **/
1738 2608 hiro
gint procmsg_concat_partial_messages(GSList *mlist, const gchar *file)
1739 2608 hiro
{
1740 2608 hiro
        static HeaderEntry hentry[] = {{"Content-Type:", NULL, FALSE},
1741 2608 hiro
                                       {NULL, NULL, FALSE}};
1742 2608 hiro
        FILE *fp;
1743 2608 hiro
        gchar buf[BUFFSIZE];
1744 2608 hiro
        FILE *tmp_fp;
1745 2608 hiro
        gchar *part_id = NULL;
1746 2608 hiro
        gint total = 0;
1747 2608 hiro
        MsgInfo *msg_array[100] = {NULL};
1748 2608 hiro
        MsgInfo *msginfo;
1749 2608 hiro
        MimeInfo *mimeinfo;
1750 2608 hiro
        GSList *cur;
1751 2608 hiro
        gint i;
1752 2608 hiro
1753 2608 hiro
        g_return_val_if_fail(mlist != NULL, -1);
1754 2608 hiro
        g_return_val_if_fail(file != NULL, -1);
1755 2608 hiro
1756 2608 hiro
        debug_print("procmsg_concat_partial_messages\n");
1757 2608 hiro
1758 2608 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
1759 2608 hiro
                gint n = 0;
1760 2608 hiro
                gint t = 0;
1761 2608 hiro
                gchar *cur_id = NULL;
1762 2608 hiro
1763 2608 hiro
                msginfo = (MsgInfo *)cur->data;
1764 2608 hiro
1765 2608 hiro
                fp = procmsg_open_message_decrypted(msginfo, &mimeinfo);
1766 2608 hiro
                if (!fp)
1767 2608 hiro
                        continue;
1768 2608 hiro
                if (!mimeinfo->content_type ||
1769 2608 hiro
                    g_ascii_strcasecmp(mimeinfo->content_type, "message/partial") != 0)
1770 2608 hiro
                        goto skip;
1771 2608 hiro
1772 2608 hiro
                rewind(fp);
1773 2608 hiro
                if (procheader_get_one_field(buf, sizeof(buf), fp, hentry) == -1)
1774 2608 hiro
                        goto skip;
1775 2608 hiro
1776 2609 hiro
                procmime_scan_content_type_partial(buf + strlen(hentry[0].name),
1777 2609 hiro
                                                   &t, &cur_id, &n);
1778 2609 hiro
                if (n == 0 || n > 100 || t > 100 || (t > 0 && n > t)) {
1779 2609 hiro
                        debug_print("bad partial number (%d/%d), skip\n", n, t);
1780 2608 hiro
                        g_free(cur_id);
1781 2608 hiro
                        goto skip;
1782 2608 hiro
                }
1783 2608 hiro
1784 2608 hiro
                debug_print("partial: %d/%d id=%s\n", n, t, cur_id);
1785 2608 hiro
                if (!part_id)
1786 2608 hiro
                        part_id = g_strdup(cur_id);
1787 2608 hiro
                if (total == 0)
1788 2608 hiro
                        total = t;
1789 2608 hiro
1790 2609 hiro
                if ((t > 0 && total != t) || (total > 0 && n > total) ||
1791 2609 hiro
                    strcmp(part_id, cur_id) != 0) {
1792 2608 hiro
                        debug_print("skip\n");
1793 2608 hiro
                        g_free(cur_id);
1794 2608 hiro
                        goto skip;
1795 2608 hiro
                }
1796 2608 hiro
1797 2608 hiro
                msg_array[n - 1] = msginfo;
1798 2608 hiro
1799 2608 hiro
                g_free(cur_id);
1800 2608 hiro
skip:
1801 2608 hiro
                fclose(fp);
1802 2608 hiro
                procmime_mimeinfo_free_all(mimeinfo);
1803 2608 hiro
        }
1804 2608 hiro
1805 2608 hiro
        if (!part_id) {
1806 2608 hiro
                debug_print("piece not found\n");
1807 2608 hiro
                return -1;
1808 2608 hiro
        }
1809 2608 hiro
1810 2623 hiro
        debug_print("part_id = %s , total = %d\n", part_id, total);
1811 2608 hiro
        g_free(part_id);
1812 2608 hiro
1813 2609 hiro
        if (total == 0) {
1814 2609 hiro
                debug_print("total number not found\n");
1815 2609 hiro
                return -1;
1816 2609 hiro
        }
1817 2609 hiro
1818 2608 hiro
        /* check if all pieces exist */
1819 2608 hiro
        for (i = 0; i < total; i++) {
1820 2608 hiro
                if (msg_array[i] == NULL) {
1821 2608 hiro
                        debug_print("message part %d not exist\n", i + 1);
1822 2608 hiro
                        return -1;
1823 2608 hiro
                }
1824 2608 hiro
        }
1825 2608 hiro
1826 2608 hiro
        /* concatenate parts */
1827 2608 hiro
        if ((tmp_fp = g_fopen(file, "wb")) == NULL) {
1828 2608 hiro
                FILE_OP_ERROR(file, "fopen");
1829 2608 hiro
                return -1;
1830 2608 hiro
        }
1831 2608 hiro
1832 2608 hiro
        for (i = 0; i < total; i++) {
1833 2608 hiro
                msginfo = msg_array[i];
1834 2608 hiro
                off_t out_size;
1835 2608 hiro
                gint empty_line_size = 0;
1836 2608 hiro
1837 2608 hiro
                fp = procmsg_open_message_decrypted(msginfo, &mimeinfo);
1838 2608 hiro
                if (!fp) {
1839 2608 hiro
                        g_warning("cannot open message part %d\n", i + 1);
1840 2608 hiro
                        fclose(tmp_fp);
1841 2608 hiro
                        g_unlink(file);
1842 2608 hiro
                        return -1;
1843 2608 hiro
                }
1844 2608 hiro
1845 2610 hiro
                /* write out first headers */
1846 2610 hiro
                if (i == 0) {
1847 2610 hiro
                        rewind(fp);
1848 2610 hiro
                        while (procheader_get_one_field(buf, sizeof(buf), fp, NULL) != -1) {
1849 2610 hiro
                                if (!g_ascii_strncasecmp(buf, "Content-", 8) ||
1850 2610 hiro
                                    !g_ascii_strncasecmp(buf, "Subject", 7) ||
1851 2610 hiro
                                    !g_ascii_strncasecmp(buf, "Message-ID", 10) ||
1852 2610 hiro
                                    !g_ascii_strncasecmp(buf, "Encrypted", 9) ||
1853 2610 hiro
                                    !g_ascii_strncasecmp(buf, "MIME-Version", 12))
1854 2610 hiro
                                        continue;
1855 2610 hiro
                                fputs(buf, tmp_fp);
1856 2610 hiro
                                fputs("\n", tmp_fp);
1857 2610 hiro
                        }
1858 2610 hiro
1859 2610 hiro
                        while (procheader_get_one_field(buf, sizeof(buf), fp, NULL) != -1) {
1860 2610 hiro
                                if (!g_ascii_strncasecmp(buf, "Content-", 8) ||
1861 2610 hiro
                                    !g_ascii_strncasecmp(buf, "Subject", 7) ||
1862 2610 hiro
                                    !g_ascii_strncasecmp(buf, "Message-ID", 10) ||
1863 2610 hiro
                                    !g_ascii_strncasecmp(buf, "Encrypted", 9) ||
1864 2610 hiro
                                    !g_ascii_strncasecmp(buf, "MIME-Version", 12)) {
1865 2610 hiro
                                        fputs(buf, tmp_fp);
1866 2610 hiro
                                        fputs("\n", tmp_fp);
1867 2610 hiro
                                }
1868 2610 hiro
                        }
1869 2610 hiro
1870 2610 hiro
                        /* header-body separator */
1871 2610 hiro
                        fputs("\n", tmp_fp);
1872 2610 hiro
                }
1873 2610 hiro
1874 2608 hiro
                out_size = get_left_file_size(fp);
1875 2608 hiro
                if (out_size < 0) {
1876 2608 hiro
                        g_warning("cannot tell left file size of part %d\n", i + 1);
1877 2608 hiro
                        fclose(tmp_fp);
1878 2608 hiro
                        g_unlink(file);
1879 2608 hiro
                        return -1;
1880 2608 hiro
                }
1881 2608 hiro
                empty_line_size = get_last_empty_line_size(fp, out_size);
1882 2608 hiro
                if (empty_line_size < 0) {
1883 2608 hiro
                        g_warning("cannot get last empty line size of part %d\n", i + 1);
1884 2608 hiro
                        fclose(tmp_fp);
1885 2608 hiro
                        g_unlink(file);
1886 2608 hiro
                        return -1;
1887 2608 hiro
                }
1888 2608 hiro
1889 2608 hiro
                if (append_file_part(fp, ftell(fp), out_size - empty_line_size,
1890 2608 hiro
                                     tmp_fp) < 0) {
1891 2608 hiro
                        g_warning("write failed\n");
1892 2608 hiro
                        fclose(tmp_fp);
1893 2608 hiro
                        g_unlink(file);
1894 2608 hiro
                        return -1;
1895 2608 hiro
                }
1896 2608 hiro
1897 2608 hiro
                fclose(fp);
1898 2608 hiro
                procmime_mimeinfo_free_all(mimeinfo);
1899 2608 hiro
        }
1900 2608 hiro
1901 2608 hiro
        fclose(tmp_fp);
1902 2608 hiro
1903 2608 hiro
        return 0;
1904 2608 hiro
}
1905 2608 hiro
1906 1848 hiro
static gboolean procmsg_get_flags(FolderItem *item, gint num,
1907 1848 hiro
                                  MsgPermFlags *flags)
1908 1848 hiro
{
1909 1848 hiro
        FILE *fp;
1910 1848 hiro
        guint32 idata;
1911 1848 hiro
        gint read_num;
1912 1848 hiro
        MsgPermFlags perm_flags;
1913 1848 hiro
        gboolean found = FALSE;
1914 1848 hiro
        GSList *cur;
1915 1848 hiro
1916 1848 hiro
        if ((fp = procmsg_open_mark_file(item, DATA_READ)) == NULL)
1917 1848 hiro
                return FALSE;
1918 1848 hiro
1919 1848 hiro
        while (fread(&idata, sizeof(idata), 1, fp) == 1) {
1920 1848 hiro
                read_num = idata;
1921 1848 hiro
                if (fread(&idata, sizeof(idata), 1, fp) != 1)
1922 1848 hiro
                        break;
1923 1848 hiro
                perm_flags = idata;
1924 1848 hiro
                if (read_num == num) {
1925 1848 hiro
                        *flags = perm_flags;
1926 1848 hiro
                        found = TRUE;
1927 1848 hiro
                        break;
1928 1848 hiro
                }
1929 1848 hiro
        }
1930 1848 hiro
1931 1848 hiro
        fclose(fp);
1932 1848 hiro
        if (found)
1933 1848 hiro
                return TRUE;
1934 1848 hiro
1935 1848 hiro
        for (cur = item->mark_queue; cur != NULL; cur = cur->next) {
1936 2251 hiro
                MsgFlagInfo *flaginfo = (MsgFlagInfo *)cur->data;
1937 1848 hiro
1938 2251 hiro
                if (flaginfo->msgnum == num) {
1939 2251 hiro
                        *flags = flaginfo->flags.perm_flags;
1940 1848 hiro
                        found = TRUE;
1941 1848 hiro
                        break;
1942 1848 hiro
                }
1943 1848 hiro
        }
1944 1848 hiro
1945 1848 hiro
        return found;
1946 1848 hiro
}
1947 1848 hiro
1948 1848 hiro
MsgInfo *procmsg_get_msginfo(FolderItem *item, gint num)
1949 1848 hiro
{
1950 1848 hiro
        MsgInfo *msginfo;
1951 1848 hiro
        FolderType type;
1952 1848 hiro
1953 1910 hiro
        g_return_val_if_fail(item->folder != NULL, NULL);
1954 1848 hiro
1955 1848 hiro
        msginfo = folder_item_get_msginfo(item, num);
1956 1848 hiro
        if (!msginfo)
1957 1848 hiro
                return NULL;
1958 1848 hiro
1959 1848 hiro
        type = FOLDER_TYPE(item->folder);
1960 1848 hiro
        if (type == F_MH || type == F_IMAP) {
1961 1848 hiro
                if (item->stype == F_QUEUE) {
1962 1848 hiro
                        MSG_SET_TMP_FLAGS(msginfo->flags, MSG_QUEUED);
1963 1848 hiro
                } else if (item->stype == F_DRAFT) {
1964 1848 hiro
                        MSG_SET_TMP_FLAGS(msginfo->flags, MSG_DRAFT);
1965 1848 hiro
                }
1966 1848 hiro
        }
1967 1848 hiro
        if (type == F_IMAP) {
1968 1848 hiro
                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_IMAP);
1969 1848 hiro
        } else if (type == F_NEWS) {
1970 1848 hiro
                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_NEWS);
1971 1848 hiro
        }
1972 1848 hiro
1973 1848 hiro
        if (type == F_MH || type == F_NEWS) {
1974 1848 hiro
                MsgPermFlags flags = 0;
1975 1857 hiro
                if (procmsg_get_flags(item, num, &flags))
1976 1848 hiro
                        msginfo->flags.perm_flags = flags;
1977 1848 hiro
        }
1978 1848 hiro
1979 1848 hiro
        return msginfo;
1980 1848 hiro
}
1981 1848 hiro
1982 1 hiro
MsgInfo *procmsg_msginfo_copy(MsgInfo *msginfo)
1983 1 hiro
{
1984 1 hiro
        MsgInfo *newmsginfo;
1985 1 hiro
1986 1 hiro
        if (msginfo == NULL) return NULL;
1987 1 hiro
1988 1 hiro
        newmsginfo = g_new0(MsgInfo, 1);
1989 1 hiro
1990 1 hiro
#define MEMBCOPY(mmb)        newmsginfo->mmb = msginfo->mmb
1991 1 hiro
#define MEMBDUP(mmb)        newmsginfo->mmb = msginfo->mmb ? \
1992 1 hiro
                        g_strdup(msginfo->mmb) : NULL
1993 1 hiro
1994 1 hiro
        MEMBCOPY(msgnum);
1995 1 hiro
        MEMBCOPY(size);
1996 1 hiro
        MEMBCOPY(mtime);
1997 1 hiro
        MEMBCOPY(date_t);
1998 1 hiro
1999 1 hiro
        MEMBCOPY(flags);
2000 1 hiro
2001 1 hiro
        MEMBDUP(fromname);
2002 1 hiro
2003 1 hiro
        MEMBDUP(date);
2004 1 hiro
        MEMBDUP(from);
2005 1 hiro
        MEMBDUP(to);
2006 1 hiro
        MEMBDUP(cc);
2007 1 hiro
        MEMBDUP(newsgroups);
2008 1 hiro
        MEMBDUP(subject);
2009 1 hiro
        MEMBDUP(msgid);
2010 1 hiro
        MEMBDUP(inreplyto);
2011 1 hiro
2012 1 hiro
        MEMBCOPY(folder);
2013 1 hiro
        MEMBCOPY(to_folder);
2014 1 hiro
2015 1 hiro
        MEMBDUP(xface);
2016 1 hiro
2017 1 hiro
        MEMBDUP(file_path);
2018 1 hiro
2019 1128 hiro
        if (msginfo->encinfo) {
2020 1128 hiro
                newmsginfo->encinfo = g_new0(MsgEncryptInfo, 1);
2021 1128 hiro
                MEMBDUP(encinfo->plaintext_file);
2022 1128 hiro
                MEMBDUP(encinfo->sigstatus);
2023 1128 hiro
                MEMBDUP(encinfo->sigstatus_full);
2024 1128 hiro
                MEMBCOPY(encinfo->decryption_failed);
2025 1128 hiro
        }
2026 1 hiro
2027 1 hiro
        return newmsginfo;
2028 1 hiro
}
2029 1 hiro
2030 1 hiro
MsgInfo *procmsg_msginfo_get_full_info(MsgInfo *msginfo)
2031 1 hiro
{
2032 1 hiro
        MsgInfo *full_msginfo;
2033 1 hiro
        gchar *file;
2034 1 hiro
2035 1 hiro
        if (msginfo == NULL) return NULL;
2036 1 hiro
2037 1 hiro
        file = procmsg_get_message_file(msginfo);
2038 1 hiro
        if (!file) {
2039 1 hiro
                g_warning("procmsg_msginfo_get_full_info(): can't get message file.\n");
2040 1 hiro
                return NULL;
2041 1 hiro
        }
2042 1 hiro
2043 1 hiro
        full_msginfo = procheader_parse_file(file, msginfo->flags, TRUE);
2044 1 hiro
        g_free(file);
2045 1 hiro
        if (!full_msginfo) return NULL;
2046 1 hiro
2047 1 hiro
        full_msginfo->msgnum = msginfo->msgnum;
2048 1 hiro
        full_msginfo->size = msginfo->size;
2049 1 hiro
        full_msginfo->mtime = msginfo->mtime;
2050 1 hiro
        full_msginfo->folder = msginfo->folder;
2051 1 hiro
        full_msginfo->to_folder = msginfo->to_folder;
2052 1 hiro
2053 1 hiro
        full_msginfo->file_path = g_strdup(msginfo->file_path);
2054 1 hiro
2055 1128 hiro
        if (msginfo->encinfo) {
2056 1128 hiro
                full_msginfo->encinfo = g_new0(MsgEncryptInfo, 1);
2057 1128 hiro
                full_msginfo->encinfo->plaintext_file =
2058 1128 hiro
                        g_strdup(msginfo->encinfo->plaintext_file);
2059 1128 hiro
                full_msginfo->encinfo->sigstatus =
2060 1128 hiro
                        g_strdup(msginfo->encinfo->sigstatus);
2061 1128 hiro
                full_msginfo->encinfo->sigstatus_full =
2062 1128 hiro
                        g_strdup(msginfo->encinfo->sigstatus_full);
2063 1128 hiro
                full_msginfo->encinfo->decryption_failed =
2064 1128 hiro
                        msginfo->encinfo->decryption_failed;
2065 1128 hiro
        }
2066 1 hiro
2067 1 hiro
        return full_msginfo;
2068 1 hiro
}
2069 1 hiro
2070 409 hiro
gboolean procmsg_msginfo_equal(MsgInfo *msginfo_a, MsgInfo *msginfo_b)
2071 409 hiro
{
2072 409 hiro
        if (!msginfo_a || !msginfo_b)
2073 409 hiro
                return FALSE;
2074 409 hiro
2075 409 hiro
        if (msginfo_a == msginfo_b)
2076 409 hiro
                return TRUE;
2077 409 hiro
2078 409 hiro
        if (msginfo_a->folder == msginfo_b->folder &&
2079 409 hiro
            msginfo_a->msgnum == msginfo_b->msgnum &&
2080 409 hiro
            msginfo_a->size   == msginfo_b->size   &&
2081 409 hiro
            msginfo_a->mtime  == msginfo_b->mtime)
2082 409 hiro
                return TRUE;
2083 409 hiro
2084 409 hiro
        return FALSE;
2085 409 hiro
}
2086 409 hiro
2087 1 hiro
void procmsg_msginfo_free(MsgInfo *msginfo)
2088 1 hiro
{
2089 1 hiro
        if (msginfo == NULL) return;
2090 1 hiro
2091 1 hiro
        g_free(msginfo->xface);
2092 1 hiro
2093 1 hiro
        g_free(msginfo->fromname);
2094 1 hiro
2095 1 hiro
        g_free(msginfo->date);
2096 1 hiro
        g_free(msginfo->from);
2097 1 hiro
        g_free(msginfo->to);
2098 1 hiro
        g_free(msginfo->cc);
2099 1 hiro
        g_free(msginfo->newsgroups);
2100 1 hiro
        g_free(msginfo->subject);
2101 1 hiro
        g_free(msginfo->msgid);
2102 1 hiro
        g_free(msginfo->inreplyto);
2103 1 hiro
2104 190 hiro
        slist_free_strings(msginfo->references);
2105 190 hiro
        g_slist_free(msginfo->references);
2106 190 hiro
2107 1 hiro
        g_free(msginfo->file_path);
2108 1 hiro
2109 1128 hiro
        if (msginfo->encinfo) {
2110 1128 hiro
                g_free(msginfo->encinfo->plaintext_file);
2111 1128 hiro
                g_free(msginfo->encinfo->sigstatus);
2112 1128 hiro
                g_free(msginfo->encinfo->sigstatus_full);
2113 1128 hiro
                g_free(msginfo->encinfo);
2114 1128 hiro
        }
2115 1 hiro
2116 1 hiro
        g_free(msginfo);
2117 1 hiro
}
2118 1 hiro
2119 1 hiro
gint procmsg_cmp_msgnum_for_sort(gconstpointer a, gconstpointer b)
2120 1 hiro
{
2121 1 hiro
        const MsgInfo *msginfo1 = a;
2122 1 hiro
        const MsgInfo *msginfo2 = b;
2123 1 hiro
2124 496 hiro
        if (!msginfo1 || !msginfo2)
2125 496 hiro
                return 0;
2126 1 hiro
2127 1 hiro
        return msginfo1->msgnum - msginfo2->msgnum;
2128 1 hiro
}
2129 1 hiro
2130 1 hiro
#define CMP_FUNC_DEF(func_name, val)                                        \
2131 1 hiro
static gint func_name(gconstpointer a, gconstpointer b)                        \
2132 1 hiro
{                                                                        \
2133 1 hiro
        const MsgInfo *msginfo1 = a;                                        \
2134 1 hiro
        const MsgInfo *msginfo2 = b;                                        \
2135 496 hiro
        gint ret;                                                        \
2136 1 hiro
                                                                        \
2137 1 hiro
        if (!msginfo1 || !msginfo2)                                        \
2138 496 hiro
                return 0;                                                \
2139 1 hiro
                                                                        \
2140 496 hiro
        ret = (val);                                                        \
2141 496 hiro
        if (ret == 0)                                                        \
2142 496 hiro
                ret = msginfo1->date_t - msginfo2->date_t;                \
2143 496 hiro
                                                                        \
2144 496 hiro
        return ret * (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1);        \
2145 1 hiro
}
2146 1 hiro
2147 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_mark,
2148 1 hiro
             MSG_IS_MARKED(msginfo1->flags) - MSG_IS_MARKED(msginfo2->flags))
2149 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_unread,
2150 1 hiro
             MSG_IS_UNREAD(msginfo1->flags) - MSG_IS_UNREAD(msginfo2->flags))
2151 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_mime,
2152 1 hiro
             MSG_IS_MIME(msginfo1->flags) - MSG_IS_MIME(msginfo2->flags))
2153 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_label,
2154 1 hiro
             MSG_GET_COLORLABEL(msginfo1->flags) -
2155 1 hiro
             MSG_GET_COLORLABEL(msginfo2->flags))
2156 496 hiro
CMP_FUNC_DEF(procmsg_cmp_by_size, msginfo1->size - msginfo2->size)
2157 1 hiro
2158 496 hiro
#undef CMP_FUNC_DEF
2159 496 hiro
#define CMP_FUNC_DEF(func_name, val)                                        \
2160 496 hiro
static gint func_name(gconstpointer a, gconstpointer b)                        \
2161 496 hiro
{                                                                        \
2162 496 hiro
        const MsgInfo *msginfo1 = a;                                        \
2163 496 hiro
        const MsgInfo *msginfo2 = b;                                        \
2164 496 hiro
                                                                        \
2165 496 hiro
        if (!msginfo1 || !msginfo2)                                        \
2166 496 hiro
                return 0;                                                \
2167 496 hiro
                                                                        \
2168 496 hiro
        return (val) * (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1);        \
2169 496 hiro
}
2170 496 hiro
2171 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_number, msginfo1->msgnum - msginfo2->msgnum)
2172 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_date, msginfo1->date_t - msginfo2->date_t)
2173 1 hiro
2174 1 hiro
#undef CMP_FUNC_DEF
2175 1 hiro
#define CMP_FUNC_DEF(func_name, var_name)                                \
2176 1 hiro
static gint func_name(gconstpointer a, gconstpointer b)                        \
2177 1 hiro
{                                                                        \
2178 1 hiro
        const MsgInfo *msginfo1 = a;                                        \
2179 1 hiro
        const MsgInfo *msginfo2 = b;                                        \
2180 496 hiro
        gint ret;                                                        \
2181 1 hiro
                                                                        \
2182 1 hiro
        if (!msginfo1->var_name)                                        \
2183 496 hiro
                return (msginfo2->var_name != NULL) *                        \
2184 496 hiro
                        (cmp_func_sort_type == SORT_ASCENDING ? -1 : 1);\
2185 1 hiro
        if (!msginfo2->var_name)                                        \
2186 496 hiro
                return (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1);        \
2187 1 hiro
                                                                        \
2188 496 hiro
        ret = g_ascii_strcasecmp                                        \
2189 496 hiro
                (msginfo1->var_name, msginfo2->var_name);                \
2190 496 hiro
        if (ret == 0)                                                        \
2191 496 hiro
                ret = msginfo1->date_t - msginfo2->date_t;                \
2192 496 hiro
                                                                        \
2193 496 hiro
        return ret * (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1);        \
2194 1 hiro
}
2195 1 hiro
2196 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_from, fromname)
2197 1 hiro
CMP_FUNC_DEF(procmsg_cmp_by_to, to)
2198 1 hiro
2199 1 hiro
#undef CMP_FUNC_DEF
2200 1 hiro
2201 496 hiro
static gint procmsg_cmp_by_subject(gconstpointer a, gconstpointer b)
2202 496 hiro
{
2203 496 hiro
        const MsgInfo *msginfo1 = a;
2204 496 hiro
        const MsgInfo *msginfo2 = b;
2205 496 hiro
        gint ret;
2206 496 hiro
2207 496 hiro
        if (!msginfo1->subject)
2208 496 hiro
                return (msginfo2->subject != NULL) *
2209 496 hiro
                        (cmp_func_sort_type == SORT_ASCENDING ? -1 : 1);
2210 496 hiro
        if (!msginfo2->subject)
2211 496 hiro
                return (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1);
2212 496 hiro
2213 496 hiro
        ret = subject_compare_for_sort(msginfo1->subject, msginfo2->subject);
2214 496 hiro
        if (ret == 0)
2215 496 hiro
                ret = msginfo1->date_t - msginfo2->date_t;
2216 496 hiro
2217 496 hiro
        return ret * (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1);
2218 1 hiro
}