2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2005 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.
23 #include <glib/gi18n.h>
31 #include "procheader.h"
32 #include "send_message.h"
34 #include "statusbar.h"
35 #include "prefs_filtering.h"
36 #include "filtering.h"
38 #include "prefs_common.h"
40 #include "alertpanel.h"
44 #include "partial_download.h"
46 static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_session);
54 Q_MAIL_ACCOUNT_ID = 4,
55 Q_NEWS_ACCOUNT_ID = 5,
56 Q_SAVE_COPY_FOLDER = 6,
57 Q_REPLY_MESSAGE_ID = 7,
64 GHashTable *procmsg_msg_hash_table_create(GSList *mlist)
66 GHashTable *msg_table;
68 if (mlist == NULL) return NULL;
70 msg_table = g_hash_table_new(NULL, g_direct_equal);
71 procmsg_msg_hash_table_append(msg_table, mlist);
76 void procmsg_msg_hash_table_append(GHashTable *msg_table, GSList *mlist)
81 if (msg_table == NULL || mlist == NULL) return;
83 for (cur = mlist; cur != NULL; cur = cur->next) {
84 msginfo = (MsgInfo *)cur->data;
86 g_hash_table_insert(msg_table,
87 GUINT_TO_POINTER(msginfo->msgnum),
92 GHashTable *procmsg_to_folder_hash_table_create(GSList *mlist)
94 GHashTable *msg_table;
98 if (mlist == NULL) return NULL;
100 msg_table = g_hash_table_new(NULL, g_direct_equal);
102 for (cur = mlist; cur != NULL; cur = cur->next) {
103 msginfo = (MsgInfo *)cur->data;
104 g_hash_table_insert(msg_table, msginfo->to_folder, msginfo);
110 gint procmsg_get_last_num_in_msg_list(GSList *mlist)
116 for (cur = mlist; cur != NULL; cur = cur->next) {
117 msginfo = (MsgInfo *)cur->data;
118 if (msginfo && msginfo->msgnum > last)
119 last = msginfo->msgnum;
125 void procmsg_msg_list_free(GSList *mlist)
130 for (cur = mlist; cur != NULL; cur = cur->next) {
131 msginfo = (MsgInfo *)cur->data;
132 procmsg_msginfo_free(msginfo);
146 /* CLAWS subject threading:
148 in the first round it inserts subject lines in a
149 relation (subject <-> node)
151 the second round finishes the threads by attaching
152 matching subject lines to the one found in the
153 relation. will use the oldest node with the same
154 subject that is not more then thread_by_subject_max_age
155 days old (see subject_relation_lookup)
158 static void subject_relation_insert(GRelation *relation, GNode *node)
163 g_return_if_fail(relation != NULL);
164 g_return_if_fail(node != NULL);
165 msginfo = (MsgInfo *) node->data;
166 g_return_if_fail(msginfo != NULL);
168 subject = msginfo->subject;
171 subject += subject_get_prefix_length(subject);
173 g_relation_insert(relation, subject, node);
176 static GNode *subject_relation_lookup(GRelation *relation, MsgInfo *msginfo)
183 g_return_val_if_fail(relation != NULL, NULL);
185 subject = msginfo->subject;
188 prefix_length = subject_get_prefix_length(subject);
189 if (prefix_length <= 0)
191 subject += prefix_length;
193 tuples = g_relation_select(relation, subject, 0);
197 if (tuples->len > 0) {
199 GNode *relation_node;
200 MsgInfo *relation_msginfo = NULL, *best_msginfo = NULL;
203 /* check all nodes with the same subject to find the best parent */
204 for (i = 0; i < tuples->len; i++) {
205 relation_node = (GNode *) g_tuples_index(tuples, i, 1);
206 relation_msginfo = (MsgInfo *) relation_node->data;
209 /* best node should be the oldest in the found nodes */
210 /* parent node must not be older then msginfo */
211 if ((relation_msginfo->date_t < msginfo->date_t) &&
212 ((best_msginfo == NULL) ||
213 (best_msginfo->date_t > relation_msginfo->date_t)))
216 /* parent node must not be more then thread_by_subject_max_age
217 days older then msginfo */
218 if (abs(difftime(msginfo->date_t, relation_msginfo->date_t)) >
219 prefs_common.thread_by_subject_max_age * 3600 * 24)
222 /* can add new tests for all matching
223 nodes found by subject */
226 node = relation_node;
227 best_msginfo = relation_msginfo;
232 g_tuples_destroy(tuples);
236 /* return the reversed thread tree */
237 GNode *procmsg_get_thread_tree(GSList *mlist)
239 GNode *root, *parent, *node, *next;
240 GHashTable *msgid_table;
241 GRelation *subject_relation;
246 root = g_node_new(NULL);
247 msgid_table = g_hash_table_new(g_str_hash, g_str_equal);
248 subject_relation = g_relation_new(2);
249 g_relation_index(subject_relation, 0, g_str_hash, g_str_equal);
251 for (; mlist != NULL; mlist = mlist->next) {
252 msginfo = (MsgInfo *)mlist->data;
255 if (msginfo->inreplyto) {
256 parent = g_hash_table_lookup(msgid_table, msginfo->inreplyto);
257 if (parent == NULL) {
261 node = g_node_insert_data_before
262 (parent, parent == root ? parent->children : NULL,
264 if ((msgid = msginfo->msgid) && g_hash_table_lookup(msgid_table, msgid) == NULL)
265 g_hash_table_insert(msgid_table, (gchar *)msgid, node);
267 /* CLAWS: add subject to relation (without prefix) */
268 if (prefs_common.thread_by_subject) {
269 subject_relation_insert(subject_relation, node);
273 /* complete the unfinished threads */
274 for (node = root->children; node != NULL; ) {
276 msginfo = (MsgInfo *)node->data;
279 if (msginfo->inreplyto)
280 parent = g_hash_table_lookup(msgid_table, msginfo->inreplyto);
282 /* try looking for the indirect parent */
283 if (!parent && msginfo->references) {
284 for (reflist = msginfo->references;
285 reflist != NULL; reflist = reflist->next)
286 if ((parent = g_hash_table_lookup
287 (msgid_table, reflist->data)) != NULL)
291 /* node should not be the parent, and node should not
292 be an ancestor of parent (circular reference) */
293 if (parent && parent != node &&
294 !g_node_is_ancestor(node, parent)) {
297 (parent, parent->children, node);
303 if (prefs_common.thread_by_subject) {
304 for (node = root->children; node && node != NULL;) {
306 msginfo = (MsgInfo *) node->data;
308 parent = subject_relation_lookup(subject_relation, msginfo);
310 /* the node may already be threaded by IN-REPLY-TO, so go up
312 find the parent node */
313 if (parent != NULL) {
314 if (g_node_is_ancestor(node, parent))
322 g_node_append(parent, node);
329 g_relation_destroy(subject_relation);
330 g_hash_table_destroy(msgid_table);
335 void procmsg_move_messages(GSList *mlist)
337 GSList *cur, *movelist = NULL;
339 FolderItem *dest = NULL;
343 folder_item_update_freeze();
345 for (cur = mlist; cur != NULL; cur = cur->next) {
346 msginfo = (MsgInfo *)cur->data;
348 dest = msginfo->to_folder;
349 movelist = g_slist_append(movelist, msginfo);
350 } else if (dest == msginfo->to_folder) {
351 movelist = g_slist_append(movelist, msginfo);
353 folder_item_move_msgs(dest, movelist);
354 g_slist_free(movelist);
356 dest = msginfo->to_folder;
357 movelist = g_slist_append(movelist, msginfo);
359 procmsg_msginfo_set_to_folder(msginfo, NULL);
363 folder_item_move_msgs(dest, movelist);
364 g_slist_free(movelist);
367 folder_item_update_thaw();
370 void procmsg_copy_messages(GSList *mlist)
372 GSList *cur, *copylist = NULL;
374 FolderItem *dest = NULL;
378 folder_item_update_freeze();
380 for (cur = mlist; cur != NULL; cur = cur->next) {
381 msginfo = (MsgInfo *)cur->data;
383 dest = msginfo->to_folder;
384 copylist = g_slist_append(copylist, msginfo);
385 } else if (dest == msginfo->to_folder) {
386 copylist = g_slist_append(copylist, msginfo);
388 folder_item_copy_msgs(dest, copylist);
389 g_slist_free(copylist);
391 dest = msginfo->to_folder;
392 copylist = g_slist_append(copylist, msginfo);
394 procmsg_msginfo_set_to_folder(msginfo, NULL);
398 folder_item_copy_msgs(dest, copylist);
399 g_slist_free(copylist);
402 folder_item_update_thaw();
405 gchar *procmsg_get_message_file_path(MsgInfo *msginfo)
409 g_return_val_if_fail(msginfo != NULL, NULL);
411 if (msginfo->plaintext_file)
412 file = g_strdup(msginfo->plaintext_file);
414 file = folder_item_fetch_msg(msginfo->folder, msginfo->msgnum);
420 gchar *procmsg_get_message_file(MsgInfo *msginfo)
422 gchar *filename = NULL;
424 g_return_val_if_fail(msginfo != NULL, NULL);
426 filename = folder_item_fetch_msg(msginfo->folder, msginfo->msgnum);
428 debug_print("can't fetch message %d\n", msginfo->msgnum);
433 gchar *procmsg_get_message_file_full(MsgInfo *msginfo, gboolean headers, gboolean body)
435 gchar *filename = NULL;
437 g_return_val_if_fail(msginfo != NULL, NULL);
439 filename = folder_item_fetch_msg_full(msginfo->folder, msginfo->msgnum,
442 debug_print("can't fetch message %d\n", msginfo->msgnum);
447 GSList *procmsg_get_message_file_list(GSList *mlist)
449 GSList *file_list = NULL;
451 MsgFileInfo *fileinfo;
454 while (mlist != NULL) {
455 msginfo = (MsgInfo *)mlist->data;
456 file = procmsg_get_message_file(msginfo);
458 procmsg_message_file_list_free(file_list);
461 fileinfo = g_new(MsgFileInfo, 1);
462 fileinfo->msginfo = procmsg_msginfo_new_ref(msginfo);
463 fileinfo->file = file;
464 fileinfo->flags = g_new(MsgFlags, 1);
465 *fileinfo->flags = msginfo->flags;
466 file_list = g_slist_prepend(file_list, fileinfo);
470 file_list = g_slist_reverse(file_list);
475 void procmsg_message_file_list_free(MsgInfoList *file_list)
478 MsgFileInfo *fileinfo;
480 for (cur = file_list; cur != NULL; cur = cur->next) {
481 fileinfo = (MsgFileInfo *)cur->data;
482 procmsg_msginfo_free(fileinfo->msginfo);
483 g_free(fileinfo->file);
484 g_free(fileinfo->flags);
488 g_slist_free(file_list);
491 FILE *procmsg_open_message(MsgInfo *msginfo)
496 g_return_val_if_fail(msginfo != NULL, NULL);
498 file = procmsg_get_message_file_path(msginfo);
499 g_return_val_if_fail(file != NULL, NULL);
501 if (!is_file_exist(file)) {
503 file = procmsg_get_message_file(msginfo);
508 if ((fp = fopen(file, "rb")) == NULL) {
509 FILE_OP_ERROR(file, "fopen");
516 if (MSG_IS_QUEUED(msginfo->flags) || MSG_IS_DRAFT(msginfo->flags)) {
519 while (fgets(buf, sizeof(buf), fp) != NULL)
520 if (buf[0] == '\r' || buf[0] == '\n') break;
526 gboolean procmsg_msg_exist(MsgInfo *msginfo)
531 if (!msginfo) return FALSE;
533 path = folder_item_get_path(msginfo->folder);
535 ret = !folder_item_is_msg_changed(msginfo->folder, msginfo);
541 void procmsg_get_filter_keyword(MsgInfo *msginfo, gchar **header, gchar **key,
542 PrefsFilterType type)
544 static HeaderEntry hentry[] = {{"X-BeenThere:", NULL, TRUE},
545 {"X-ML-Name:", NULL, TRUE},
546 {"X-List:", NULL, TRUE},
547 {"X-Mailing-list:", NULL, TRUE},
548 {"List-Id:", NULL, TRUE},
549 {"X-Sequence:", NULL, TRUE},
550 {NULL, NULL, FALSE}};
556 H_X_MAILING_LIST = 3,
563 g_return_if_fail(msginfo != NULL);
564 g_return_if_fail(header != NULL);
565 g_return_if_fail(key != NULL);
574 if ((fp = procmsg_open_message(msginfo)) == NULL)
576 procheader_get_header_fields(fp, hentry);
579 #define SET_FILTER_KEY(hstr, idx) \
581 *header = g_strdup(hstr); \
582 *key = hentry[idx].body; \
583 hentry[idx].body = NULL; \
586 if (hentry[H_X_BEENTHERE].body != NULL) {
587 SET_FILTER_KEY("header \"X-BeenThere\"", H_X_BEENTHERE);
588 } else if (hentry[H_X_ML_NAME].body != NULL) {
589 SET_FILTER_KEY("header \"X-ML-Name\"", H_X_ML_NAME);
590 } else if (hentry[H_X_LIST].body != NULL) {
591 SET_FILTER_KEY("header \"X-List\"", H_X_LIST);
592 } else if (hentry[H_X_MAILING_LIST].body != NULL) {
593 SET_FILTER_KEY("header \"X-Mailing-List\"", H_X_MAILING_LIST);
594 } else if (hentry[H_LIST_ID].body != NULL) {
595 SET_FILTER_KEY("header \"List-Id\"", H_LIST_ID);
596 extract_list_id_str(*key);
597 } else if (hentry[H_X_SEQUENCE].body != NULL) {
600 SET_FILTER_KEY("X-Sequence", H_X_SEQUENCE);
603 while (*p != '\0' && !g_ascii_isspace(*p)) p++;
604 while (g_ascii_isspace(*p)) p++;
605 if (g_ascii_isdigit(*p)) {
611 } else if (msginfo->subject) {
612 *header = g_strdup("subject");
613 *key = g_strdup(msginfo->subject);
616 #undef SET_FILTER_KEY
618 g_free(hentry[H_X_BEENTHERE].body);
619 hentry[H_X_BEENTHERE].body = NULL;
620 g_free(hentry[H_X_ML_NAME].body);
621 hentry[H_X_ML_NAME].body = NULL;
622 g_free(hentry[H_X_LIST].body);
623 hentry[H_X_LIST].body = NULL;
624 g_free(hentry[H_X_MAILING_LIST].body);
625 hentry[H_X_MAILING_LIST].body = NULL;
626 g_free(hentry[H_LIST_ID].body);
627 hentry[H_LIST_ID].body = NULL;
631 *header = g_strdup("from");
632 *key = g_strdup(msginfo->from);
635 *header = g_strdup("to");
636 *key = g_strdup(msginfo->to);
638 case FILTER_BY_SUBJECT:
639 *header = g_strdup("subject");
640 *key = g_strdup(msginfo->subject);
647 void procmsg_empty_trash(FolderItem *trash)
649 if (trash && trash->total_msgs > 0) {
650 GSList *mlist = folder_item_get_msg_list(trash);
652 for (cur = mlist ; cur != NULL ; cur = cur->next) {
653 MsgInfo * msginfo = (MsgInfo *) cur->data;
654 if (MSG_IS_LOCKED(msginfo->flags))
656 if (msginfo->total_size != 0 &&
657 msginfo->size != (off_t)msginfo->total_size)
658 partial_mark_for_delete(msginfo);
660 procmsg_msginfo_free(msginfo);
663 folder_item_remove_all_msg(trash);
667 void procmsg_empty_all_trash(void)
672 for (cur = folder_get_list(); cur != NULL; cur = cur->next) {
673 trash = FOLDER(cur->data)->trash;
674 procmsg_empty_trash(trash);
678 static PrefsAccount *procmsg_get_account_from_file(const gchar *file)
680 PrefsAccount *mailac = NULL;
684 static HeaderEntry qentry[] = {{"S:", NULL, FALSE},
685 {"SSV:", NULL, FALSE},
687 {"NG:", NULL, FALSE},
688 {"MAID:", NULL, FALSE},
689 {"NAID:", NULL, FALSE},
690 {"SCF:", NULL, FALSE},
691 {"RMID:", NULL, FALSE},
692 {"FMID:", NULL, FALSE},
693 {"X-Sylpheed-Privacy-System:", NULL, FALSE},
694 {"X-Sylpheed-Encrypt:", NULL, FALSE},
695 {"X-Sylpheed-Encrypt-Data:", NULL, FALSE},
696 {NULL, NULL, FALSE}};
698 g_return_val_if_fail(file != NULL, NULL);
700 if ((fp = fopen(file, "rb")) == NULL) {
701 FILE_OP_ERROR(file, "fopen");
705 while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, qentry))
707 gchar *p = buf + strlen(qentry[hnum].name);
709 if (hnum == Q_MAIL_ACCOUNT_ID) {
710 mailac = account_find_from_id(atoi(p));
718 static GSList *procmsg_list_sort_by_account(FolderItem *queue, GSList *list)
720 GSList *result = NULL;
722 PrefsAccount *last_account = NULL;
725 gboolean nothing_to_sort = TRUE;
730 orig = g_slist_copy(list);
732 msg = (MsgInfo *)orig->data;
734 for (cur = orig; cur; cur = cur->next)
735 debug_print("sort before %s\n", ((MsgInfo *)cur->data)->from);
740 nothing_to_sort = TRUE;
744 PrefsAccount *ac = procmsg_get_account_from_file(file);
745 msg = (MsgInfo *)cur->data;
746 file = folder_item_fetch_msg(queue, msg->msgnum);
749 if (last_account == NULL || (ac != NULL && ac == last_account)) {
750 result = g_slist_append(result, msg);
751 orig = g_slist_remove(orig, msg);
753 nothing_to_sort = FALSE;
759 if (orig || g_slist_length(orig)) {
760 if (!last_account && nothing_to_sort) {
761 /* can't find an account for the rest of the list */
764 result = g_slist_append(result, cur->data);
775 for (cur = result; cur; cur = cur->next)
776 debug_print("sort after %s\n", ((MsgInfo *)cur->data)->from);
783 static gboolean procmsg_is_last_for_account(FolderItem *queue, MsgInfo *msginfo, GSList *elem)
785 gchar *file = folder_item_fetch_msg(queue, msginfo->msgnum);
786 PrefsAccount *ac = procmsg_get_account_from_file(file);
789 for (cur = elem; cur; cur = cur->next) {
790 MsgInfo *cur_msginfo = (MsgInfo *)cur->data;
791 file = folder_item_fetch_msg(queue, cur_msginfo->msgnum);
793 if (cur_msginfo != msginfo && !MSG_IS_LOCKED(cur_msginfo->flags)) {
794 if (procmsg_get_account_from_file(file) == ac) {
806 *\brief Send messages in queue
808 *\param queue Queue folder to process
809 *\param save_msgs Unused
811 *\return Number of messages sent, negative if an error occurred
812 * positive if no error occurred
814 gint procmsg_send_queue(FolderItem *queue, gboolean save_msgs)
816 gint sent = 0, err = 0;
818 GSList *sorted_list = NULL;
821 queue = folder_get_default_queue();
822 g_return_val_if_fail(queue != NULL, -1);
824 folder_item_scan(queue);
825 list = folder_item_get_msg_list(queue);
827 /* sort the list per sender account; this helps reusing the same SMTP server */
828 sorted_list = procmsg_list_sort_by_account(queue, list);
830 for (elem = sorted_list; elem != NULL; elem = elem->next) {
834 msginfo = (MsgInfo *)(elem->data);
835 if (!MSG_IS_LOCKED(msginfo->flags)) {
836 file = folder_item_fetch_msg(queue, msginfo->msgnum);
838 if (procmsg_send_message_queue_full(file,
839 !procmsg_is_last_for_account(queue, msginfo, elem)) < 0) {
840 g_warning("Sending queued message %d failed.\n",
845 * We save in procmsg_send_message_queue because
846 * we need the destination folder from the queue
850 procmsg_save_to_outbox
851 (queue->folder->outbox,
855 folder_item_remove_msg(queue, msginfo->msgnum);
860 /* FIXME: supposedly if only one message is locked, and queue
861 * is being flushed, the following free says something like
862 * "freeing msg ## in folder (nil)". */
863 procmsg_msginfo_free(msginfo);
866 g_slist_free(sorted_list);
868 return (err != 0 ? -err : sent);
872 *\brief Determine if a queue folder is empty
874 *\param queue Queue folder to process
876 *\return TRUE if the queue folder is empty, otherwise return FALSE
878 gboolean procmsg_queue_is_empty(FolderItem *queue)
881 gboolean res = FALSE;
883 queue = folder_get_default_queue();
884 g_return_val_if_fail(queue != NULL, TRUE);
886 folder_item_scan(queue);
887 list = folder_item_get_msg_list(queue);
888 res = (list == NULL);
889 procmsg_msg_list_free(list);
893 gint procmsg_remove_special_headers(const gchar *in, const gchar *out)
898 if ((fp = fopen(in, "rb")) == NULL) {
899 FILE_OP_ERROR(in, "fopen");
902 if ((outfp = fopen(out, "wb")) == NULL) {
903 FILE_OP_ERROR(out, "fopen");
907 while (fgets(buf, sizeof(buf), fp) != NULL)
908 if (buf[0] == '\r' || buf[0] == '\n') break;
909 while (fgets(buf, sizeof(buf), fp) != NULL)
916 gint procmsg_save_to_outbox(FolderItem *outbox, const gchar *file,
920 MsgInfo *msginfo, *tmp_msginfo;
921 MsgFlags flag = {0, 0};
923 debug_print("saving sent message...\n");
926 outbox = folder_get_default_outbox();
927 g_return_val_if_fail(outbox != NULL, -1);
929 /* remove queueing headers */
931 gchar tmp[MAXPATHLEN + 1];
933 g_snprintf(tmp, sizeof(tmp), "%s%ctmpmsg.out.%08x",
934 get_rc_dir(), G_DIR_SEPARATOR, (guint) rand());
936 if (procmsg_remove_special_headers(file, tmp) !=0)
939 folder_item_scan(outbox);
940 if ((num = folder_item_add_msg(outbox, tmp, &flag, TRUE)) < 0) {
941 g_warning("can't save message\n");
946 folder_item_scan(outbox);
947 if ((num = folder_item_add_msg
948 (outbox, file, &flag, FALSE)) < 0) {
949 g_warning("can't save message\n");
954 msginfo = folder_item_get_msginfo(outbox, num); /* refcnt++ */
955 tmp_msginfo = procmsg_msginfo_get_full_info(msginfo); /* refcnt++ */
956 if (msginfo != NULL) {
957 procmsg_msginfo_unset_flags(msginfo, ~0, 0);
958 procmsg_msginfo_free(msginfo); /* refcnt-- */
959 /* tmp_msginfo == msginfo */
960 if (tmp_msginfo && (msginfo->dispositionnotificationto ||
961 msginfo->returnreceiptto)) {
962 procmsg_msginfo_set_flags(msginfo, MSG_RETRCPT_SENT, 0);
963 procmsg_msginfo_free(msginfo); /* refcnt-- */
970 void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline)
972 static const gchar *def_cmd = "lpr %s";
979 g_return_if_fail(msginfo);
981 if (procmime_msginfo_is_encrypted(msginfo))
982 tmpfp = procmime_get_first_encrypted_text_content(msginfo);
984 tmpfp = procmime_get_first_text_content(msginfo);
986 g_warning("Can't get text part\n");
990 prtmp = g_strdup_printf("%s%cprinttmp.%08x",
991 get_mime_tmp_dir(), G_DIR_SEPARATOR, id++);
993 if ((prfp = fopen(prtmp, "wb")) == NULL) {
994 FILE_OP_ERROR(prtmp, "fopen");
1000 if (msginfo->date) fprintf(prfp, "Date: %s\n", msginfo->date);
1001 if (msginfo->from) fprintf(prfp, "From: %s\n", msginfo->from);
1002 if (msginfo->to) fprintf(prfp, "To: %s\n", msginfo->to);
1003 if (msginfo->cc) fprintf(prfp, "Cc: %s\n", msginfo->cc);
1004 if (msginfo->newsgroups)
1005 fprintf(prfp, "Newsgroups: %s\n", msginfo->newsgroups);
1006 if (msginfo->subject) fprintf(prfp, "Subject: %s\n", msginfo->subject);
1009 while (fgets(buf, sizeof(buf), tmpfp) != NULL)
1015 if (cmdline && (p = strchr(cmdline, '%')) && *(p + 1) == 's' &&
1016 !strchr(p + 2, '%'))
1017 g_snprintf(buf, sizeof(buf) - 1, cmdline, prtmp);
1020 g_warning("Print command line is invalid: '%s'\n",
1022 g_snprintf(buf, sizeof(buf) - 1, def_cmd, prtmp);
1028 if (buf[strlen(buf) - 1] != '&') strcat(buf, "&");
1032 MsgInfo *procmsg_msginfo_new_ref(MsgInfo *msginfo)
1039 MsgInfo *procmsg_msginfo_new(void)
1041 MsgInfo *newmsginfo;
1043 newmsginfo = g_new0(MsgInfo, 1);
1044 newmsginfo->refcnt = 1;
1049 MsgInfo *procmsg_msginfo_copy(MsgInfo *msginfo)
1051 MsgInfo *newmsginfo;
1054 if (msginfo == NULL) return NULL;
1056 newmsginfo = g_new0(MsgInfo, 1);
1058 newmsginfo->refcnt = 1;
1060 #define MEMBCOPY(mmb) newmsginfo->mmb = msginfo->mmb
1061 #define MEMBDUP(mmb) newmsginfo->mmb = msginfo->mmb ? \
1062 g_strdup(msginfo->mmb) : NULL
1077 MEMBDUP(newsgroups);
1084 MEMBCOPY(to_folder);
1087 MEMBDUP(dispositionnotificationto);
1088 MEMBDUP(returnreceiptto);
1090 refs = msginfo->references;
1091 for (refs = msginfo->references; refs != NULL; refs = refs->next) {
1092 newmsginfo->references = g_slist_prepend
1093 (newmsginfo->references, g_strdup(refs->data));
1095 newmsginfo->references = g_slist_reverse(newmsginfo->references);
1098 MEMBCOPY(threadscore);
1099 MEMBDUP(plaintext_file);
1104 MsgInfo *procmsg_msginfo_get_full_info(MsgInfo *msginfo)
1106 MsgInfo *full_msginfo;
1109 if (msginfo == NULL) return NULL;
1111 file = procmsg_get_message_file_path(msginfo);
1112 if (!file || !is_file_exist(file)) {
1114 file = procmsg_get_message_file(msginfo);
1116 if (!file || !is_file_exist(file)) {
1117 g_warning("procmsg_msginfo_get_full_info(): can't get message file.\n");
1121 full_msginfo = procheader_parse_file(file, msginfo->flags, TRUE, FALSE);
1123 if (!full_msginfo) return NULL;
1125 /* CLAWS: make sure we add the missing members; see:
1126 * procheader.c::procheader_get_headernames() */
1127 if (!msginfo->xface)
1128 msginfo->xface = g_strdup(full_msginfo->xface);
1129 if (!msginfo->dispositionnotificationto)
1130 msginfo->dispositionnotificationto =
1131 g_strdup(full_msginfo->dispositionnotificationto);
1132 if (!msginfo->returnreceiptto)
1133 msginfo->returnreceiptto = g_strdup
1134 (full_msginfo->returnreceiptto);
1135 if (!msginfo->partial_recv && full_msginfo->partial_recv)
1136 msginfo->partial_recv = g_strdup
1137 (full_msginfo->partial_recv);
1138 msginfo->total_size = full_msginfo->total_size;
1139 if (!msginfo->account_server && full_msginfo->account_server)
1140 msginfo->account_server = g_strdup
1141 (full_msginfo->account_server);
1142 if (!msginfo->account_login && full_msginfo->account_login)
1143 msginfo->account_login = g_strdup
1144 (full_msginfo->account_login);
1145 msginfo->planned_download = full_msginfo->planned_download;
1146 procmsg_msginfo_free(full_msginfo);
1148 return procmsg_msginfo_new_ref(msginfo);
1151 void procmsg_msginfo_free(MsgInfo *msginfo)
1153 if (msginfo == NULL) return;
1156 if (msginfo->refcnt > 0)
1159 if (msginfo->to_folder) {
1160 msginfo->to_folder->op_count--;
1161 folder_item_update(msginfo->to_folder, F_ITEM_UPDATE_MSGCNT);
1164 g_free(msginfo->fromspace);
1165 g_free(msginfo->returnreceiptto);
1166 g_free(msginfo->dispositionnotificationto);
1167 g_free(msginfo->xface);
1169 g_free(msginfo->fromname);
1171 g_free(msginfo->date);
1172 g_free(msginfo->from);
1173 g_free(msginfo->to);
1174 g_free(msginfo->cc);
1175 g_free(msginfo->newsgroups);
1176 g_free(msginfo->subject);
1177 g_free(msginfo->msgid);
1178 g_free(msginfo->inreplyto);
1179 g_free(msginfo->xref);
1181 g_free(msginfo->partial_recv);
1182 g_free(msginfo->account_server);
1183 g_free(msginfo->account_login);
1185 slist_free_strings(msginfo->references);
1186 g_slist_free(msginfo->references);
1188 g_free(msginfo->plaintext_file);
1193 guint procmsg_msginfo_memusage(MsgInfo *msginfo)
1198 memusage += sizeof(MsgInfo);
1199 if (msginfo->fromname)
1200 memusage += strlen(msginfo->fromname);
1202 memusage += strlen(msginfo->date);
1204 memusage += strlen(msginfo->from);
1206 memusage += strlen(msginfo->to);
1208 memusage += strlen(msginfo->cc);
1209 if (msginfo->newsgroups)
1210 memusage += strlen(msginfo->newsgroups);
1211 if (msginfo->subject)
1212 memusage += strlen(msginfo->subject);
1214 memusage += strlen(msginfo->msgid);
1215 if (msginfo->inreplyto)
1216 memusage += strlen(msginfo->inreplyto);
1218 memusage += strlen(msginfo->xface);
1219 if (msginfo->dispositionnotificationto)
1220 memusage += strlen(msginfo->dispositionnotificationto);
1221 if (msginfo->returnreceiptto)
1222 memusage += strlen(msginfo->returnreceiptto);
1223 for (refs = msginfo->references; refs; refs=refs->next) {
1224 gchar *r = (gchar *)refs->data;
1225 memusage += r?strlen(r):0;
1227 if (msginfo->fromspace)
1228 memusage += strlen(msginfo->fromspace);
1233 gint procmsg_cmp_msgnum_for_sort(gconstpointer a, gconstpointer b)
1235 const MsgInfo *msginfo1 = a;
1236 const MsgInfo *msginfo2 = b;
1243 return msginfo1->msgnum - msginfo2->msgnum;
1246 static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_session)
1248 static HeaderEntry qentry[] = {{"S:", NULL, FALSE},
1249 {"SSV:", NULL, FALSE},
1250 {"R:", NULL, FALSE},
1251 {"NG:", NULL, FALSE},
1252 {"MAID:", NULL, FALSE},
1253 {"NAID:", NULL, FALSE},
1254 {"SCF:", NULL, FALSE},
1255 {"RMID:", NULL, FALSE},
1256 {"FMID:", NULL, FALSE},
1257 {"X-Sylpheed-Privacy-System:", NULL, FALSE},
1258 {"X-Sylpheed-Encrypt:", NULL, FALSE},
1259 {"X-Sylpheed-Encrypt-Data:", NULL, FALSE},
1260 {NULL, NULL, FALSE}};
1263 gint mailval = 0, newsval = 0;
1265 gchar *smtpserver = NULL;
1266 GSList *to_list = NULL;
1267 GSList *newsgroup_list = NULL;
1268 gchar *savecopyfolder = NULL;
1269 gchar *replymessageid = NULL;
1270 gchar *fwdmessageid = NULL;
1271 gchar *privacy_system = NULL;
1272 gboolean encrypt = FALSE;
1273 gchar *encrypt_data = NULL;
1274 gchar buf[BUFFSIZE];
1276 PrefsAccount *mailac = NULL, *newsac = NULL;
1277 gboolean save_clear_text = TRUE;
1278 gchar *tmp_enc_file = NULL;
1282 g_return_val_if_fail(file != NULL, -1);
1284 if ((fp = fopen(file, "rb")) == NULL) {
1285 FILE_OP_ERROR(file, "fopen");
1289 while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, qentry))
1291 gchar *p = buf + strlen(qentry[hnum].name);
1299 if (smtpserver == NULL)
1300 smtpserver = g_strdup(p);
1303 to_list = address_list_append(to_list, p);
1306 newsgroup_list = newsgroup_list_append(newsgroup_list, p);
1308 case Q_MAIL_ACCOUNT_ID:
1309 mailac = account_find_from_id(atoi(p));
1311 case Q_NEWS_ACCOUNT_ID:
1312 newsac = account_find_from_id(atoi(p));
1314 case Q_SAVE_COPY_FOLDER:
1315 if (savecopyfolder == NULL)
1316 savecopyfolder = g_strdup(p);
1318 case Q_REPLY_MESSAGE_ID:
1319 if (replymessageid == NULL)
1320 replymessageid = g_strdup(p);
1322 case Q_FWD_MESSAGE_ID:
1323 if (fwdmessageid == NULL)
1324 fwdmessageid = g_strdup(p);
1326 case Q_PRIVACY_SYSTEM:
1327 if (privacy_system == NULL)
1328 privacy_system = g_strdup(p);
1334 case Q_ENCRYPT_DATA:
1335 if (encrypt_data == NULL)
1336 encrypt_data = g_strdup(p);
1340 filepos = ftell(fp);
1345 save_clear_text = (mailac != NULL && mailac->save_encrypted_as_clear_text);
1350 mimeinfo = procmime_scan_queue_file(file);
1351 if (!privacy_encrypt(privacy_system, mimeinfo, encrypt_data)
1352 || (fp = my_tmpfile()) == NULL
1353 || procmime_write_mimeinfo(mimeinfo, fp) < 0) {
1356 procmime_mimeinfo_free_all(mimeinfo);
1359 slist_free_strings(to_list);
1360 g_slist_free(to_list);
1361 slist_free_strings(newsgroup_list);
1362 g_slist_free(newsgroup_list);
1363 g_free(savecopyfolder);
1364 g_free(replymessageid);
1365 g_free(fwdmessageid);
1366 g_free(privacy_system);
1367 g_free(encrypt_data);
1372 if (!save_clear_text) {
1373 gchar *content = NULL;
1374 FILE *tmpfp = get_tmpfile_in_dir(get_mime_tmp_dir(), &tmp_enc_file);
1378 content = file_read_stream_to_str(fp);
1381 str_write_to_file(content, tmp_enc_file);
1384 g_warning("couldn't get tempfile\n");
1388 procmime_mimeinfo_free_all(mimeinfo);
1394 debug_print("Sending message by mail\n");
1396 g_warning("Queued message header is broken.\n");
1398 } else if (mailac && mailac->use_mail_command &&
1399 mailac->mail_command && (* mailac->mail_command)) {
1400 mailval = send_message_local(mailac->mail_command, fp);
1404 mailac = account_find_from_smtp_server(from, smtpserver);
1406 g_warning("Account not found. "
1407 "Using current account...\n");
1408 mailac = cur_account;
1413 mailval = send_message_smtp_full(mailac, to_list, fp, keep_session);
1415 PrefsAccount tmp_ac;
1417 g_warning("Account not found.\n");
1419 memset(&tmp_ac, 0, sizeof(PrefsAccount));
1420 tmp_ac.address = from;
1421 tmp_ac.smtp_server = smtpserver;
1422 tmp_ac.smtpport = SMTP_PORT;
1423 mailval = send_message_smtp(&tmp_ac, to_list, fp);
1428 fseek(fp, filepos, SEEK_SET);
1429 if (newsgroup_list && (mailval == 0)) {
1434 /* write to temporary file */
1435 tmp = g_strdup_printf("%s%ctmp%d", g_get_tmp_dir(),
1436 G_DIR_SEPARATOR, (gint)file);
1437 if ((tmpfp = fopen(tmp, "wb")) == NULL) {
1438 FILE_OP_ERROR(tmp, "fopen");
1440 alertpanel_error(_("Could not create temporary file for news sending."));
1442 if (change_file_mode_rw(tmpfp, tmp) < 0) {
1443 FILE_OP_ERROR(tmp, "chmod");
1444 g_warning("can't change file mode\n");
1447 while ((newsval == 0) && fgets(buf, sizeof(buf), fp) != NULL) {
1448 if (fputs(buf, tmpfp) == EOF) {
1449 FILE_OP_ERROR(tmp, "fputs");
1451 alertpanel_error(_("Error when writing temporary file for news sending."));
1457 debug_print("Sending message by news\n");
1459 folder = FOLDER(newsac->folder);
1461 newsval = news_post(folder, tmp);
1463 alertpanel_error(_("Error occurred while posting the message to %s ."),
1464 newsac->nntp_server);
1474 /* save message to outbox */
1475 if (mailval == 0 && newsval == 0 && savecopyfolder) {
1478 debug_print("saving sent message...\n");
1480 outbox = folder_find_item_from_identifier(savecopyfolder);
1482 outbox = folder_get_default_outbox();
1484 if (save_clear_text || tmp_enc_file == NULL) {
1485 procmsg_save_to_outbox(outbox, file, TRUE);
1487 procmsg_save_to_outbox(outbox, tmp_enc_file, FALSE);
1491 if (tmp_enc_file != NULL) {
1492 unlink(tmp_enc_file);
1494 tmp_enc_file = NULL;
1497 if (replymessageid != NULL || fwdmessageid != NULL) {
1501 if (replymessageid != NULL)
1502 tokens = g_strsplit(replymessageid, "\x7f", 0);
1504 tokens = g_strsplit(fwdmessageid, "\x7f", 0);
1505 item = folder_find_item_from_identifier(tokens[0]);
1507 /* check if queued message has valid folder and message id */
1508 if (item != NULL && tokens[2] != NULL) {
1511 msginfo = folder_item_get_msginfo(item, atoi(tokens[1]));
1513 /* check if referring message exists and has a message id */
1514 if ((msginfo != NULL) &&
1515 (msginfo->msgid != NULL) &&
1516 (strcmp(msginfo->msgid, tokens[2]) != 0)) {
1517 procmsg_msginfo_free(msginfo);
1521 if (msginfo == NULL) {
1522 msginfo = folder_item_get_msginfo_by_msgid(item, tokens[2]);
1525 if (msginfo != NULL) {
1526 if (replymessageid != NULL) {
1527 procmsg_msginfo_unset_flags(msginfo, MSG_FORWARDED, 0);
1528 procmsg_msginfo_set_flags(msginfo, MSG_REPLIED, 0);
1530 procmsg_msginfo_unset_flags(msginfo, MSG_REPLIED, 0);
1531 procmsg_msginfo_set_flags(msginfo, MSG_FORWARDED, 0);
1533 procmsg_msginfo_free(msginfo);
1541 slist_free_strings(to_list);
1542 g_slist_free(to_list);
1543 slist_free_strings(newsgroup_list);
1544 g_slist_free(newsgroup_list);
1545 g_free(savecopyfolder);
1546 g_free(replymessageid);
1547 g_free(fwdmessageid);
1548 g_free(privacy_system);
1549 g_free(encrypt_data);
1551 return (newsval != 0 ? newsval : mailval);
1554 gint procmsg_send_message_queue(const gchar *file)
1556 return procmsg_send_message_queue_full(file, FALSE);
1559 static void update_folder_msg_counts(FolderItem *item, MsgInfo *msginfo, MsgPermFlags old_flags)
1561 MsgPermFlags new_flags = msginfo->flags.perm_flags;
1564 if (!(old_flags & MSG_NEW) && (new_flags & MSG_NEW)) {
1568 if ((old_flags & MSG_NEW) && !(new_flags & MSG_NEW)) {
1573 if (!(old_flags & MSG_UNREAD) && (new_flags & MSG_UNREAD)) {
1574 item->unread_msgs++;
1575 if (procmsg_msg_has_marked_parent(msginfo))
1576 item->unreadmarked_msgs++;
1579 if ((old_flags & MSG_UNREAD) && !(new_flags & MSG_UNREAD)) {
1580 item->unread_msgs--;
1581 if (procmsg_msg_has_marked_parent(msginfo))
1582 item->unreadmarked_msgs--;
1586 if (!(old_flags & MSG_MARKED) && (new_flags & MSG_MARKED)) {
1587 procmsg_update_unread_children(msginfo, TRUE);
1588 item->marked_msgs++;
1591 if ((old_flags & MSG_MARKED) && !(new_flags & MSG_MARKED)) {
1592 procmsg_update_unread_children(msginfo, FALSE);
1593 item->marked_msgs--;
1597 void procmsg_msginfo_set_flags(MsgInfo *msginfo, MsgPermFlags perm_flags, MsgTmpFlags tmp_flags)
1600 MsgInfoUpdate msginfo_update;
1601 MsgPermFlags perm_flags_new, perm_flags_old;
1602 MsgTmpFlags tmp_flags_old;
1604 g_return_if_fail(msginfo != NULL);
1605 item = msginfo->folder;
1606 g_return_if_fail(item != NULL);
1608 debug_print("Setting flags for message %d in folder %s\n", msginfo->msgnum, item->path);
1610 /* Perm Flags handling */
1611 perm_flags_old = msginfo->flags.perm_flags;
1612 perm_flags_new = msginfo->flags.perm_flags | perm_flags;
1613 if ((perm_flags & MSG_IGNORE_THREAD) || (perm_flags_old & MSG_IGNORE_THREAD)) {
1614 perm_flags_new &= ~(MSG_NEW | MSG_UNREAD);
1617 if (perm_flags_old != perm_flags_new) {
1618 folder_item_change_msg_flags(msginfo->folder, msginfo, perm_flags_new);
1620 update_folder_msg_counts(item, msginfo, perm_flags_old);
1624 /* Tmp flags handling */
1625 tmp_flags_old = msginfo->flags.tmp_flags;
1626 msginfo->flags.tmp_flags |= tmp_flags;
1628 /* update notification */
1629 if ((perm_flags_old != perm_flags_new) || (tmp_flags_old != msginfo->flags.tmp_flags)) {
1630 msginfo_update.msginfo = msginfo;
1631 msginfo_update.flags = MSGINFO_UPDATE_FLAGS;
1632 hooks_invoke(MSGINFO_UPDATE_HOOKLIST, &msginfo_update);
1633 folder_item_update(msginfo->folder, F_ITEM_UPDATE_MSGCNT);
1637 void procmsg_msginfo_unset_flags(MsgInfo *msginfo, MsgPermFlags perm_flags, MsgTmpFlags tmp_flags)
1640 MsgInfoUpdate msginfo_update;
1641 MsgPermFlags perm_flags_new, perm_flags_old;
1642 MsgTmpFlags tmp_flags_old;
1644 g_return_if_fail(msginfo != NULL);
1645 item = msginfo->folder;
1646 g_return_if_fail(item != NULL);
1648 debug_print("Unsetting flags for message %d in folder %s\n", msginfo->msgnum, item->path);
1650 /* Perm Flags handling */
1651 perm_flags_old = msginfo->flags.perm_flags;
1652 perm_flags_new = msginfo->flags.perm_flags & ~perm_flags;
1654 if (perm_flags_old != perm_flags_new) {
1655 folder_item_change_msg_flags(msginfo->folder, msginfo, perm_flags_new);
1657 update_folder_msg_counts(item, msginfo, perm_flags_old);
1659 msginfo_update.msginfo = msginfo;
1660 msginfo_update.flags = MSGINFO_UPDATE_FLAGS;
1661 hooks_invoke(MSGINFO_UPDATE_HOOKLIST, &msginfo_update);
1662 folder_item_update(msginfo->folder, F_ITEM_UPDATE_MSGCNT);
1665 /* Tmp flags hanlding */
1666 tmp_flags_old = msginfo->flags.tmp_flags;
1667 msginfo->flags.tmp_flags &= ~tmp_flags;
1669 /* update notification */
1670 if ((perm_flags_old != perm_flags_new) || (tmp_flags_old != msginfo->flags.tmp_flags)) {
1671 msginfo_update.msginfo = msginfo;
1672 msginfo_update.flags = MSGINFO_UPDATE_FLAGS;
1673 hooks_invoke(MSGINFO_UPDATE_HOOKLIST, &msginfo_update);
1674 folder_item_update(msginfo->folder, F_ITEM_UPDATE_MSGCNT);
1679 *\brief check for flags (e.g. mark) in prior msgs of current thread
1681 *\param info Current message
1682 *\param perm_flags Flags to be checked
1683 *\param parentmsgs Hash of prior msgs to avoid loops
1685 *\return gboolean TRUE if perm_flags are found
1687 gboolean procmsg_msg_has_flagged_parent_real(MsgInfo *info,
1688 MsgPermFlags perm_flags, GHashTable *parentmsgs)
1692 g_return_val_if_fail(info != NULL, FALSE);
1694 if (info != NULL && info->folder != NULL && info->inreplyto != NULL) {
1695 tmp = folder_item_get_msginfo_by_msgid(info->folder,
1697 if (tmp && (tmp->flags.perm_flags & perm_flags)) {
1698 procmsg_msginfo_free(tmp);
1700 } else if (tmp != NULL) {
1703 if (g_hash_table_lookup(parentmsgs, info)) {
1704 debug_print("loop detected: %s%c%d\n",
1705 folder_item_get_path(info->folder),
1706 G_DIR_SEPARATOR, info->msgnum);
1709 g_hash_table_insert(parentmsgs, info, "1");
1710 result = procmsg_msg_has_flagged_parent_real(
1711 tmp, perm_flags, parentmsgs);
1713 procmsg_msginfo_free(tmp);
1723 *\brief Callback for cleaning up hash of parentmsgs
1725 gboolean parentmsgs_hash_remove(gpointer key,
1733 *\brief Set up list of parentmsgs
1734 * See procmsg_msg_has_flagged_parent_real()
1736 gboolean procmsg_msg_has_flagged_parent(MsgInfo *info, MsgPermFlags perm_flags)
1739 GHashTable *parentmsgs = g_hash_table_new(NULL, NULL);
1741 result = procmsg_msg_has_flagged_parent_real(info, perm_flags, parentmsgs);
1742 g_hash_table_foreach_remove(parentmsgs, parentmsgs_hash_remove, NULL);
1743 g_hash_table_destroy(parentmsgs);
1748 *\brief Check if msgs prior in thread are marked
1749 * See procmsg_msg_has_flagged_parent_real()
1751 gboolean procmsg_msg_has_marked_parent(MsgInfo *info)
1753 return procmsg_msg_has_flagged_parent(info, MSG_MARKED);
1757 GSList *procmsg_find_children_func(MsgInfo *info,
1758 GSList *children, GSList *all)
1762 g_return_val_if_fail(info!=NULL, children);
1763 if (info->msgid == NULL)
1766 for (cur = all; cur != NULL; cur = g_slist_next(cur)) {
1767 MsgInfo *tmp = (MsgInfo *)cur->data;
1768 if (tmp->inreplyto && !strcmp(tmp->inreplyto, info->msgid)) {
1769 /* Check if message is already in the list */
1770 if ((children == NULL) ||
1771 (g_slist_index(children, tmp) == -1)) {
1772 children = g_slist_prepend(children,
1773 procmsg_msginfo_new_ref(tmp));
1774 children = procmsg_find_children_func(tmp,
1783 GSList *procmsg_find_children (MsgInfo *info)
1788 g_return_val_if_fail(info!=NULL, NULL);
1789 all = folder_item_get_msg_list(info->folder);
1790 children = procmsg_find_children_func(info, NULL, all);
1791 if (children != NULL) {
1792 for (cur = all; cur != NULL; cur = g_slist_next(cur)) {
1793 /* this will not free the used pointers
1794 created with procmsg_msginfo_new_ref */
1795 procmsg_msginfo_free((MsgInfo *)cur->data);
1803 void procmsg_update_unread_children(MsgInfo *info, gboolean newly_marked)
1805 GSList *children = procmsg_find_children(info);
1807 for (cur = children; cur != NULL; cur = g_slist_next(cur)) {
1808 MsgInfo *tmp = (MsgInfo *)cur->data;
1809 if(MSG_IS_UNREAD(tmp->flags) && !MSG_IS_IGNORE_THREAD(tmp->flags)) {
1811 info->folder->unreadmarked_msgs++;
1813 info->folder->unreadmarked_msgs--;
1814 folder_item_update(info->folder, F_ITEM_UPDATE_MSGCNT);
1816 procmsg_msginfo_free(tmp);
1818 g_slist_free(children);
1822 * Set the destination folder for a copy or move operation
1824 * \param msginfo The message which's destination folder is changed
1825 * \param to_folder The destination folder for the operation
1827 void procmsg_msginfo_set_to_folder(MsgInfo *msginfo, FolderItem *to_folder)
1829 if(msginfo->to_folder != NULL) {
1830 msginfo->to_folder->op_count--;
1831 folder_item_update(msginfo->to_folder, F_ITEM_UPDATE_MSGCNT);
1833 msginfo->to_folder = to_folder;
1834 if(to_folder != NULL) {
1835 to_folder->op_count++;
1836 folder_item_update(msginfo->to_folder, F_ITEM_UPDATE_MSGCNT);
1841 * Apply filtering actions to the msginfo
1843 * \param msginfo The MsgInfo describing the message that should be filtered
1844 * \return TRUE if the message was moved and MsgInfo is now invalid,
1847 gboolean procmsg_msginfo_filter(MsgInfo *msginfo)
1849 MailFilteringData mail_filtering_data;
1851 mail_filtering_data.msginfo = msginfo;
1852 if (hooks_invoke(MAIL_FILTERING_HOOKLIST, &mail_filtering_data))
1855 /* filter if enabled in prefs or move to inbox if not */
1856 if((filtering_rules != NULL) &&
1857 filter_message_by_msginfo(filtering_rules, msginfo))
1860 hooks_invoke(MAIL_POSTFILTERING_HOOKLIST, msginfo);
1865 MsgInfo *procmsg_msginfo_new_from_mimeinfo(MsgInfo *src_msginfo, MimeInfo *mimeinfo)
1867 MsgInfo *tmp_msginfo = NULL;
1868 MsgFlags flags = {0, 0};
1871 if (!mimeinfo || mimeinfo->type != MIMETYPE_MESSAGE ||
1872 g_ascii_strcasecmp(mimeinfo->subtype, "rfc822")) {
1873 g_warning("procmsg_msginfo_new_from_mimeinfo(): unsuitable mimeinfo");
1877 if (mimeinfo->content == MIMECONTENT_MEM) {
1878 gchar *tmpfile = get_tmp_file();
1879 str_write_to_file(mimeinfo->data.mem, tmpfile);
1880 g_free(mimeinfo->data.mem);
1881 mimeinfo->content = MIMECONTENT_FILE;
1882 mimeinfo->data.filename = g_strdup(tmpfile);
1886 tmp_msginfo = procheader_parse_file(mimeinfo->data.filename,
1887 flags, TRUE, FALSE);
1889 if (tmp_msginfo != NULL) {
1890 tmp_msginfo->folder = src_msginfo->folder;
1891 tmp_msginfo->plaintext_file = g_strdup(mimeinfo->data.filename);
1893 g_warning("procmsg_msginfo_new_from_mimeinfo(): Can't generate new msginfo");