2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2002 Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #include "procheader.h"
33 #include "statusbar.h"
35 #include "prefs_common.h"
40 #include "alertpanel.h"
45 typedef struct _FlagInfo FlagInfo
;
53 static GHashTable
*procmsg_read_mark_file (const gchar
*folder
);
54 void procmsg_msginfo_write_flags (MsgInfo
*msginfo
);
55 static void procmsg_update_unread_children (MsgInfo
*info
, gboolean newly_marked
);
57 GHashTable
*procmsg_msg_hash_table_create(GSList
*mlist
)
59 GHashTable
*msg_table
;
61 if (mlist
== NULL
) return NULL
;
63 msg_table
= g_hash_table_new(NULL
, g_direct_equal
);
64 procmsg_msg_hash_table_append(msg_table
, mlist
);
69 void procmsg_msg_hash_table_append(GHashTable
*msg_table
, GSList
*mlist
)
74 if (msg_table
== NULL
|| mlist
== NULL
) return;
76 for (cur
= mlist
; cur
!= NULL
; cur
= cur
->next
) {
77 msginfo
= (MsgInfo
*)cur
->data
;
79 g_hash_table_insert(msg_table
,
80 GUINT_TO_POINTER(msginfo
->msgnum
),
85 GHashTable
*procmsg_to_folder_hash_table_create(GSList
*mlist
)
87 GHashTable
*msg_table
;
91 if (mlist
== NULL
) return NULL
;
93 msg_table
= g_hash_table_new(NULL
, g_direct_equal
);
95 for (cur
= mlist
; cur
!= NULL
; cur
= cur
->next
) {
96 msginfo
= (MsgInfo
*)cur
->data
;
97 g_hash_table_insert(msg_table
, msginfo
->to_folder
, msginfo
);
103 static gint
procmsg_read_cache_data_str(FILE *fp
, gchar
**str
)
109 if (fread(&len
, sizeof(len
), 1, fp
) == 1) {
116 size_t size
= MIN(len
, BUFFSIZE
- 1);
118 if (fread(buf
, size
, 1, fp
) != 1) {
120 if (tmp
) g_free(tmp
);
127 *str
= g_strconcat(tmp
, buf
, NULL
);
131 tmp
= *str
= g_strdup(buf
);
140 g_warning("Cache data is corrupted\n");
145 #define READ_CACHE_DATA(data, fp) \
147 if (procmsg_read_cache_data_str(fp, &data) < 0) { \
148 procmsg_msginfo_free(msginfo); \
153 #define READ_CACHE_DATA_INT(n, fp) \
155 if (fread(&n, sizeof(n), 1, fp) != 1) { \
156 g_warning("Cache data is corrupted\n"); \
157 procmsg_msginfo_free(msginfo); \
162 GSList
*procmsg_read_cache(FolderItem
*item
, gboolean scan_file
)
164 GSList
*mlist
= NULL
;
169 MsgFlags default_flags
;
170 gchar file_buf
[BUFFSIZE
];
175 g_return_val_if_fail(item
!= NULL
, NULL
);
176 g_return_val_if_fail(item
->folder
!= NULL
, NULL
);
177 type
= item
->folder
->type
;
179 default_flags
.perm_flags
= MSG_NEW
|MSG_UNREAD
;
180 default_flags
.tmp_flags
= MSG_CACHED
;
181 if (type
== F_MH
|| type
== F_IMAP
) {
182 if (item
->stype
== F_QUEUE
) {
183 MSG_SET_TMP_FLAGS(default_flags
, MSG_QUEUED
);
184 } else if (item
->stype
== F_DRAFT
) {
185 MSG_SET_TMP_FLAGS(default_flags
, MSG_DRAFT
);
188 if (type
== F_IMAP
) {
189 MSG_SET_TMP_FLAGS(default_flags
, MSG_IMAP
);
190 } else if (type
== F_NEWS
) {
191 MSG_SET_TMP_FLAGS(default_flags
, MSG_NEWS
);
197 path
= folder_item_get_path(item
);
198 if (change_dir(path
) < 0) {
204 cache_file
= folder_item_get_cache_file(item
);
205 if ((fp
= fopen(cache_file
, "rb")) == NULL
) {
206 debug_print("\tNo cache file\n");
210 setvbuf(fp
, file_buf
, _IOFBF
, sizeof(file_buf
));
213 debug_print("\tReading summary cache...\n");
215 /* compare cache version */
216 if (fread(&ver
, sizeof(ver
), 1, fp
) != 1 ||
217 CACHE_VERSION
!= ver
) {
218 debug_print("Cache version is different. Discarding it.\n");
223 while (fread(&num
, sizeof(num
), 1, fp
) == 1) {
224 msginfo
= procmsg_msginfo_new();
225 msginfo
->msgnum
= num
;
226 READ_CACHE_DATA_INT(msginfo
->size
, fp
);
227 READ_CACHE_DATA_INT(msginfo
->mtime
, fp
);
228 READ_CACHE_DATA_INT(msginfo
->date_t
, fp
);
229 READ_CACHE_DATA_INT(msginfo
->flags
.tmp_flags
, fp
);
231 READ_CACHE_DATA(msginfo
->fromname
, fp
);
233 READ_CACHE_DATA(msginfo
->date
, fp
);
234 READ_CACHE_DATA(msginfo
->from
, fp
);
235 READ_CACHE_DATA(msginfo
->to
, fp
);
236 READ_CACHE_DATA(msginfo
->cc
, fp
);
237 READ_CACHE_DATA(msginfo
->newsgroups
, fp
);
238 READ_CACHE_DATA(msginfo
->subject
, fp
);
239 READ_CACHE_DATA(msginfo
->msgid
, fp
);
240 READ_CACHE_DATA(msginfo
->inreplyto
, fp
);
241 READ_CACHE_DATA(msginfo
->references
, fp
);
242 READ_CACHE_DATA(msginfo
->xref
, fp
);
245 MSG_SET_PERM_FLAGS(msginfo
->flags
, default_flags
.perm_flags
);
246 MSG_SET_TMP_FLAGS(msginfo
->flags
, default_flags
.tmp_flags
);
248 /* if the message file doesn't exist or is changed,
249 don't add the data */
250 if (type
== F_MH
&& scan_file
&&
251 folder_item_is_msg_changed(item
, msginfo
))
252 procmsg_msginfo_free(msginfo
);
254 msginfo
->folder
= item
;
257 last
= mlist
= g_slist_append(NULL
, msginfo
);
259 last
= g_slist_append(last
, msginfo
);
266 debug_print("done.\n");
271 #undef READ_CACHE_DATA
272 #undef READ_CACHE_DATA_INT
274 void procmsg_set_flags(GSList
*mlist
, FolderItem
*item
)
281 GHashTable
*mark_table
;
285 g_return_if_fail(item
!= NULL
);
286 g_return_if_fail(item
->folder
!= NULL
);
288 debug_print("\tMarking the messages...\n");
290 markdir
= folder_item_get_path(item
);
291 if (!is_dir_exist(markdir
))
292 make_dir_hier(markdir
);
294 mark_table
= procmsg_read_mark_file(markdir
);
297 if (!mark_table
) return;
299 for (cur
= mlist
; cur
!= NULL
; cur
= cur
->next
) {
300 msginfo
= (MsgInfo
*)cur
->data
;
302 if (lastnum
< msginfo
->msgnum
)
303 lastnum
= msginfo
->msgnum
;
305 flags
= g_hash_table_lookup
306 (mark_table
, GUINT_TO_POINTER(msginfo
->msgnum
));
309 /* add the permanent flags only */
310 msginfo
->flags
.perm_flags
= flags
->perm_flags
;
311 if (item
->folder
->type
== F_IMAP
) {
312 MSG_SET_TMP_FLAGS(msginfo
->flags
, MSG_IMAP
);
313 } else if (item
->folder
->type
== F_NEWS
) {
314 MSG_SET_TMP_FLAGS(msginfo
->flags
, MSG_NEWS
);
317 /* not found (new message) */
319 for (tmp
= mlist
; tmp
!= cur
; tmp
= tmp
->next
)
321 (((MsgInfo
*)tmp
->data
)->flags
,
328 item
->last_num
= lastnum
;
330 debug_print("done.\n");
332 debug_print("\t%d new message(s)\n", newmsg
);
334 hash_free_value_mem(mark_table
);
335 g_hash_table_destroy(mark_table
);
338 gint
procmsg_get_last_num_in_msg_list(GSList
*mlist
)
344 for (cur
= mlist
; cur
!= NULL
; cur
= cur
->next
) {
345 msginfo
= (MsgInfo
*)cur
->data
;
346 if (msginfo
&& msginfo
->msgnum
> last
)
347 last
= msginfo
->msgnum
;
353 void procmsg_msg_list_free(GSList
*mlist
)
358 for (cur
= mlist
; cur
!= NULL
; cur
= cur
->next
) {
359 msginfo
= (MsgInfo
*)cur
->data
;
360 procmsg_msginfo_free(msginfo
);
365 void procmsg_write_cache(MsgInfo
*msginfo
, FILE *fp
)
367 MsgTmpFlags flags
= msginfo
->flags
.tmp_flags
& MSG_CACHED_FLAG_MASK
;
369 WRITE_CACHE_DATA_INT(msginfo
->msgnum
, fp
);
370 WRITE_CACHE_DATA_INT(msginfo
->size
, fp
);
371 WRITE_CACHE_DATA_INT(msginfo
->mtime
, fp
);
372 WRITE_CACHE_DATA_INT(msginfo
->date_t
, fp
);
373 WRITE_CACHE_DATA_INT(flags
, fp
);
375 WRITE_CACHE_DATA(msginfo
->fromname
, fp
);
377 WRITE_CACHE_DATA(msginfo
->date
, fp
);
378 WRITE_CACHE_DATA(msginfo
->from
, fp
);
379 WRITE_CACHE_DATA(msginfo
->to
, fp
);
380 WRITE_CACHE_DATA(msginfo
->cc
, fp
);
381 WRITE_CACHE_DATA(msginfo
->newsgroups
, fp
);
382 WRITE_CACHE_DATA(msginfo
->subject
, fp
);
383 WRITE_CACHE_DATA(msginfo
->msgid
, fp
);
384 WRITE_CACHE_DATA(msginfo
->inreplyto
, fp
);
385 WRITE_CACHE_DATA(msginfo
->references
, fp
);
386 WRITE_CACHE_DATA(msginfo
->xref
, fp
);
390 void procmsg_write_flags(MsgInfo
*msginfo
, FILE *fp
)
392 MsgPermFlags flags
= msginfo
->flags
.perm_flags
;
394 WRITE_CACHE_DATA_INT(msginfo
->msgnum
, fp
);
395 WRITE_CACHE_DATA_INT(flags
, fp
);
398 void procmsg_flush_mark_queue(FolderItem
*item
, FILE *fp
)
402 g_return_if_fail(item
!= NULL
);
403 g_return_if_fail(fp
!= NULL
);
405 while (item
->mark_queue
!= NULL
) {
406 flaginfo
= (MsgInfo
*)item
->mark_queue
->data
;
407 procmsg_write_flags(flaginfo
, fp
);
408 procmsg_msginfo_free(flaginfo
);
409 item
->mark_queue
= g_slist_remove(item
->mark_queue
, flaginfo
);
413 void procmsg_add_flags(FolderItem
*item
, gint num
, MsgFlags flags
)
419 g_return_if_fail(item
!= NULL
);
422 MsgInfo
*queue_msginfo
;
424 queue_msginfo
= g_new0(MsgInfo
, 1);
425 queue_msginfo
->msgnum
= num
;
426 queue_msginfo
->flags
= flags
;
427 item
->mark_queue
= g_slist_append
428 (item
->mark_queue
, queue_msginfo
);
432 path
= folder_item_get_path(item
);
433 g_return_if_fail(path
!= NULL
);
435 if ((fp
= procmsg_open_mark_file(path
, TRUE
)) == NULL
) {
436 g_warning("can't open mark file\n");
442 msginfo
.msgnum
= num
;
443 msginfo
.flags
= flags
;
445 procmsg_write_flags(&msginfo
, fp
);
458 static GHashTable
*procmsg_read_mark_file(const gchar
*folder
)
461 GHashTable
*mark_table
= NULL
;
464 MsgPermFlags perm_flags
;
466 if ((fp
= procmsg_open_mark_file(folder
, FALSE
)) == NULL
)
469 mark_table
= g_hash_table_new(NULL
, g_direct_equal
);
471 while (fread(&num
, sizeof(num
), 1, fp
) == 1) {
472 if (fread(&perm_flags
, sizeof(perm_flags
), 1, fp
) != 1) break;
474 flags
= g_hash_table_lookup(mark_table
, GUINT_TO_POINTER(num
));
478 flags
= g_new0(MsgFlags
, 1);
479 flags
->perm_flags
= perm_flags
;
481 if (!MSG_IS_REALLY_DELETED(*flags
)) {
482 g_hash_table_insert(mark_table
, GUINT_TO_POINTER(num
), flags
);
484 g_hash_table_remove(mark_table
, GUINT_TO_POINTER(num
));
492 FILE *procmsg_open_mark_file(const gchar
*folder
, gboolean append
)
498 markfile
= g_strconcat(folder
, G_DIR_SEPARATOR_S
, MARK_FILE
, NULL
);
500 if ((fp
= fopen(markfile
, "rb")) == NULL
)
501 debug_print("Mark file not found.\n");
502 else if (fread(&ver
, sizeof(ver
), 1, fp
) != 1 || MARK_VERSION
!= ver
) {
503 debug_print("Mark version is different (%d != %d). "
504 "Discarding it.\n", ver
, MARK_VERSION
);
510 if (append
== FALSE
) {
516 /* reopen with append mode */
518 if ((fp
= fopen(markfile
, "ab")) == NULL
)
519 g_warning("Can't open mark file with append mode.\n");
521 /* open with overwrite mode if mark file doesn't exist or
522 version is different */
523 if ((fp
= fopen(markfile
, "wb")) == NULL
)
524 g_warning("Can't open mark file with write mode.\n");
527 WRITE_CACHE_DATA_INT(ver
, fp
);
535 static gboolean
procmsg_ignore_node(GNode
*node
, gpointer data
)
537 MsgInfo
*msginfo
= (MsgInfo
*)node
->data
;
539 procmsg_msginfo_set_flags(msginfo
, MSG_IGNORE_THREAD
, 0);
544 /* return the reversed thread tree */
545 GNode
*procmsg_get_thread_tree(GSList
*mlist
)
547 GNode
*root
, *parent
, *node
, *next
;
548 GHashTable
*msgid_table
;
549 GHashTable
*subject_table
;
552 const gchar
*subject
;
553 GNode
*found_subject
;
555 root
= g_node_new(NULL
);
556 msgid_table
= g_hash_table_new(g_str_hash
, g_str_equal
);
557 subject_table
= g_hash_table_new(g_str_hash
, g_str_equal
);
559 for (; mlist
!= NULL
; mlist
= mlist
->next
) {
560 msginfo
= (MsgInfo
*)mlist
->data
;
563 if (msginfo
->inreplyto
) {
564 parent
= g_hash_table_lookup(msgid_table
, msginfo
->inreplyto
);
565 if (parent
== NULL
) {
568 if (MSG_IS_IGNORE_THREAD(((MsgInfo
*)parent
->data
)->flags
) && !MSG_IS_IGNORE_THREAD(msginfo
->flags
)) {
569 procmsg_msginfo_set_flags(msginfo
, MSG_IGNORE_THREAD
, 0);
573 node
= g_node_insert_data_before
574 (parent
, parent
== root
? parent
->children
: NULL
,
576 if ((msgid
= msginfo
->msgid
) &&
577 g_hash_table_lookup(msgid_table
, msgid
) == NULL
)
578 g_hash_table_insert(msgid_table
, (gchar
*)msgid
, node
);
580 subject
= msginfo
->subject
;
581 found_subject
= subject_table_lookup(subject_table
,
583 if (found_subject
== NULL
)
584 subject_table_insert(subject_table
, (gchar
*) subject
,
587 /* replace if msg in table is older than current one
588 * can add here more stuff. */
589 if ( ((MsgInfo
*)(found_subject
->data
))->date_t
>
590 ((MsgInfo
*)(node
->data
))->date_t
) {
591 subject_table_remove(subject_table
, (gchar
*) subject
);
592 subject_table_insert(subject_table
, (gchar
*) subject
, node
);
597 /* complete the unfinished threads */
598 for (node
= root
->children
; node
!= NULL
; ) {
600 msginfo
= (MsgInfo
*)node
->data
;
602 if (msginfo
->inreplyto
)
603 parent
= g_hash_table_lookup(msgid_table
, msginfo
->inreplyto
);
604 if (parent
&& parent
!= node
) {
607 (parent
, parent
->children
, node
);
608 /* CLAWS: ignore thread */
609 if (MSG_IS_IGNORE_THREAD(((MsgInfo
*)parent
->data
)->flags
) && !MSG_IS_IGNORE_THREAD(msginfo
->flags
)) {
610 g_node_traverse(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, procmsg_ignore_node
, NULL
);
616 /* CLAWS: now see if the first level (below root) still has some nodes that can be
617 * threaded by subject line. we need to handle this in a special way to prevent
618 * circular reference from a node that has already been threaded by IN-REPLY-TO
619 * but is also in the subject line hash table */
620 for (node
= root
->children
; node
!= NULL
; ) {
622 msginfo
= (MsgInfo
*) node
->data
;
624 if (subject_is_reply(msginfo
->subject
)) {
625 parent
= subject_table_lookup(subject_table
,
627 /* the node may already be threaded by IN-REPLY-TO,
628 so go up in the tree to find the parent node */
629 if (parent
!= NULL
) {
630 if (g_node_is_ancestor(node
, parent
))
638 g_node_append(parent
, node
);
639 /* CLAWS: ignore thread */
640 if (MSG_IS_IGNORE_THREAD(((MsgInfo
*)parent
->data
)->flags
) && !MSG_IS_IGNORE_THREAD(msginfo
->flags
)) {
641 g_node_traverse(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, -1, procmsg_ignore_node
, NULL
);
648 g_hash_table_destroy(subject_table
);
649 g_hash_table_destroy(msgid_table
);
654 void procmsg_move_messages(GSList
*mlist
)
656 GSList
*cur
, *movelist
= NULL
;
658 FolderItem
*dest
= NULL
;
662 for (cur
= mlist
; cur
!= NULL
; cur
= cur
->next
) {
663 msginfo
= (MsgInfo
*)cur
->data
;
665 dest
= msginfo
->to_folder
;
666 movelist
= g_slist_append(movelist
, msginfo
);
667 } else if (dest
== msginfo
->to_folder
) {
668 movelist
= g_slist_append(movelist
, msginfo
);
670 folder_item_move_msgs_with_dest(dest
, movelist
);
671 g_slist_free(movelist
);
673 dest
= msginfo
->to_folder
;
674 movelist
= g_slist_append(movelist
, msginfo
);
679 folder_item_move_msgs_with_dest(dest
, movelist
);
680 g_slist_free(movelist
);
684 void procmsg_copy_messages(GSList
*mlist
)
686 GSList
*cur
, *copylist
= NULL
;
688 FolderItem
*dest
= NULL
;
694 Horrible: Scanning 2 times for every copy!
696 hash = procmsg_to_folder_hash_table_create(mlist);
697 folder_item_scan_foreach(hash);
698 g_hash_table_destroy(hash);
701 for (cur
= mlist
; cur
!= NULL
; cur
= cur
->next
) {
702 msginfo
= (MsgInfo
*)cur
->data
;
704 dest
= msginfo
->to_folder
;
705 copylist
= g_slist_append(copylist
, msginfo
);
706 } else if (dest
== msginfo
->to_folder
) {
707 copylist
= g_slist_append(copylist
, msginfo
);
709 folder_item_copy_msgs_with_dest(dest
, copylist
);
710 g_slist_free(copylist
);
712 dest
= msginfo
->to_folder
;
713 copylist
= g_slist_append(copylist
, msginfo
);
718 folder_item_copy_msgs_with_dest(dest
, copylist
);
719 g_slist_free(copylist
);
723 gchar
*procmsg_get_message_file_path(MsgInfo
*msginfo
)
727 g_return_val_if_fail(msginfo
!= NULL
, NULL
);
729 if (msginfo
->plaintext_file
)
730 file
= g_strdup(msginfo
->plaintext_file
);
732 path
= folder_item_get_path(msginfo
->folder
);
733 file
= g_strconcat(path
, G_DIR_SEPARATOR_S
,
734 itos(msginfo
->msgnum
), NULL
);
741 gchar
*procmsg_get_message_file(MsgInfo
*msginfo
)
743 gchar
*filename
= NULL
;
745 g_return_val_if_fail(msginfo
!= NULL
, NULL
);
747 filename
= folder_item_fetch_msg(msginfo
->folder
, msginfo
->msgnum
);
749 g_warning("can't fetch message %d\n", msginfo
->msgnum
);
754 FILE *procmsg_open_message(MsgInfo
*msginfo
)
759 g_return_val_if_fail(msginfo
!= NULL
, NULL
);
761 file
= procmsg_get_message_file_path(msginfo
);
762 g_return_val_if_fail(file
!= NULL
, NULL
);
764 if (!is_file_exist(file
)) {
766 file
= procmsg_get_message_file(msginfo
);
767 g_return_val_if_fail(file
!= NULL
, NULL
);
770 if ((fp
= fopen(file
, "rb")) == NULL
) {
771 FILE_OP_ERROR(file
, "fopen");
778 if (MSG_IS_QUEUED(msginfo
->flags
) || MSG_IS_DRAFT(msginfo
->flags
)) {
781 while (fgets(buf
, sizeof(buf
), fp
) != NULL
)
782 if (buf
[0] == '\r' || buf
[0] == '\n') break;
789 FILE *procmsg_open_message_decrypted(MsgInfo
*msginfo
, MimeInfo
**mimeinfo
)
794 g_return_val_if_fail(msginfo
!= NULL
, NULL
);
796 if (mimeinfo
) *mimeinfo
= NULL
;
798 if ((fp
= procmsg_open_message(msginfo
)) == NULL
) return NULL
;
800 mimeinfo_
= procmime_scan_mime_header(fp
);
806 if (!MSG_IS_ENCRYPTED(msginfo
->flags
) &&
807 rfc2015_is_encrypted(mimeinfo_
)) {
808 MSG_SET_TMP_FLAGS(msginfo
->flags
, MSG_ENCRYPTED
);
811 if (MSG_IS_ENCRYPTED(msginfo
->flags
) &&
812 !msginfo
->plaintext_file
&&
813 !msginfo
->decryption_failed
) {
814 rfc2015_decrypt_message(msginfo
, mimeinfo_
, fp
);
815 if (msginfo
->plaintext_file
&&
816 !msginfo
->decryption_failed
) {
818 procmime_mimeinfo_free_all(mimeinfo_
);
819 if ((fp
= procmsg_open_message(msginfo
)) == NULL
)
821 mimeinfo_
= procmime_scan_mime_header(fp
);
829 if (mimeinfo
) *mimeinfo
= mimeinfo_
;
834 gboolean
procmsg_msg_exist(MsgInfo
*msginfo
)
839 if (!msginfo
) return FALSE
;
841 path
= folder_item_get_path(msginfo
->folder
);
843 ret
= !folder_item_is_msg_changed(msginfo
->folder
, msginfo
);
849 void procmsg_empty_trash(void)
854 for (cur
= folder_get_list(); cur
!= NULL
; cur
= cur
->next
) {
855 trash
= FOLDER(cur
->data
)->trash
;
856 if (trash
&& trash
->total
> 0)
857 folder_item_remove_all_msg(trash
);
861 gint
procmsg_send_queue(FolderItem
*queue
, gboolean save_msgs
)
867 queue
= folder_get_default_queue();
868 g_return_val_if_fail(queue
!= NULL
, -1);
870 folder_item_scan(queue
);
871 list
= folder_item_get_msg_list(queue
);
874 for (elem
= list
; elem
!= NULL
; elem
= elem
->next
) {
878 msginfo
= (MsgInfo
*)(elem
->data
);
880 file
= folder_item_fetch_msg(queue
, msginfo
->msgnum
);
882 if (procmsg_send_message_queue(file
) < 0) {
883 g_warning("Sending queued message %d failed.\n", msginfo
->msgnum
);
887 * We save in procmsg_send_message_queue because
888 * we need the destination folder from the queue
892 procmsg_save_to_outbox
893 (queue->folder->outbox,
896 folder_item_remove_msg(queue
, msginfo
->msgnum
);
900 procmsg_msginfo_free(msginfo
);
903 folder_update_item(queue
, FALSE
);
908 gint
procmsg_remove_special_headers(const gchar
*in
, const gchar
*out
)
913 if ((fp
= fopen(in
, "rb")) == NULL
) {
914 FILE_OP_ERROR(in
, "fopen");
917 if ((outfp
= fopen(out
, "wb")) == NULL
) {
918 FILE_OP_ERROR(out
, "fopen");
922 while (fgets(buf
, sizeof(buf
), fp
) != NULL
)
923 if (buf
[0] == '\r' || buf
[0] == '\n') break;
924 while (fgets(buf
, sizeof(buf
), fp
) != NULL
)
931 gint
procmsg_save_to_outbox(FolderItem
*outbox
, const gchar
*file
,
937 debug_print("saving sent message...\n");
940 outbox
= folder_get_default_outbox();
941 g_return_val_if_fail(outbox
!= NULL
, -1);
943 /* remove queueing headers */
945 gchar tmp
[MAXPATHLEN
+ 1];
947 g_snprintf(tmp
, sizeof(tmp
), "%s%ctmpmsg.out.%08x",
948 get_rc_dir(), G_DIR_SEPARATOR
, (guint
)random());
950 if (procmsg_remove_special_headers(file
, tmp
) !=0)
953 folder_item_scan(outbox
);
954 if ((num
= folder_item_add_msg(outbox
, tmp
, TRUE
)) < 0) {
955 g_warning("can't save message\n");
960 folder_item_scan(outbox
);
961 if ((num
= folder_item_add_msg(outbox
, file
, FALSE
)) < 0) {
962 g_warning("can't save message\n");
967 msginfo
= folder_item_get_msginfo(outbox
, num
);
968 if (msginfo
!= NULL
) {
969 procmsg_msginfo_unset_flags(msginfo
, ~0, 0);
970 procmsg_msginfo_free(msginfo
);
976 void procmsg_print_message(MsgInfo
*msginfo
, const gchar
*cmdline
)
978 static const gchar
*def_cmd
= "lpr %s";
985 g_return_if_fail(msginfo
);
987 if ((tmpfp
= procmime_get_first_text_content(msginfo
)) == NULL
) {
988 g_warning("Can't get text part\n");
992 prtmp
= g_strdup_printf("%s%cprinttmp.%08x",
993 get_mime_tmp_dir(), G_DIR_SEPARATOR
, id
++);
995 if ((prfp
= fopen(prtmp
, "wb")) == NULL
) {
996 FILE_OP_ERROR(prtmp
, "fopen");
1002 if (msginfo
->date
) fprintf(prfp
, "Date: %s\n", msginfo
->date
);
1003 if (msginfo
->from
) fprintf(prfp
, "From: %s\n", msginfo
->from
);
1004 if (msginfo
->to
) fprintf(prfp
, "To: %s\n", msginfo
->to
);
1005 if (msginfo
->cc
) fprintf(prfp
, "Cc: %s\n", msginfo
->cc
);
1006 if (msginfo
->newsgroups
)
1007 fprintf(prfp
, "Newsgroups: %s\n", msginfo
->newsgroups
);
1008 if (msginfo
->subject
) fprintf(prfp
, "Subject: %s\n", msginfo
->subject
);
1011 while (fgets(buf
, sizeof(buf
), tmpfp
) != NULL
)
1017 if (cmdline
&& (p
= strchr(cmdline
, '%')) && *(p
+ 1) == 's' &&
1018 !strchr(p
+ 2, '%'))
1019 g_snprintf(buf
, sizeof(buf
) - 1, cmdline
, prtmp
);
1022 g_warning("Print command line is invalid: `%s'\n",
1024 g_snprintf(buf
, sizeof(buf
) - 1, def_cmd
, prtmp
);
1030 if (buf
[strlen(buf
) - 1] != '&') strcat(buf
, "&");
1034 MsgInfo
*procmsg_msginfo_new_ref(MsgInfo
*msginfo
)
1041 MsgInfo
*procmsg_msginfo_new()
1043 MsgInfo
*newmsginfo
;
1045 newmsginfo
= g_new0(MsgInfo
, 1);
1046 newmsginfo
->refcnt
= 1;
1051 MsgInfo
*procmsg_msginfo_copy(MsgInfo
*msginfo
)
1053 MsgInfo
*newmsginfo
;
1055 if (msginfo
== NULL
) return NULL
;
1057 newmsginfo
= g_new0(MsgInfo
, 1);
1059 newmsginfo
->refcnt
= 1;
1061 #define MEMBCOPY(mmb) newmsginfo->mmb = msginfo->mmb
1062 #define MEMBDUP(mmb) newmsginfo->mmb = msginfo->mmb ? \
1063 g_strdup(msginfo->mmb) : NULL
1077 MEMBDUP(newsgroups
);
1084 MEMBCOPY(to_folder
);
1087 MEMBDUP(dispositionnotificationto
);
1088 MEMBDUP(returnreceiptto
);
1089 MEMBDUP(references
);
1092 MEMBCOPY(threadscore
);
1097 MsgInfo
*procmsg_msginfo_get_full_info(MsgInfo
*msginfo
)
1099 MsgInfo
*full_msginfo
;
1102 if (msginfo
== NULL
) return NULL
;
1104 file
= procmsg_get_message_file(msginfo
);
1106 g_warning("procmsg_msginfo_get_full_info(): can't get message file.\n");
1110 full_msginfo
= procheader_parse_file(file
, msginfo
->flags
, TRUE
, FALSE
);
1112 if (!full_msginfo
) return NULL
;
1114 full_msginfo
->msgnum
= msginfo
->msgnum
;
1115 full_msginfo
->size
= msginfo
->size
;
1116 full_msginfo
->mtime
= msginfo
->mtime
;
1117 full_msginfo
->folder
= msginfo
->folder
;
1118 full_msginfo
->to_folder
= msginfo
->to_folder
;
1120 full_msginfo
->plaintext_file
= g_strdup(msginfo
->plaintext_file
);
1121 full_msginfo
->decryption_failed
= msginfo
->decryption_failed
;
1124 return full_msginfo
;
1127 void procmsg_msginfo_free(MsgInfo
*msginfo
)
1129 if (msginfo
== NULL
) return;
1132 if (msginfo
->refcnt
> 0)
1135 g_free(msginfo
->fromspace
);
1136 g_free(msginfo
->references
);
1137 g_free(msginfo
->returnreceiptto
);
1138 g_free(msginfo
->dispositionnotificationto
);
1139 g_free(msginfo
->xface
);
1141 g_free(msginfo
->fromname
);
1143 g_free(msginfo
->date
);
1144 g_free(msginfo
->from
);
1145 g_free(msginfo
->to
);
1146 g_free(msginfo
->cc
);
1147 g_free(msginfo
->newsgroups
);
1148 g_free(msginfo
->subject
);
1149 g_free(msginfo
->msgid
);
1150 g_free(msginfo
->inreplyto
);
1151 g_free(msginfo
->xref
);
1156 guint
procmsg_msginfo_memusage(MsgInfo
*msginfo
)
1160 memusage
+= sizeof(MsgInfo
);
1161 if (msginfo
->fromname
)
1162 memusage
+= strlen(msginfo
->fromname
);
1164 memusage
+= strlen(msginfo
->date
);
1166 memusage
+= strlen(msginfo
->from
);
1168 memusage
+= strlen(msginfo
->to
);
1170 memusage
+= strlen(msginfo
->cc
);
1171 if (msginfo
->newsgroups
)
1172 memusage
+= strlen(msginfo
->newsgroups
);
1173 if (msginfo
->subject
)
1174 memusage
+= strlen(msginfo
->subject
);
1176 memusage
+= strlen(msginfo
->msgid
);
1177 if (msginfo
->inreplyto
)
1178 memusage
+= strlen(msginfo
->inreplyto
);
1180 memusage
+= strlen(msginfo
->xface
);
1181 if (msginfo
->dispositionnotificationto
)
1182 memusage
+= strlen(msginfo
->dispositionnotificationto
);
1183 if (msginfo
->returnreceiptto
)
1184 memusage
+= strlen(msginfo
->returnreceiptto
);
1185 if (msginfo
->references
)
1186 memusage
+= strlen(msginfo
->references
);
1187 if (msginfo
->fromspace
)
1188 memusage
+= strlen(msginfo
->fromspace
);
1193 gint
procmsg_cmp_msgnum_for_sort(gconstpointer a
, gconstpointer b
)
1195 const MsgInfo
*msginfo1
= a
;
1196 const MsgInfo
*msginfo2
= b
;
1203 return msginfo1
->msgnum
- msginfo2
->msgnum
;
1212 Q_MAIL_ACCOUNT_ID
= 4,
1213 Q_NEWS_ACCOUNT_ID
= 5,
1214 Q_SAVE_COPY_FOLDER
= 6,
1215 Q_REPLY_MESSAGE_ID
= 7,
1218 gint
procmsg_send_message_queue(const gchar
*file
)
1220 static HeaderEntry qentry
[] = {{"S:", NULL
, FALSE
},
1221 {"SSV:", NULL
, FALSE
},
1222 {"R:", NULL
, FALSE
},
1223 {"NG:", NULL
, FALSE
},
1224 {"MAID:", NULL
, FALSE
},
1225 {"NAID:", NULL
, FALSE
},
1226 {"SCF:", NULL
, FALSE
},
1227 {"RMID:", NULL
, FALSE
},
1228 {NULL
, NULL
, FALSE
}};
1231 gint mailval
= 0, newsval
= 0;
1233 gchar
*smtpserver
= NULL
;
1234 GSList
*to_list
= NULL
;
1235 GSList
*newsgroup_list
= NULL
;
1236 gchar
*savecopyfolder
= NULL
;
1237 gchar
*replymessageid
= NULL
;
1238 gchar buf
[BUFFSIZE
];
1240 PrefsAccount
*mailac
= NULL
, *newsac
= NULL
;
1243 g_return_val_if_fail(file
!= NULL
, -1);
1245 if ((fp
= fopen(file
, "rb")) == NULL
) {
1246 FILE_OP_ERROR(file
, "fopen");
1250 while ((hnum
= procheader_get_one_field(buf
, sizeof(buf
), fp
, qentry
))
1252 gchar
*p
= buf
+ strlen(qentry
[hnum
].name
);
1256 if (!from
) from
= g_strdup(p
);
1259 if (!smtpserver
) smtpserver
= g_strdup(p
);
1262 to_list
= address_list_append(to_list
, p
);
1265 newsgroup_list
= newsgroup_list_append(newsgroup_list
, p
);
1267 case Q_MAIL_ACCOUNT_ID
:
1268 mailac
= account_find_from_id(atoi(p
));
1270 case Q_NEWS_ACCOUNT_ID
:
1271 newsac
= account_find_from_id(atoi(p
));
1273 case Q_SAVE_COPY_FOLDER
:
1274 if (!savecopyfolder
) savecopyfolder
= g_strdup(p
);
1276 case Q_REPLY_MESSAGE_ID
:
1277 if (!replymessageid
) replymessageid
= g_strdup(p
);
1281 filepos
= ftell(fp
);
1284 debug_print("Sending message by mail\n");
1286 g_warning("Queued message header is broken.\n");
1288 } else if (mailac
&& mailac
->use_mail_command
&&
1289 mailac
->mail_command
&& (* mailac
->mail_command
)) {
1290 mailval
= send_message_local(mailac
->mail_command
, fp
);
1292 } else if (prefs_common
.use_extsend
&& prefs_common
.extsend_cmd
) {
1293 mailval
= send_message_local(prefs_common
.extsend_cmd
, fp
);
1297 mailac
= account_find_from_smtp_server(from
, smtpserver
);
1299 g_warning("Account not found. "
1300 "Using current account...\n");
1301 mailac
= cur_account
;
1306 mailval
= send_message_smtp(mailac
, to_list
, fp
);
1308 PrefsAccount tmp_ac
;
1310 g_warning("Account not found.\n");
1312 memset(&tmp_ac
, 0, sizeof(PrefsAccount
));
1313 tmp_ac
.address
= from
;
1314 tmp_ac
.smtp_server
= smtpserver
;
1315 tmp_ac
.smtpport
= SMTP_PORT
;
1316 mailval
= send_message_smtp(&tmp_ac
, to_list
, fp
);
1322 _("Error occurred while sending the message to `%s'."),
1323 mailac
? mailac
->smtp_server
: smtpserver
);
1326 _("Error occurred while sending the message with command `%s'."),
1327 (mailac
&& mailac
->use_mail_command
&&
1328 mailac
->mail_command
&& (*mailac
->mail_command
)) ?
1329 mailac
->mail_command
: prefs_common
.extsend_cmd
);
1333 fseek(fp
, filepos
, SEEK_SET
);
1334 if (newsgroup_list
&& (newsval
== 0)) {
1339 /* write to temporary file */
1340 tmp
= g_strdup_printf("%s%ctmp%d", g_get_tmp_dir(),
1341 G_DIR_SEPARATOR
, (gint
)file
);
1342 if ((tmpfp
= fopen(tmp
, "wb")) == NULL
) {
1343 FILE_OP_ERROR(tmp
, "fopen");
1345 alertpanel_error(_("Could not create temporary file for news sending."));
1347 if (change_file_mode_rw(tmpfp
, tmp
) < 0) {
1348 FILE_OP_ERROR(tmp
, "chmod");
1349 g_warning("can't change file mode\n");
1352 while ((newsval
== 0) && fgets(buf
, sizeof(buf
), fp
) != NULL
) {
1353 if (fputs(buf
, tmpfp
) == EOF
) {
1354 FILE_OP_ERROR(tmp
, "fputs");
1356 alertpanel_error(_("Error when writing temporary file for news sending."));
1362 debug_print("Sending message by news\n");
1364 folder
= FOLDER(newsac
->folder
);
1366 newsval
= news_post(folder
, tmp
);
1368 alertpanel_error(_("Error occurred while posting the message to %s ."),
1369 newsac
->nntp_server
);
1377 slist_free_strings(to_list
);
1378 g_slist_free(to_list
);
1379 slist_free_strings(newsgroup_list
);
1380 g_slist_free(newsgroup_list
);
1385 /* save message to outbox */
1386 if (mailval
== 0 && newsval
== 0 && savecopyfolder
) {
1389 debug_print("saving sent message...\n");
1391 outbox
= folder_find_item_from_identifier(savecopyfolder
);
1393 outbox
= folder_get_default_outbox();
1395 procmsg_save_to_outbox(outbox
, file
, TRUE
);
1398 if (replymessageid
!= NULL
) {
1402 tokens
= g_strsplit(replymessageid
, "\x7f", 0);
1403 item
= folder_find_item_from_identifier(tokens
[0]);
1407 msginfo
= folder_item_get_msginfo(item
, atoi(tokens
[1]));
1408 if ((msginfo
!= NULL
) && (strcmp(msginfo
->msgid
, tokens
[2]) != 0)) {
1409 procmsg_msginfo_free(msginfo
);
1413 if (msginfo
== NULL
) {
1414 msginfo
= folder_item_get_msginfo_by_msgid(item
, tokens
[2]);
1417 if (msginfo
!= NULL
) {
1418 procmsg_msginfo_unset_flags(msginfo
, MSG_FORWARDED
, 0);
1419 procmsg_msginfo_set_flags(msginfo
, MSG_REPLIED
, 0);
1421 procmsg_msginfo_free(msginfo
);
1427 g_free(savecopyfolder
);
1428 g_free(replymessageid
);
1430 return (newsval
!= 0 ? newsval
: mailval
);
1433 #define CHANGE_FLAGS(msginfo) \
1435 if (msginfo->folder->folder->change_flags != NULL) \
1436 msginfo->folder->folder->change_flags(msginfo->folder->folder, \
1441 void procmsg_msginfo_set_flags(MsgInfo
*msginfo
, MsgPermFlags perm_flags
, MsgTmpFlags tmp_flags
)
1444 MsgInfoUpdate msginfo_update
;
1446 g_return_if_fail(msginfo
!= NULL
);
1447 item
= msginfo
->folder
;
1448 g_return_if_fail(item
!= NULL
);
1450 debug_print("Setting flags for message %d in folder %s\n", msginfo
->msgnum
, item
->path
);
1452 /* if new flag is set */
1453 if ((perm_flags
& MSG_NEW
) && !MSG_IS_NEW(msginfo
->flags
) &&
1454 !MSG_IS_IGNORE_THREAD(msginfo
->flags
)) {
1456 item
->need_update
= TRUE
;
1459 /* if unread flag is set */
1460 if ((perm_flags
& MSG_UNREAD
) && !MSG_IS_UNREAD(msginfo
->flags
) &&
1461 !MSG_IS_IGNORE_THREAD(msginfo
->flags
)) {
1463 item
->need_update
= TRUE
;
1466 if (!MSG_IS_UNREAD(msginfo
->flags
) &&(perm_flags
& MSG_UNREAD
)
1467 && procmsg_msg_has_marked_parent(msginfo
)) {
1468 item
->unreadmarked
++;
1469 item
->need_update
= TRUE
;
1472 if (!MSG_IS_MARKED(msginfo
->flags
) && (perm_flags
& MSG_MARKED
)) {
1473 procmsg_update_unread_children(msginfo
, TRUE
);
1477 /* if ignore thread flag is set */
1478 if ((perm_flags
& MSG_IGNORE_THREAD
) && !MSG_IS_IGNORE_THREAD(msginfo
->flags
)) {
1479 if (MSG_IS_NEW(msginfo
->flags
) || (perm_flags
& MSG_NEW
)) {
1481 item
->need_update
= TRUE
;
1483 if (MSG_IS_UNREAD(msginfo
->flags
) || (perm_flags
& MSG_UNREAD
)) {
1485 item
->need_update
= TRUE
;
1487 if ((perm_flags
& MSG_UNREAD
) || (MSG_IS_UNREAD(msginfo
->flags
)
1488 && procmsg_msg_has_marked_parent(msginfo
))) {
1489 item
->unreadmarked
--;
1490 item
->need_update
= TRUE
;
1492 if ((perm_flags
& MSG_MARKED
) || (MSG_IS_MARKED(msginfo
->flags
)
1493 && !MSG_IS_IGNORE_THREAD(msginfo
->flags
))) {
1494 procmsg_update_unread_children(msginfo
, FALSE
);
1499 if (MSG_IS_IMAP(msginfo
->flags
))
1500 imap_msg_set_perm_flags(msginfo
, perm_flags
);
1502 msginfo
->flags
.perm_flags
|= perm_flags
;
1503 msginfo
->flags
.tmp_flags
|= tmp_flags
;
1505 msginfo_update
.msginfo
= msginfo
;
1506 hooks_invoke(MSGINFO_UPDATE_HOOKLIST
, &msginfo_update
);
1508 CHANGE_FLAGS(msginfo
);
1509 procmsg_msginfo_write_flags(msginfo
);
1512 void procmsg_msginfo_unset_flags(MsgInfo
*msginfo
, MsgPermFlags perm_flags
, MsgTmpFlags tmp_flags
)
1515 MsgInfoUpdate msginfo_update
;
1517 g_return_if_fail(msginfo
!= NULL
);
1518 item
= msginfo
->folder
;
1519 g_return_if_fail(item
!= NULL
);
1521 debug_print("Unsetting flags for message %d in folder %s\n", msginfo
->msgnum
, item
->path
);
1523 /* if new flag is unset */
1524 if ((perm_flags
& MSG_NEW
) && MSG_IS_NEW(msginfo
->flags
) &&
1525 !MSG_IS_IGNORE_THREAD(msginfo
->flags
)) {
1527 item
->need_update
= TRUE
;
1530 /* if unread flag is unset */
1531 if ((perm_flags
& MSG_UNREAD
) && MSG_IS_UNREAD(msginfo
->flags
) &&
1532 !MSG_IS_IGNORE_THREAD(msginfo
->flags
)) {
1534 item
->need_update
= TRUE
;
1537 if (MSG_IS_UNREAD(msginfo
->flags
) && (perm_flags
& MSG_UNREAD
)
1538 && !MSG_IS_IGNORE_THREAD(msginfo
->flags
)
1539 && procmsg_msg_has_marked_parent(msginfo
)) {
1540 item
->unreadmarked
--;
1541 item
->need_update
= TRUE
;
1544 if (MSG_IS_MARKED(msginfo
->flags
) && (perm_flags
& MSG_MARKED
)
1545 && !MSG_IS_IGNORE_THREAD(msginfo
->flags
)) {
1546 procmsg_update_unread_children(msginfo
, FALSE
);
1549 /* if ignore thread flag is unset */
1550 if ((perm_flags
& MSG_IGNORE_THREAD
) && MSG_IS_IGNORE_THREAD(msginfo
->flags
)) {
1551 if (MSG_IS_NEW(msginfo
->flags
) && !(perm_flags
& MSG_NEW
)) {
1553 item
->need_update
= TRUE
;
1555 if (MSG_IS_UNREAD(msginfo
->flags
) && !(perm_flags
& MSG_UNREAD
)) {
1557 item
->need_update
= TRUE
;
1559 if (MSG_IS_UNREAD(msginfo
->flags
) && !(perm_flags
& MSG_UNREAD
)
1560 && procmsg_msg_has_marked_parent(msginfo
)) {
1561 item
->unreadmarked
++;
1562 item
->need_update
= TRUE
;
1564 if (MSG_IS_MARKED(msginfo
->flags
) && !(perm_flags
& MSG_MARKED
)) {
1565 procmsg_update_unread_children(msginfo
, TRUE
);
1570 if (MSG_IS_IMAP(msginfo
->flags
))
1571 imap_msg_unset_perm_flags(msginfo
, perm_flags
);
1573 msginfo
->flags
.perm_flags
&= ~perm_flags
;
1574 msginfo
->flags
.tmp_flags
&= ~tmp_flags
;
1576 msginfo_update
.msginfo
= msginfo
;
1577 hooks_invoke(MSGINFO_UPDATE_HOOKLIST
, &msginfo_update
);
1579 CHANGE_FLAGS(msginfo
);
1580 procmsg_msginfo_write_flags(msginfo
);
1583 void procmsg_msginfo_write_flags(MsgInfo
*msginfo
)
1588 destdir
= folder_item_get_path(msginfo
->folder
);
1589 if (!is_dir_exist(destdir
))
1590 make_dir_hier(destdir
);
1592 if ((fp
= procmsg_open_mark_file(destdir
, TRUE
))) {
1593 procmsg_write_flags(msginfo
, fp
);
1596 g_warning("Can't open mark file.\n");
1602 gboolean
procmsg_msg_has_marked_parent (MsgInfo
*info
)
1605 g_return_val_if_fail(info
!= NULL
, FALSE
);
1606 if (info
!= NULL
&& info
->folder
!= NULL
&& info
->inreplyto
!= NULL
) {
1607 tmp
= folder_item_get_msginfo_by_msgid(info
->folder
, info
->inreplyto
);
1608 if (tmp
&& MSG_IS_MARKED(tmp
->flags
)) {
1609 procmsg_msginfo_free(tmp
);
1611 } else if (tmp
!= NULL
) {
1612 gboolean result
= procmsg_msg_has_marked_parent(tmp
);
1613 procmsg_msginfo_free(tmp
);
1622 GSList
*procmsg_find_children (MsgInfo
*info
)
1624 GSList
*children
= NULL
;
1627 g_return_val_if_fail(info
!=NULL
, NULL
);
1628 if (info
->msgid
== NULL
)
1630 all
= folder_item_get_msg_list(info
->folder
);
1631 for (cur
= all
; cur
!= NULL
; cur
= g_slist_next(cur
)) {
1632 MsgInfo
*tmp
= (MsgInfo
*)cur
->data
;
1633 if (tmp
->inreplyto
&& !strcmp(tmp
->inreplyto
, info
->msgid
)) {
1634 GSList
*grand_children
;
1635 children
= g_slist_prepend(children
, tmp
);
1636 grand_children
= procmsg_find_children(tmp
);
1637 children
= slist_concat_unique(children
, grand_children
);
1638 g_slist_free(grand_children
);
1640 if (tmp
&& tmp
!= info
)
1641 procmsg_msginfo_free(tmp
);
1647 static void procmsg_update_unread_children (MsgInfo
*info
, gboolean newly_marked
)
1649 GSList
*children
= procmsg_find_children(info
);
1651 for (cur
= children
; cur
!= NULL
; cur
= g_slist_next(cur
)) {
1652 MsgInfo
*tmp
= (MsgInfo
*)cur
->data
;
1653 if(MSG_IS_UNREAD(tmp
->flags
) && !MSG_IS_IGNORE_THREAD(tmp
->flags
)) {
1655 info
->folder
->unreadmarked
++;
1657 info
->folder
->unreadmarked
--;
1658 info
->folder
->need_update
= TRUE
;
1660 procmsg_msginfo_free(tmp
);